.env
文件在由 creact-react-app 生成的項目里是一個關(guān)于當(dāng)環(huán)境的配置文件(先不去管這個文件的起源),我們可以在這個文件里寫一些配置纪隙,然后通過某種手段在代碼里讀取中鼠、應(yīng)用這些配置窗怒,比如我們會有開發(fā)姨丈、staging岸蜗、生產(chǎn)等環(huán)境九昧,每個環(huán)境的配置都不盡相同绊袋,最基本地,每個環(huán)境請求的后端服務(wù)器的 url 就不相同铸鹰,自己 mock 的時候的本機地址癌别、與后端聯(lián)調(diào)時候的局域網(wǎng)的地址,staging 的域名和正式上線環(huán)境的域名蹋笼,之前的做法是一般會在 api 請求相關(guān)的目錄下有 config.js
這樣一個文件展姐,那些配置就當(dāng)成一個常量寫到這個文件里躁垛,然后導(dǎo)出供其他需要的模塊引用,那么問題就來了圾笨,每次切換環(huán)境時都需要去更改這些配置變量為對應(yīng)環(huán)境的值教馆,這是一件很繁瑣的事情,一般我是
const HOST = 'xxx.xxx.xxx'
// const HOST = 'yyy.yyy.yyy'
在用哪個環(huán)境的時候就把另一個環(huán)境的賦值語句給注釋掉擂达,然后后面如果在需要 build 的時候把多余的注釋掉的刪掉土铺,當(dāng)然,刪除注釋的工作可以由工具來做谍婉,但是開發(fā)時一堆無關(guān)代碼的注釋躺在那里看起來很惡心舒憾,然后我就想能不能不管怎么切換環(huán)境,需要放到瀏覽器上去跑的那段代碼永遠不用變穗熬,而只通過啟動時輸入不同的命令就可以應(yīng)用對應(yīng)的配置镀迂,比如 npm run start:mock
表示使用本地的 mock 環(huán)境,同時開啟本地的 mock 服務(wù)唤蔗;npm run start
表示使用默認的開發(fā)環(huán)境探遵,使用后端提供的環(huán)境,然后 npm run build
表示正式上線環(huán)境的編譯妓柜;npm run build:staging
表示 staging 環(huán)境的編譯箱季。然后我就找到了 .env 文件。
要實現(xiàn)上面說的那些棍掐,我們需要用到 dotenv
和 dotenv-webpack
這兩個 npm 包(前提是在通過 create-react-app 創(chuàng)建的項目里藏雏,同時還要 run eject
,當(dāng)然其他腳手架生成的項目肯定也可以做到這樣作煌,因為憑自己目前的功力還沒有辦法自己搗鼓出一個完成的項目骨架掘殴,所以就先把 create-react-app 研究透)。關(guān)于 .env
文件的用法粟誓,就不多說了 https://github.com/motdotla/dotenv 里有奏寨,然后我看到里面:
Should I have multiple .env files?
No. We strongly recommend against having a "main" .env file and an "environment" .env file like .env.test. Your config should vary between deploys, and you should not be sharing values between environments.
里面是不提倡用多個 .env.*.*
這樣的文件的,可是 create-react-app 里則提倡用多個這樣的文件鹰服,比如 .env.development.local
病瞳、.env.development
、.env.local
……這樣的悲酷,然后讀取這些配置的時候有個優(yōu)先級套菜,這些代碼都寫在項目根目錄下的 config/env.js
里的,然后在切換環(huán)境的時候都會執(zhí)行一遍這個文件设易,讀取對應(yīng)的配置逗柴,我暫時還沒弄懂它讀取所有 .env.*.*
文件的用意。但是我目前也沒想到如何單憑一個 .env
文件而能實現(xiàn)我想要的東西亡嫌,所以我也用的多個 .env 文件嚎于,但是我稍微改寫了env.js
掘而、start.js
、webpcakDevServer.js
于购、webpack.config.dev.js
和 webpack.config.prod.js
袍睡,使得一個環(huán)境對應(yīng)特定的 .env 文件,每個環(huán)境里的通用配置的字段都一樣肋僧,然后正式代碼里只用讀取這些字段就可以了斑胜,這些字段會根據(jù)不同的環(huán)境提供不同的值。其起作用的原理 https://github.com/mrsteele/dotenv-webpack 里有寫:
The plugin can be installed with little-to-no configuration needed. Once installed, you can access the variables within your code using process.env as you would with dotenv.
就是說嫌吠,在編譯時止潘,將正式代碼里引用了 .env
文件配置的變量直接替換成對應(yīng)的值,比如 .env
里有 HOST = xxx.xxx.xxx
辫诅,然后正式的 js 代碼里有 const host = process.env.HOST
凭戴,然后在編譯過程中 HOST
這個變量會被替換成 xxx.xxx.xxx
,所以編譯后的代碼就會是 const host = 'xxx.xxx.xxx'
炕矮,相當(dāng)于對正式 js 代碼提供了一個全局變量 process.env.HOST
么夫,但是這個變量只在編譯時有效。dotenv-webpack
這個插件的用法:
const Dotenv = require('dotenv-webpack');
module.exports = {
...
plugins: [
new Dotenv()
]
...
}
用了這個插件后 new webpack.definePlugin({...})
這條語句實現(xiàn)的功能可一并由 dotenv-webpack
來實現(xiàn)了肤视,只需要在對應(yīng) .env
文件里寫上 NODE_ENV = development
或 NODE_ENV = production
就可以了档痪。此外,new DotEnv()
接受一個配置對象邢滑,里面有個 path
字段腐螟,值是加載的 .env
文件的路徑,這就允許我們根據(jù)不同的條件加載不同的 .env.*.*
文件困后,這是實現(xiàn)我想要的功能的關(guān)鍵(不過這也應(yīng)該是一個插件必然會提供的)乐纸。
下面我以默認開發(fā)環(huán)境和 mock 環(huán)境為例,簡單說下大致細節(jié)操灿。這二者都算開發(fā)環(huán)境锯仪,但還是可能會在某些時候需要區(qū)分”枚剑現(xiàn)在我為 mock 環(huán)境配一個 .env.development.local
文件趾盐,然后當(dāng)我執(zhí)行 npm run start:mock
時讓 new DotEnv(option)
加載這個文件,而在 npm run start
時加載 .env.develpment
文件小腊。 npm run start
真正執(zhí)行的是 node ./scripts/start.js
救鲤,然后這個 start.js
文件里有對 webpcak.config.dev.js
這個文件的引用,需要用到它導(dǎo)出的 webpack 的配置秩冈,這是一個靜態(tài)的對象本缠,所以如果我們在 webpcak.config.dev.js
里將 new DotEnv(option)
里的 option 寫死的話,那么我們對于多個 option
就需要導(dǎo)出多個 webpack 配置入问,所以可以將 webpcak.config.dev.js
的導(dǎo)出做成一個接受一個 option
的函數(shù)丹锹,函數(shù)的返回值是應(yīng)用了這個 option
而生成的配置對象稀颁。然后我們需要一個變量來決定 option
的取值,這個變量需要在 start.js
里出現(xiàn)楣黍,然后這個變量顯然不能是通過在 start.js
文件里通過 const arg = 'xxx'
來生成而只能通過外部傳入匾灶,怎么傳入呢?很自然想到在命令行里傳入租漂,然后再對應(yīng)的腳本文件里讀取 process.argv
來獲取阶女。于是:
// package.json
{
...
"start:mock": "node ./scrips/start.js mock"
...
}
將 mock 這個字符串傳到 start.js
里,然后 start.js
通過判斷 process.argv[2] === ‘mock’
來決定加載哪個 .env
文件哩治。加載其他 .env
的原理一致秃踩。
此外,當(dāng)我們切換到 mock 環(huán)境時候业筏,還有一件事情要做憔杨,就是開啟本地的 mock 服務(wù),當(dāng)然我們可以在輸入 npm run start:mock
之后再又去手動開啟 mock 服務(wù)蒜胖,但步也可以放到 npm run start:mock
命令去完成芍秆,通過 npm-run-all
這個 npm 模塊。
然后翠勉,通常 mock 服務(wù)是不是也會有個類似的 config.js
文件妖啥,但是這里我們既然已經(jīng)有了 env.development.lcoal
那便不必再費事去多維護一些多余的數(shù)據(jù)了。通過
const config = require('dotenv').config({
path: dotEnvFile
}).parsed
就可以讀取一個由 .env
里的配置轉(zhuǎn)換而成的配置對象对碌,然后這就保持正式 js 代碼里的配置值和實際 mock 服務(wù)的配置永遠一致了荆虱。