深刻淺出webpack學習(18)--區分環境

爲何要區分環境

在開發網頁的時候,通常都會有多套運行環境,例如:node

  1. 在開發過程當中方便開發調試的環境。
  2. 發佈到線上給用戶使用的運行環境。

這兩套不一樣的環境雖然都是由同一套代碼編譯而來,可是代碼內容卻不同,差別包括:react

線上代碼通過壓縮處理
開發用的代碼包含一些用於提示開發者的提示日誌,這些日誌普通用戶不可能去看它
開發用的代碼所鏈接的後端數據接口地址也可能和線上環境不一樣,由於避免開發過程當中形成對線上數據的影響。

爲了儘量的複用代碼,在構建的過程當中須要根據目標代碼要運行的環境而輸出不一樣的代碼。咱們須要一套機制在源碼中去區分環境。幸運的是webpack已經爲咱們實現了。webpack

如何區分環境

具體區分方法比較簡單,在源碼中經過以下方式:web

if(process.env.NODE_ENV === "production") {
    console.log("你正在線上環境")
}else {
    console.log("你正在使用開發環境")
}

其大概原理是藉助於環境變量的值去判斷執行哪一個分支。shell

當你的代碼中出現了使用process模塊的語句時, webpack就自動打包進process模塊的代碼以支持非nodejs的運行環境。當你的代碼中沒有使用proces時就不會打包進process模塊的代碼。這個注入process模塊做用就是爲了模擬nodejs中的process,以支持上面使用的後端

process.env.NODE_ENV === 'production'

在構建線上環境代碼時,須要給當前運行環境設置環境設置環境變量NODE_ENV == 'prodeuction',webpack的配置以下:性能

const DefinePlugin = require("webpack/lib/DefinePlugin")

module.exports = {
    plugins: [
        new DefinePlugin({
            //定義NODE_ENV環境變量爲production
            "production.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模塊了。ui

DefinePlugin定義的環境變量只對webpack須要處理的代碼有效, 而不會影響nodejs運行時的環境變量的值。調試

經過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沒有實現去除死代碼的功能,可是UglifyJ能夠作這個事情。

第三方庫中的環境區分

除了在本身寫的源碼中能夠有環境區分的代碼外, 不少第三方庫也作了環境區分的優化。以react爲例,它作了兩套環境區分:

  1. 開發環境: 包含類型檢查, HTML元素檢查等等針對開發者的警告日誌代碼;
  2. 線上環境: 去掉全部針對開發者的代碼,只保留讓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'兩個值是社區的約定, 一般使用這條判斷語句在區分開發環境和線上環境。

相關文章
相關標籤/搜索