Vue CLI中模式與環境變量的深入詳解

前言

在實際項目的開發中,我們一般會經歷項目的開發階段、測試階段和最終上線階段,每一個階段對於項目代碼的要求可能都不盡相同,那麼我們如何能夠遊刃有餘的在不同階段下使我們的項目呈現不同的效果,使用不同的功能呢?
這裡就需要引入環境的概念。官方文檔中模式和環境變量說明

一般一個項目都會有以下 3 種環境:

  • 開發環境(開發階段,本地開發版本,一般會使用一些調試工具或額外的輔助功能);
  • 測試環境(測試階段,上線前版本,除瞭一些 bug 的修復,基本不會和上線版本有很大差別);
  • 生產環境(上線階段,正式對外發佈的版本,一般會進行優化,關掉錯誤報告);

作為一名開發人員,我們可能需要針對每一種環境編寫一些不同的代碼並且保證這些代碼運行在正確的環境中,那麼我們應該如何在代碼中判斷項目所處的環境同時執行不同的代碼呢?這就需要我們進行正確的環境配置和管理。

1. 配置文件

正確的配置環境首先需要我們認識不同環境配置之間的關系,如圖所示:

我們從上圖中可以瞭解到每一個環境其實有其不同的配置,同時它們也存在著交集部分,交集便是它們都共有的配置項,那麼在 Vue 中我們應該如何處理呢?

我們可以在根目錄下創建以下形式的文件進行不同環境下變量的配置:

.env                # 在所有的環境中被載入
.env.local          # 在所有的環境中被載入,但會被 git 忽略
.env.[mode]         # 隻在指定的模式中被載入, 如:.env.development,.env.production 
.env.[mode].local   # 隻在指定的模式中被載入,但會被 git 忽略

如:創建一個名為 .env.development 的文件,該文件表明其隻在 development 環境下被加載。

在這個文件中,我們可以配置如下鍵值對的變量:

# 開發環境配置
NODE_ENV=development
VUE_APP_API_BASE_URL=https://www.baidu.com/

這時怎麼在 vue.config.js 中訪問這些變量呢?使用 process.env.[name] 進行訪問就可以瞭。

// vue.config.js
console.log(process.env.NODE_ENV); // development(在終端輸出)

當運行 npm run serve 命令後會發現輸出的是 development,因為 vue-cli-service serve 命令 默認設置的環境就是 development。

如果我們需要修改,可將 package.json 中的 serve 腳本的命令為:

// package.json
"scripts": {
  "serve": "vue-cli-service serve --mode stage",
},

–mode stage 其實就是修改瞭 webpack 4 中的 mode 配置項為 stage,同時其會讀取對應 .env.[model] 文件下的配置。
如果沒找到對應配置文件,其會使用默認環境 development,同樣 vue-cli-service build 會使用默認環境 production。

如果再創建一個 .env 的文件,再次配置重復的變量,但是值不同。

# 環境配置
NODE_ENV=ENV
VUE_APP_API_BASE_URL=http://www.soso.com/

因為 .env 文件會被所有環境加載,即公共配置,那麼最終運行 vue-cli-service serve 打印出來的是哪個呢?

答案是 development。

但是如果是 .env.development.local 文件中配置成上方這樣,答案便是 ENV。

所以 .env.[mode].local 會覆蓋 .env.[mode] 下的相同配置。

同理 .env.local 會覆蓋 .env 下的相同配置。

由此可以得出結論,相同配置項的權重:.env.[mode].local > .env.[mode] > .env.local > .env
註意: 除瞭相同配置項權重大的覆蓋小的,不同配置項它們會進行合並操作,類似於 Javascript 中的 Object.assign 的用法。

2. 環境註入

通過上述配置文件的創建,我們成功地使用命令行的形式對項目環境進行瞭設置並可以自由切換,但是註意:在 Vue 的前端代碼中打印出的 process.env 與 vue.config.js 中輸出的可能是不一樣的,這需要普及一個知識點:webpack 通過 DefinePlugin 內置插件將 process.env 註入到客戶端代碼中。

// webpack 配置
{
    ...
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify(process.env.NODE_ENV)
            }
        }),
    ], 
    ...
}

