// 文件目錄結構
|--config
|--jest
|--env.js
...
|--paths.js
|--node_modules
|--public
|--scripts
|--build.js
|--start.js
|--test.js
|--src
|--package.json
使用第三方庫 dotenv冬阳、dotenv-expand
-
dotenv解析文件賦值到process.env荠锭,默認解析.env文件。也可添加配置去解析其他文件
const path = require("path"); const envFile = path.join(__dirname, ".env.local") dotenv({path: envFile});
-
Dotenv-expand
默認dotenv不能解析文件里的變量栈拖,必須得是字符串才行司草,dotenv-expand 擴展了dotenv的功能
可在目標文件里通過{} 引用變量
// .env.local NODE_ENV = "production" VUE_APP_NAME = "vue app" SUNSET = $REAC_APP_NAME
使用規(guī)則
React中規(guī)定,要使用process.env上的變量兜喻,可以在本地新建.env梦染、.env.development、.env.production、.env.local 等文件帕识,在文件里定義以REACT_APP
開頭的變量泛粹。然后就可以在項目中使用 process.env.xxx
等環(huán)境變量。
從源碼中看環(huán)境變量的定義過程
-
當我們執(zhí)行npm start 時肮疗,在
scripts --> start.js
文件頭部一開始就掛載了兩個變量
BABEL_ENV
晶姊、NODE_ENV
// Do this as the first thing so that any code reading it knows the right env. process.env.BABEL_ENV = 'development'; process.env.NODE_ENV = 'development';
-
然后進入到
config --> env.js
文件首先這里定義 dotenvFiles ,是一個包含幾個文件名的數(shù)組,這幾個文件名就是上面提到的react規(guī)定的幾個定義變量的文件(.env 伪货、.env.local 们衙、.env.development ...)
其中paths.dotenv可以在
config --> paths.js`中找到,就是項目根目錄下的.env文件碱呼,
其余幾種都是基于.env的名字出來的砍艾。const NODE_ENV = process.env.NODE_ENV; if (!NODE_ENV) { throw new Error( 'The NODE_ENV environment variable is required but was not specified.' ); } // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use const dotenvFiles = [ `${paths.dotenv}.${NODE_ENV}.local`, `${paths.dotenv}.${NODE_ENV}`, // Don't include `.env.local` for `test` environment // since normally you expect tests to produce the same // results for everyone NODE_ENV !== 'test' && `${paths.dotenv}.local`, paths.dotenv, ].filter(Boolean);
這里遍歷上面的dotenvFiles,并用dotenv,dotenv-expand 分別綁定變量到 process.env上巍举。
執(zhí)行完下面這段代碼后就可以在process.env上看到自己在.env等文件中定義的變量脆荷。
到目前為止這些變量都只是在node環(huán)境中可見,在瀏覽器中是找不到的接下來通過webpack.DefinePlugin把變量注入到瀏覽器環(huán)境懊悯。
// Load environment variables from .env* files. Suppress warnings using silent // if this file is missing. dotenv will never modify any environment variables // that have already been set. Variable expansion is supported in .env files. // https://github.com/motdotla/dotenv // https://github.com/motdotla/dotenv-expand dotenvFiles.forEach(dotenvFile => { if (fs.existsSync(dotenvFile)) { require('dotenv-expand')( require('dotenv').config({ path: dotenvFile, }) ); } });
-
在把變量注入到瀏覽器環(huán)境之前蜓谋,react還做了一層過濾,在
config --> env.js
里定義了一個/^REACT_APP_/i
正則炭分,這個函數(shù)就是只抽取 變量名是REACT_APP_
開頭的變量作為客戶端環(huán)境變量const REACT_APP = /^REACT_APP_/i; function getClientEnvironment(publicUrl) { const raw = Object.keys(process.env) .filter(key => REACT_APP.test(key)) .reduce( (env, key) => { env[key] = process.env[key]; return env; }, { // Useful for determining whether we’re running in production mode. // Most importantly, it switches React into the correct mode. NODE_ENV: process.env.NODE_ENV || 'development', // Useful for resolving the correct path to static assets in `public`. // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />. // This should only be used as an escape hatch. Normally you would put // images into the `src` and `import` them in code to get their paths. PUBLIC_URL: publicUrl, // We support configuring the sockjs pathname during development. // These settings let a developer run multiple simultaneous projects. // They are used as the connection `hostname`, `pathname` and `port` // in webpackHotDevClient. They are used as the `sockHost`, `sockPath` // and `sockPort` options in webpack-dev-server. WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST, WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH, WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT, } ); // Stringify all values so we can feed into webpack DefinePlugin const stringified = { 'process.env': Object.keys(raw).reduce((env, key) => { env[key] = JSON.stringify(raw[key]); return env; }, {}), }; return { raw, stringified }; } module.exports = getClientEnvironment;
-
接下來打開
config --> webpack.config.js
,在plugins
配置里new webpack.DefinePlugin(env.stringified),
這一步就是把最終過濾出來的變量桃焕,注入到客戶端環(huán)境了。
最后放上一段webpack的部分文件介紹捧毛。
DefinePlugin
DefinePlugin
允許創(chuàng)建一個在編譯時可以配置的全局常量观堂。這可能會對開發(fā)模式和發(fā)布模式的構建允許不同的行為非常有用。如果在開發(fā)構建中呀忧,而不在發(fā)布構建中執(zhí)行日志記錄师痕,則可以使用全局常量來決定是否記錄日志。這就是DefinePlugin
的用處而账,設置它胰坟,就可以忘記開發(fā)和發(fā)布構建的規(guī)則。new webpack.DefinePlugin({ // Definitions... })