從源碼看React環(huán)境變量那些事兒

// 文件目錄結構
|--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...
    })
    
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末泞辐,一起剝皮案震驚了整個濱河市笔横,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌咐吼,老刑警劉巖吹缔,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異锯茄,居然都是意外死亡厢塘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來俗冻,“玉大人礁叔,你說我怎么就攤上這事∑。” “怎么了琅关?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讥蔽。 經(jīng)常有香客問我涣易,道長,這世上最難降的妖魔是什么冶伞? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任新症,我火速辦了婚禮,結果婚禮上响禽,老公的妹妹穿的比我還像新娘徒爹。我一直安慰自己,他們只是感情好芋类,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布隆嗅。 她就那樣靜靜地躺著,像睡著了一般侯繁。 火紅的嫁衣襯著肌膚如雪胖喳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天贮竟,我揣著相機與錄音丽焊,去河邊找鬼。 笑死咕别,一個胖子當著我的面吹牛技健,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顷级,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼凫乖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弓颈?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤删掀,失蹤者是張志新(化名)和其女友劉穎翔冀,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體披泪,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡纤子,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片控硼。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡泽论,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卡乾,到底是詐尸還是另有隱情翼悴,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布幔妨,位于F島的核電站鹦赎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏误堡。R本人自食惡果不足惜古话,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锁施。 院中可真熱鬧陪踩,春花似錦、人聲如沸悉抵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽基跑。三九已至婚温,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間媳否,已是汗流浹背栅螟。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留篱竭,地道東北人力图。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像掺逼,于是被迫代替她去往敵國和親吃媒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容