使用 .env 靈活切換真 API 與 假 API

實務上一定會遇到在不同 server ( developmentlabstagingproduction) ,且各有各的 環境變數,該如何設定這些環境變數並且自動切換呢 ?

Version


Vue 2.5.17
Vue CLI 3.0.3

Modes


Vue CLI 內建 3 種 mode:

  • development:執行 yarn serveyarn lint 時使用此模式
  • productionyarn buildyarn test:e2e 使用此模式
  • testyarn test:unit 使用此模式

我們也可以自行新增 mode,如 labstaging

.env


  • .env:所有 mode 都會載入
  • env.local:所有 mode 都會載入,但不會進 Git,適合每個人本機自行設定
  • env.[mode]:特定 mode 會載入
  • env.[mode].local:特定 mode 會載入,但不會進 Git,適合每個人本機自行設定

若 key 同時存在 .env.env.[mode]env.[mode].local 時,則其載入順序為:

.env => env.[mode] => env.[mode].local

也就是其優先權為:

env.[mode].local > env.[mode] > .env

.env.development.local

1
2
NODE_ENV=development
VUE_APP_API="https://jsonplaceholder.typicode.com"
  • NODE_ENV:指定使用 Vue CLI 內建的 3 個 mode 之一
  • VUE_APP_API:所有變數以 VUE_APP_ 為開頭
1
console.log(process.env.VUE_APP_API);

任何在 .env 所設定的變數,可以使用 process.env.VUE_APP_xxx 讀取。

實務案例


  1. 前後端分離後,當 API spec 定義好,前後端就可以同時進行開發,此時後端的 API 還沒開發好,前端可根據 API spec 的 example 製造 假 API 先行開發
  2. 執行 e2e testing 時,由於實際打 真 API 的測試速度較慢,因此會希望只打 local 的 假 API,加快測試速度
  3. 希望開發時期的 假 API 能留下來進 Git,將來就能透過 CLI 切換使用 真 API假 API,不用修改 code
  • 使用 Node.js 建立假 API
  • 使用 .env 切換 API

使用 Node.js 建立假 API


安裝 Express 與 Cors

1
$ yarn add express

安裝 express framework。

1
$ yarn add cors

安裝 express 的解 CORS 套件。

envmode000

  • package.jsondependencies 會看到 corsexpress 兩個 package 被安裝

建立 node 目錄與檔案

envmode001

  1. 在專案根目錄建立 node 目錄與 index.js

node/index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express');
const cors = require('cors');

const todos = require('./todos');

const app = express().use(cors());
const hostname = '127.0.0.1';
const port = 3000;

app.get('/todos', todos);

app.listen(port, () => {
console.log(`Serving running at http://${hostname}:${port}/`);
});

第 1 行

1
const express = require('express');

Import express module。

第 2 行

1
const cors = require('cors');

Import cors module。

第 3 行

1
const todos = require('./todos');

Import 自己寫的 todos module,為假 API。

第 6 行

1
const app = express().use(cors());

使用 express() 建立 app,並且 use cors() 所建立的物件。

第 7 行

1
2
const hostname = '127.0.0.1';
const port = 3000;

定義 hostname 位置與 port。

第 10 行

1
app.get('/todos', todos);

/todos 設定為 GET,其資料由 todos() function 所提供。

12 行

1
2
3
app.listen(port, () => {
console.log(`Serving running at http://${hostname}:${port}/`);
});

使用 app.listen() 啟動 Node.js 服務。

node/todos.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
const todos = (req, res) =>
res.send([
{
userId: 1,
id: 1,
title: 'delectus aut autem',
completed: false,
},
{
userId: 1,
id: 2,
title: 'quis ut nam facilis et officia qui',
completed: false,
},
{
userId: 1,
id: 3,
title: 'fugiat veniam minus',
completed: false,
},
{
userId: 1,
id: 4,
title: 'et porro tempora',
completed: true,
},
{
userId: 1,
id: 5,
title: 'laboriosam mollitia et enim quasi adipisci quia provident illum',
completed: false,
},
{
userId: 1,
id: 6,
title: 'qui ullam ratione quibusdam voluptatem quia omnis',
completed: false,
},
]);

