Webpack 設置環境變量的誤區

1、前言

  • 平常的前端開發工做中,至少會有兩套構建環境
    • 一套開發時使用,構建結果用於本地開發調試,不進行代碼壓縮、打印 debug 信息、包含 sourcemap 文件等
    • 一套發佈時使用,構建結果用於線上,即代碼都是壓縮過的、運行時不打印 debug 信息、靜態文件不包括 sourcemap 等
  • webpack 4.0 版本開始引入了 mode 的概念
選項 描述
development 會將 process.env.NODE_ENV 的值設爲 development。啓用 NamedChunksPluginNamedModulesPlugin
production 會將 process.env.NODE_ENV 的值設爲 production。啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPluginUglifyJsPlugin

2、區分開發環境/生產環境的多種方式

2.1 使用命令行

2.1.1 寫法一

"scripts": {
    // 默認 mode 爲 development
    "dev1": "webpack-dev-server",
    // 默認 mode 爲 production,不過這樣寫,打包的時候會有警告
    "build1": "webpack",
}
複製代碼
  • 以上 script 腳本,能夠在任意模塊內經過 process.env.NODE_ENV 獲取當前的環境變量
  • 但沒法在 node 環境(webpack 配置文件中)下獲取當前的環境變量
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
複製代碼

2.1.2 寫法二

"scripts": {
   "dev2": "webpack --mode=development",
   "build2": "webpack --mode=production",
}
複製代碼
  • 寫法一, 是同樣的結果

2.1.3 寫法三

"scripts": {
   "dev3": "webpack-dev-server --env=development",
   "build3": "webpack --env=production",
}
複製代碼
  • 以上 script 腳本,沒法在任意模塊內經過 process.env.NODE_ENV 獲取當前的環境變量
  • 但能夠在 node 環境(webpack 配置文件中)下,經過函數獲取當前環境變量
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// undefined
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

// 經過函數獲取當前環境變量
module.exports = (env,argv) => {
  console.log('env',env);// development | production
  return {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
  }
};
複製代碼

2.2 使用 mode

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development | production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('NODE_ENV',process.env.NODE_ENV);// undefined

module.exports =  {
  	mode:'development',// development | production
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
複製代碼
  • 和 2.1 中的寫法二,是同樣的結果
  • 一個是在命令行中設置,一個是在 webpack 配置文件中設置

2.3 使用 webpack.DefinePlugin

  • 首先得知道這個插件的做用:設置全局變量(並不是掛載到 window 上),全部模塊都能讀取到該變量的值
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development
   console.log(NODE_ENV);//  production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

// 這裏只是湊巧和環境變量同名了,因此纔不會報錯
console.log('process.env.NODE_ENV',process.env.NODE_ENV);// undefined
console.log('NODE_ENV',NODE_ENV);// error !!!

module.exports =  {
  	mode:'development',// development | production
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
            new webpack.DefinePlugin({
           	'process.env.NODE_ENV':JSON.stringify('development'),
                'NODE_ENV':JSON.stringify('production'),
       }),
    ],
    		...
};
複製代碼
  • 能夠在任意模塊內經過 process.env.NODE_ENV 獲取當前的環境變量
  • 但沒法在 node 環境(webpack 配置文件中)下獲取當前的環境變量

2.4 使用 cross-env 插件

  • 原先我一直覺得這個插件,能夠用來設置全部環境(瀏覽器環境、node 環境)下的變量。通過測試發現,只能設置node 環境下的變量 —— NODE_ENV

2.4.1 寫法一

"scripts": {
 	"dev1": "cross-env NODE_ENV='production' webpack-dev-server",
        "build1": "cross-env NODE_ENV='development' webpack",
}
複製代碼
  • 以上 script 腳本,能夠在任意模塊內經過 process.env.NODE_ENV 獲取當前的環境變量
  • 能夠在 node 環境(webpack 配置文件中)下,獲取當前環境變量
  • 可是會有一個問題: 瀏覽器環境和 node 環境下獲取到的值是不同的
//  !!!!!!
// npm run build1 
//  !!!!!!

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
複製代碼

2.4.2 寫法二

"scripts": {
  "dev2": "cross-env NODE_ENV='development' --mode development",
  "build2": "cross-env NODE_ENV='production' --mode production",
}
複製代碼
  • 以上 script 腳本,能夠在任意模塊內經過 process.env.NODE_ENV 獲取當前的環境變量
  • 能夠在 node 環境(webpack 配置文件中)下,獲取當前環境變量
  • 因此在能瀏覽器環境下讀取到環境變量的值,靠的是 mode ,在 node 環境下讀取到環境變量的值,靠的是 cross-env
//  !!!!!!
// npm run build2 
//  !!!!!!

// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// production
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// production

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
    		...
};
複製代碼

3、誤區

  • 常常在一些羣裏看到這個問題: cross-envwebpack.DefinePlugin 配合使用的時候,沒法經過 process.env.xxx 來獲取到設置的環境變量,須要經過 webpack.DefinePlugin 裏面設置的 key 來獲取。
  • 會引起這個問題的可能緣由是:先往 cross-env 裏設置了 NODE_ENV 變量,而後又到 DefinePlugin裏設置了一遍環境變量
"scripts": {
  "dev": "cross-env NODE_ENV='development' --mode development"
}
複製代碼
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// development
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
           new webpack.DefinePlugin({
             	// 設置環境變量
               	'process.env.NODE_ENV':JSON.stringify('development'),
           }),
        ],
    		...
};
複製代碼
  • 此時會發現瀏覽器環境和 node 環境都能獲取到設置的變量了,而後就認爲以後再設置其餘的全局變量時,也像這樣寫就好了。javascript

  • 認爲 cross-envDefinePlugin 是配套一塊兒使用的,這個見解自己就很奇怪,由於二者的做用點不同前端

    • DefinePlugin 的做用:是設置瀏覽器環境下能讀取到的 "全局變量",直接經過 key 讀取,在 node 環境下是沒法讀取到的
    • cross-env 的做用:是經過命令行設置環境變量 NODE_ENV,使 node 環境下能讀取到,經過 process.env.NODE_ENV 讀取
    • 若是在DefinePlugin 裏設置的 keyprocess.env.NODE_ENV ,會覆蓋 webpack 經過 mode 模式設置的環境變量的值
"scripts": {
  "dev": "cross-env NODE_ENV='development' --mode development"
}
複製代碼
// index.js 
function getEnv() {
   console.log(process.env.NODE_ENV);// 666666
}

// webpack.config.js
const path = require('path');
const webpack = require('webpack');

console.log('process.env.NODE_ENV',process.env.NODE_ENV);// development

module.exports =  {
  	entry:'./src/index.js',
        output: {
            filename: 'js/[name].js'
        },
  	plugins:[
           new webpack.DefinePlugin({
                // 注意:由於同名的 key,這裏的值會覆蓋默認的值 !!!!!!
               	'process.env.NODE_ENV':JSON.stringify('666666'),
           }),
        ],
    		...
};
複製代碼

4、總結

  • cross-env專門用來設置 node 環境變量
  • webpack.DefinePlugin專門用來設置瀏覽器環境下的全局變量(不會掛載到 window 上)
  • 本文只是我我的的理解,若有錯誤還請告知,萬分感謝

5、推薦閱讀

你真的瞭解 React 生命週期嗎java

React Hooks 詳解 【近 1W 字】+ 項目實戰node

React SSR 詳解【近 1W 字】+ 2個項目實戰webpack

從 0 到 1 實現一款簡易版 Webpackweb

相關文章
相關標籤/搜索