由於 vue-cli 3.x 封裝的 webpack 配置中已經幫我們完成瞭這個功能,所以可以直接在客戶端代碼中打印出 process.env 的值,該對象可以包含多個鍵值對,也就是說可以註入多個值,但是 經過 vue-cli 封裝後僅支持註入環境配置文件中以 VUE_APP_ 開頭的變量,而 NODE_ENV 和 BASE_URL 這兩個特殊變量除外。

比如:在權重最高的 .env.development.local 文件中寫入:

# 開發環境配置
NODE_ENV=developmentLocal
VUE_APP_API_BASE_URL=https://www.baidu.com/
NAME=javaScript

然後我們嘗試在 vue.config.js 中打印 process.env,終端輸出:

{
    ...
    npm_config_ignore_scripts: '',
    npm_config_version_git_sign: '',
    npm_config_ignore_optional: '',
    npm_config_init_version: '1.0.0',
    npm_package_dependencies_vue_router: '^3.0.1',
    npm_config_version_tag_prefix: 'v',
    npm_node_execpath: '/usr/local/bin/node',
    NODE_ENV: 'developmentLocal',
    VUE_APP_API_BASE_URL: 'https://www.baidu.com/',
    NAME: 'javaScript',
    BABEL_ENV: 'development',
    ...
}

可以看到輸出內容除瞭環境配置中的變量外還包含瞭很多 npm 的信息,但在入口文件 main.js 中打印會發現輸出:

{
  BASE_URL: "/",
  NODE_ENV: "developmentLocal",
  VUE_APP_API_BASE_URL: "https://www.baidu.com/",
}

可見註入時過濾調瞭非 VUE_APP_ 開頭的變量,其中多出的 BASE_URL 為你在 vue.config.js 設置的值,默認為 /,其在環境配置文件中設置無效。

3. 額外配置

以上我們通過新建配置文件的方式為項目不同環境配置不同的變量值,能夠實現項目基本的環境管理,但是 .env 這樣的配置文件中的參數目前隻支持靜態值,無法使用動態參數,在某些情況下無法實現特定需求。

這時候可以在根目錄下新建 config 文件夾用於存放一些額外的配置文件。

/* 配置文件 index.js */
 
// 公共變量
const com = {
  IP: JSON.stringify('xxx')
};

module.exports = {
  // 開發環境變量
  dev: {
    env: {
      TYPE: JSON.stringify('dev'),
      ...com
    }
  },
  // 生產環境變量
  build: {
    env: {
      TYPE: JSON.stringify('prod'),
      ...com
    }
  }
}

以上代碼把環境變量分為瞭公共變量、開發環境變量和生產環境變量,當然這些變量可能是動態的,比如用戶的 ip 等。
現在我們要在 vue.config.js 裡註入這些變量,可以使用 chainWebpack 修改 DefinePlugin 中的值:

/* vue.config.js */
const configs = require('./config');
 
// 用於做相應的 merge 處理
const merge = require('webpack-merge');
 
// 根據環境判斷使用哪份配置
const cfg = process.env.NODE_ENV === 'production' ? configs.build.env : configs.dev.env;
module.exports = {
  chainWebpack: config => {
    config.plugin('define').tap(args => {
      let name = 'process.env';
      // 使用 merge 保證原始值不變
      args[0][name] = merge(args[0][name], cfg);
      return args
    })
  },	
}

最後可以在客戶端成功打印出包含動態配置的對象:

{
  BASE_URL: "/",
  IP: "xxx",
  NODE_ENV: "developmentLocal",
  TYPE: "dev",
  VUE_APP_API_BASE_URL: "https://www.baidu.com/",
}

4. 實際場景

使用 process.env.xxx 來訪問屬性

<script>
export default {
  data() { 
    return {
      BASEURL:process.env,
    } 
  },  
  mounted(){
 	console.log(this.BASEURL.VUE_APP_API_BASE_URL) // https://www.baidu.com/
  }
}
</script> 
// 創建 axios 實例
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  timeout: 5000
})

結語

環境的配置和管理對於項目的構建起到瞭至關重要的作用,通過給項目配置不同的環境不僅可以增加開發的靈活性、提高程序的拓展性,同時也有助於幫助我們去瞭解並分析項目在不同環境下的運行機制,建立全局觀念。

到此這篇關於Vue CLI中模式與環境變量的文章就介紹到這瞭,更多相關Vue CLI模式與環境變量內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: