webpack學習筆記--區分環境
在開發網頁的時候,一般都會有多套運行環境,例如:
- 在開發過程中方便開發調試的環境。
- 發布到線上給用戶使用的運行環境。
這兩套不同的環境雖然都是由同一套源代碼編譯而來,但是代碼內容卻不一樣,差異包括:
- 線上代碼被通過 4-8 壓縮代碼 中提到的方法壓縮過。
- 開發用的代碼包含一些用於提示開發者的提示日誌,這些日誌普通用戶不可能去看它。
- 開發用的代碼所連接的後端數據接口地址也可能和線上環境不同,因為要避免開發過程中造成對線上數據的影響。
為了盡可能的復用代碼,在構建的過程中需要根據目標代碼要運行的環境而輸出不同的代碼,我們需要一套機制在源碼中去區分環境。 幸運的是 Webpack 已經為我們實現了這點。
如何區分環境
具體區分方法很簡單,在源碼中通過如下方式:
if (process.env.NODE_ENV === ‘production‘) { console.log(‘你正在線上環境‘); } else { console.log(‘你正在使用開發環境‘); }
其大概原理是借助於環境變量的值去判斷執行哪個分支。
當你的代碼中出現了使用 process 模塊的語句時,Webpack 就自動打包進 process 模塊的代碼以支持非 Node.js 的運行環境。 當你的代碼中沒有使用 process 時就不會打包進 process 模塊的代碼。這個註入的 process 模塊作用是為了模擬 Node.js 中的 process,以支持上面使用的 process.env.NODE_ENV === ‘production‘
在構建線上環境代碼時,需要給當前運行環境設置環境變量 NODE_ENV = ‘production‘ ,Webpack 相關配置如下:
const DefinePlugin = require(‘webpack/lib/DefinePlugin‘); module.exports = { plugins: [ new DefinePlugin({ // 定義 NODE_ENV 環境變量為 production ‘process.env‘: { NODE_ENV: JSON.stringify(‘production‘) } }), ], };
註意在定義環境變量的值時用 JSON.stringify 包裹字符串的原因是環境變量的值需要是一個由雙引號包裹的字符串,而 JSON.stringify(‘production‘) 的值正好等於 "production" 。
執行構建後,你會在輸出的文件中發現如下代碼:
if (true) { console.log(‘你正在使用線上環境‘); } else { console.log(‘你正在使用開發環境‘); }
定義的環境變量的值被代入到了源碼中, process.env.NODE_ENV === ‘production‘ 被直接替換成了 true
。 並且由於此時訪問 process 的語句被替換了而沒有了,Webpack 也不會打包進 process 模塊了。
DefinePlugin 定義的環境變量只對 Webpack 需要處理的代碼有效,而不會影響 Node.js 運行時的環境變量的值。
通過 Shell 腳本的方式去定義的環境變量,例如 NODE_ENV=production webpack ,Webpack 是不認識的,對 Webpack 需要處理的代碼中的環境區分語句是沒有作用的。
也就是說只需要通過 DefinePlugin 定義環境變量就能使上面介紹的環境區分語句正常工作,沒必要又通過 Shell 腳本的方式去定義一遍。
如果你想讓 Webpack 使用通過 Shell 腳本的方式去定義的環境變量,你可以使用 EnvironmentPlugin,代碼如下:
new webpack.EnvironmentPlugin([‘NODE_ENV‘])
以上這句代碼實際上等價於:
new webpack.DefinePlugin({ ‘process.env.NODE_ENV‘: JSON.stringify(process.env.NODE_ENV), })
結合 UglifyJS
其實以上輸出的代碼還可以進一步優化,因為 if(true) 語句永遠只會執行前一個分支中的代碼,也就是說最佳的輸出其實應該直接是:
console.log(‘你正在線上環境‘);
Webpack 沒有實現去除死代碼功能,但是 UglifyJS 可以做這個事情,如何使用請閱讀 4-8 壓縮代碼 中的壓縮 JavaScript。
第三方庫中的環境區分
除了在自己寫的源碼中可以有環境區分的代碼外,很多第三方庫也做了環境區分的優化。 以 React 為例,它做了兩套環境區分,分別是:
- 開發環境:包含類型檢查、HTML 元素檢查等等針對開發者的警告日誌代碼。
- 線上環境:去掉了所有針對開發者的代碼,只保留讓 React 能正常運行的部分,以優化大小和性能。
例如 React 源碼中有大量類似下面這樣的代碼:
if (process.env.NODE_ENV !== ‘production‘) { warning(false, ‘%s(...): Can only update a mounted or mounting component.... ‘) }
如果你不定義 NODE_ENV=production 那麽這些警告日誌就會被包含到輸出的代碼中,輸出的文件將會非常大。
process.env.NODE_ENV !== ‘production‘ 中的 NODE_ENV 和 ‘ production ‘
兩個值是社區的約定,通常使用這條判斷語句在區分開發環境和線上環境。本實例 提供項目完整代碼
webpack學習筆記--區分環境