本文首發於 Array_Huang的技術博客——實用至上
,非經做者贊成,請勿轉載。
原文地址: http://www.javashuo.com/article/p-gfjsypje-kc.html
若是您對本系列文章感興趣,歡迎關注訂閱這裏:https://segmentfault.com/blog/array_huang
開發環境與生產環境分離的緣由以下:javascript
若是硬是要在開發環境和生產環境用徹底同樣的代碼,那麼必然會付出沉重的代價,這點想必也不用多說了。css
下面主要針對兩點來介紹如何分離開發環境和生產環境:一是如何以不一樣的方式進行編譯,也即如何分別造成開發環境及生產環境的webpack配置文件;二是在業務代碼中如何根據環境的不一樣而作出不一樣的處理。html
若是同時把一份完整的開發環境配置文件和一份完整的生產環境配置文件列在一塊兒進行比較,那麼會出現如下三種狀況:前端
HotModuleReplacementPlugin
。UglifyJsPlugin
。output.publicPath
,又好比說css-loader
中的minimize
和autoprefixer
參數。更重要的是,實際上開發環境和生產環境的配置文件的絕大部分都是一致的,對於這一致的部分來講,咱們堅定要消除冗餘,不然後續維護起來不只麻煩,並且還容易出錯。java
答案很簡單:分拆webpack配置文件成N個小module。原先咱們是一個完整的配置文件,有好幾百行,從頭看到尾都頭大了,更別說分離不分離的了。下面來看看我分離的結果:node
├─webpack.dev.config.js # 開發環境的webpack配置文件(無實質內容,僅爲組織整理) ├─webpack.config.js # 生產環境的webpack配置文件(無實質內容,僅爲組織整理) ├─webpack-config # 存放分拆後的webpack配置文件 ├─entry.config.js # webpack配置中的各個大項,這一級目錄裏的文件都是 ├─module.config.js ├─output.config.js ├─plugins.dev.config.js # 倆環境配置中不一致的部分,此文件由開發環境配置文件webpack.dev.config.js來加載 ├─plugins.product.config.js # 倆環境配置中不一致的部分,此文件由生產環境配置文件webpack.config.js來加載 ├─resolve.config.js │ ├─base # 主要是存放一些變量 │ ├─dir-vars.config.js │ ├─page-entries.config.js │ ├─inherit # 存放生產環境和開發環境相同的部分,以供繼承 │ ├─plugins.config.js │ └─vendor # 存放webpack兼容第三方庫所需的配置文件 ├─eslint.config.js ├─postcss.config.js
文件目錄結構看過了,接下來看一下我是如何組織整理最後的配置文件的:webpack
/* 開發環境webpack配置文件webpack.dev.config.js */ module.exports = { entry: require('./webpack-config/entry.config.js'), output: require('./webpack-config/output.config.js'), module: require('./webpack-config/module.config.js'), resolve: require('./webpack-config/resolve.config.js'), plugins: require('./webpack-config/plugins.dev.config.js'), eslint: require('./webpack-config/vendor/eslint.config.js'), postcss: require('./webpack-config/vendor/postcss.config.js'), };
這樣,你就能夠很輕鬆地處理開發/生產環境配置文件中相同與不一樣的部分了。git
還記得我在《webpack多頁應用架構系列(二):webpack配置經常使用部分有哪些?》裏講過,咱們在控制檯調用webpack命令來啓動打包時,能夠添加上--config
參數來指定webpack配置文件的路徑嗎?咱們能夠配合上npm scripts
來使用,在package.json裏定義:github
"scripts": { "build": "node build-script.js && webpack --progress --colors", "dev": "node build-script.js && webpack --progress --colors --config ./webpack.dev.config.js", "watch": "webpack --progress --colors --watch --config ./webpack.dev.config.js" },
這樣一來,當咱們開發的時候就可使用npm run dev
或npm run watch
,而到要上線打包的時候就運行npm run build
。web
在業務代碼裏要判斷生產/開發環境其實很簡單,只需一個變量便可:
if (IS_PRODUCTION) { // 作生產環境該作的事情 } else { // 作開發環境該作的事情 }
這麼一來,關鍵就在於這變量IS_PRODUCTION
是怎麼來的了。
在我還沒分離開發和生產環境時,我用的辦法是,開發時在業務代碼所使用的配置文件中把這變量設爲false
,而在最後打包上線時就手動改成true
。這種方法我用過一段時間,很是繁瑣,並且常常上線後發現,我嘞個去怎麼ajax讀的是我本地的mock服務器。
我參考了許多文章,先粗略講講我沒有采用的方法:
EnvironmentPlugin
引入process.env,這樣就能夠在業務代碼中靠process.env.NODE_ENV
來判斷了。ProvidePlugin
來控制在不一樣環境里加載不一樣的配置文件(業務代碼用的)。那我用的是什麼方法呢?我最後選用的是DefinePlugin
。
舉個官方例子,其大概用法是這樣的:
new webpack.DefinePlugin({ PRODUCTION: JSON.stringify(true), VERSION: JSON.stringify("5fa3b9"), BROWSER_SUPPORTS_HTML5: true, TWO: "1+1", "typeof window": JSON.stringify("object") })
DefinePlugin
可能會被誤認爲其做用是在webpack配置文件中爲編譯後的代碼上下文環境設置全局變量,但其實否則。它真正的機制是:DefinePlugin
的參數是一個object,那麼其中會有一些key-value
對。在webpack編譯的時候,會把業務代碼中沒有定義(使用var/const/let來預約義的)而變量名又與key
相同的變量(直接讀代碼的話的確像是全局變量)替換成value
。例如上面的官方例子,PRODUCTION
就會被替換爲true
;VERSION
就會被替換爲'5fa3b9'
(注意單引號);BROWSER_SUPPORTS_HTML5
也是會被替換爲true
;TWO
會被替換爲1+1
(至關因而一個數學表達式);typeof window
就被替換爲'object'
了。
再舉個例子,好比你在代碼裏是這麼寫的:
if (!PRODUCTION) console.log('Debug info') if (PRODUCTION) console.log('Production log')
那麼在編譯生成的代碼裏就會是這樣了:
if (!true) console.log('Debug info') if (true) console.log('Production log')
而若是你用了UglifyJsPlugin
,則會變成這樣:
console.log('Production log')
如此一來,只要在倆環境的配置文件裏用DefinePlugin
分別定義好IS_PRODUCTION
的值,咱們就能夠在業務代碼裏進行判斷了:
/* global IS_PRODUCTION:true */ if (!IS_PRODUCTION) { console.log('若是你看到這個Log,那麼這個版本其實是開發用的版本'); }
須要注意的是,若是你在webpack裏整合了ESLint,那麼,因爲ESLint會檢測沒有定義的變量(ESLint要求使用全局變量時要用window.xxxxx
的寫法),所以須要一個global
註釋聲明(/* global IS_PRODUCTION:true */
)IS_PRODUCTION是一個全局變量(固然在本例中並非)來規避warning。
諸位看本系列文章,搭配我在Github上的腳手架項目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed
)。
https://segmentfault.com/a/1190000006843916
https://segmentfault.com/a/1190000006863968
https://segmentfault.com/a/1190000006871991
https://segmentfault.com/a/1190000006887523
https://segmentfault.com/a/1190000006897458
https://segmentfault.com/a/1190000006907701
https://segmentfault.com/a/1190000006952432
https://segmentfault.com/a/1190000006992218
https://segmentfault.com/a/1190000007030775
https://segmentfault.com/a/1190000007043716
https://segmentfault.com/a/1190000007104372
https://segmentfault.com/a/1190000007126268
https://segmentfault.com/a/1190000007159115
本文首發於 Array_Huang的技術博客——實用至上
,非經做者贊成,請勿轉載。
原文地址: http://www.javashuo.com/article/p-gfjsypje-kc.html
若是您對本系列文章感興趣,歡迎關注訂閱這裏:https://segmentfault.com/blog/array_huang