module.exports = todos;

第 1 行

1
const todos = (req, res) =>

定義 todos() ,其 argument 為 reqres

第 2 行

1
res.send();

API 要傳回的 JSON 資料。

41 行

1
module.exports = todos;

使用 CommonJS 方式 export 出 todos()

使用 .env 切換 API


建立 .env

.env

1
NODE_ENV=production
  • 整個專案的 .env,會進 Git

  • NODE_ENV 預設為 Vue CLI 的 production mode

.env.development

1
2
NODE_ENV=development
VUE_APP_API="https://jsonplaceholder.typicode.com"
  • 設定 development mode 的 .env,會進 Git

  • NODE_ENV 設定為 Vue CLI 的 development mode

  • VUE_APP_API 變數為 真 API 位址

.env.development.local

1
2
NODE_ENV=development
VUE_APP_API="http://localhost:3000"
  • 設定 development mode 的 env不會 進 Git

  • NODE_ENV 設定為 Vue CLI 的 development mode

  • VUE_APP_API 變數為 假 API 位址

因為 .env.development.local 不會進 Git,自己開發用的環境變數可以設定在此

.env.lab

1
2
NODE_ENV=development
VUE_APP_API="https://jsonplaceholder.typicode.com"
  • 設定 lab mode,此為自訂的新 mode,會進 Git
  • NODE_ENV 設定為 Vue CLI 的 production mode
  • VUE_APP_API 變數為 真 API 位址

讀取 .env

api/todo.api.js

1
2
3
4
5
import axios from 'axios';

const API = process.env.VUE_APP_API;

export const fetchTodos = () => axios.get(`${API}/todos`);

第 3 行

1
const API = process.env.VUE_APP_API;

使用 process.env.VUE_APP_API 讀取 .envVUE_APP_API 變數。

使用假 API

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
{
"name": "vue-todo-lis-api",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"api": "node ./node/index.js"
}
,

"dependencies": {
"axios": "^0.18.0",
"cors": "^2.8.4",
"express": "^4.16.4",
"vue": "^2.5.17"
}
,

"devDependencies": {
"@vue/cli-plugin-babel": "^3.0.3",
"@vue/cli-plugin-eslint": "^3.0.3",
"@vue/cli-service": "^3.0.3",
"@vue/eslint-config-airbnb": "^3.0.5",
"vue-template-compiler": "^2.5.17"
}

}

第 9 行

1
"api": "node ./node/index.js"

輸入 yarn api 將執行 Node.js 的 假 API

1
$ yarn api

envmode002

  1. 執行 假 API
1
$ yarn serve

envmode003

  1. yarn serve 會使用 development mode,因為有提供 .env.development.local,所以 VUE_APP_API 應為 http://localhost:3000,也就是 假 API

使用真 API

1
$ yarn serve --mode lab

envmode004

  1. yarn serve 使用 lab mode,也就是 真 API

.env.local.sample


.env.development.local.sample

1
2
NODE_ENV=development
VUE_APP_API="http://localhost:3000"

由於 env.local.sample 沒有進 Git,其他人直接 git clone 下整個專案時,會因為不會設定 .env.development.local,導致無法執行 假 API 模式,可另外提供 .env.development.local.sample,此檔會進 Git,在自行由 .env.development.local.sample 命名為 .env.development.local 即可。

Conclusion


  • 透過 Node.js,就可解決 JSON Server 無法建立 POST 回傳資料的問題,因為 JSON Server 是純 RESTful
  • 靈活的運用 .env.development.localyarn serve --mode,就可靈活的切換 假 API真 API
  • 可將 .env.development.local.sample 也存進 Git,如此其他人 git clone 下來,可根據此檔建立 .env.development.local

Sample Code


完整的範例可以在我的 GitHub 上找到

Reference


Vue CLI, Environment Variables and Modes

2018-10-22