在實際項目開發中,須要基於多種環境去設置不一樣的環境變量以便於在構建階段或是運行階段去使用,例如常見的經過process.env.NODE_ENV
在構建時去判斷當前的構建環境是development
仍是production
,例如須要在開發環境
、測試環境
和生產環境
去訪問不一樣的接口服務器。html
爲了模擬真實的項目,使用webpack搭建了一個最小化的項目結構:前端
├─package.json ├─src | └index.jsx ├─public | └index.html ├─config | └webpack.config.js
Node環境變量就是指process.env
這個屬性node
它是 Nodejs 應用程序中,process.env
屬性,返回包含用戶環境的對象,因此它不能夠在客戶端側代碼中使用,也就不能在瀏覽器環境上使用。webpack
// process.env(官方示例) { TERM: 'xterm-256color', SHELL: '/usr/local/bin/bash', USER: 'nodejscn', PATH: '~/.bin/:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin', PWD: '/Users/nodejscn', EDITOR: 'vim', SHLVL: '1', HOME: '/Users/nodejscn', LOGNAME: 'nodejscn', _: '/usr/local/bin/node' }
使用 cross-env
依賴包,支持跨平臺配置環境變量。git
// package.json { ..., "scripts": { "start": "npm run dev", "dev": "cross-env NODE_ENV=development AAA=123 webpack serve --config ./config/webpack.config.js", "build:test": "cross-env NODE_ENV=test webpack --config ./config/webpack.config.js", "build:pro": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js" }, ... }
經過在package.json
腳本中設置變量的方式來注入環境變量,同時cross-env
還支持去設置多個環境變量,只須要經過空格區分,例如在dev
腳本中設置的NODE_ENV=development
和AAA=123
。github
這樣在執行npm start
就可以經過process.env
獲取到對應的環境變量。web
// webpack.config.js console.log("【process.env】", process.env.AAA);
可以在構建時的終端中打印出npm
可是在index.jsx
中也就是瀏覽器環境下的文件中打印process.env
就會報錯json
緣由就是前文提到的peocess.env
是Node環境的屬性,瀏覽器環境不可以獲取到。讓瀏覽器環境獲取到所需變量咱們後文再說。vim
直接經過在script腳本中注入環境變量的方式不利於集中管理環境變量,並且在環境變量較多時這種方式也十分不友好,因此須要一種方式來集中管理這些環境變量。
使用dotenv
依賴包可將環境變量從 .env
文件加載到 process.env
。
dotenv
會默認加載根目錄的.env
文件去注入環境變量,經過require('dotenv').config()
便可完成注入。
//webpack.config.js dotenv.config(); //.env文件 AAA=123
一樣也可以在終端中看到
在多環境配置時須要經過規定不一樣環境對應的.env
文件,例如如今規定.env.test
是測試環境對應的環境變量,.env.production
是生產環境,.env
是開發環境。而後經過dotenv.config({ path: })
去加載對應文件的環境變量。
//webpack.config.js const PROJECT_PATH = resolve(__dirname, "../"); const dotenvFile = resolve(PROJECT_PATH, `./.env.${process.env.NODE_ENV}`); // 加載.env*文件 默認加載.env文件 dotenv.config({ path: fs.existsSync(dotenvFile) ? dotenvFile : resolve(PROJECT_PATH, `./.env`), }); console.log("【process.env】", process.env.ENV);
這裏process.env.NODE_ENV
是爲了判斷當前的運行環境來去加載對應的.env
文件。
// package.json "scripts": { "start": "npm run dev", "dev": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js", "build:test": "cross-env NODE_ENV=test webpack --config ./config/webpack.config.js", "build:pro": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js" } //.env.production ENV=pro //.env ENV=dev
執行npm start
執行npm run build:pro
能夠看到不一樣環境的變量確實已經注入成功。
瀏覽器環境下也須要根據不一樣的環境變量來處理一些邏輯,可是它不能獲取到process.env
因此不能像注入Node環境變量的方式來實現。瀏覽器環境變量是基於webpack.DefinePlugin
這個插件在項目構建時引入的,引入以後能夠在前端代碼中全局獲取到對應的變量。
基礎使用方式是將所需的變量按鍵值對的方式傳入DefinePlugin
中,須要注意的是變量值須要經過JSON.stringify
進行包裹。
module.exports = { plugins: [ new DefinePlugin({ aaa: JSON.stringify("!!!!") }) ] }
執行腳本後能夠在index.jsx
中獲得對應的結果
//index.jsx console.log("【app】", aaa); const App = () => { return <div>app</div>; };
瀏覽器環境中也須要根據項目環境來引入不一樣的變量,以前在Node
環境中已經獲取到不一樣的環境變量,咱們能夠創建一個基於此的映射表在項目構建時根據拿到的Node
環境變量來引入對應的瀏覽器環境變量。
// webpack.config.js // 瀏覽器環境注入的變量 const define = { dev: { baseURL: "/api/dev", }, test: { baseURL: "/api/test", }, pro: { baseURL: "/api/pro", }, }; module.exports = { new DefinePlugin({ "process.env": Object.keys(define[process.env.ENV]).reduce((env, key) => { env[key] = JSON.stringify(define[process.env.ENV][key]); return env; }, {}), }), }
執行npm start
,能夠在瀏覽器控制檯看到結果
執行npm run build:pro
,在dist目錄開啓一個服務器,能夠在瀏覽器控制檯看到結果
在實際項目中根據不一樣環境切換接口服務器地址的場景中,就能經過這樣的方式來獲取到不一樣環境中的接口地址。
在平時開發中較常使用umi
做爲項目框架,umi
經過環境變量UMI_ENV
區分不一樣環境來指定不一樣配置。
具體來講是經過腳本中注入的UMI_ENV=xxx
去匹配對應的config.xxx.js
配置文件,而後在define
屬性中去配置須要引入瀏覽器環境的變量。
// webpack.config.js module.exports = { ..., "scripts": { "start": "cross-env UMI_ENV=dev umi dev", "build:test": "cross-env UMI_ENV=test umi build", "build:pre": "cross-env UMI_ENV=pre umi build", "build:pro": "cross-env UMI_ENV=pro umi build", } ..., } //config.dev.js import { defineConfig } from 'umi'; export default defineConfig({ define: { 'process.env': { BASE_API: '/api/dev', }, }, });