摘要:開發環境和生產環境都擁有的配置,但在細節上有所不同,比如說,又比如說中的和參數。更重要的是,實際上開發環境和生產環境的配置文件的絕大部分都是一致的,對于這一致的部分來說,我們堅決要消除冗余,否則后續維護起來不僅麻煩,而且還容易出錯。
本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。前言
原文地址:https://segmentfault.com/a/1190000006952432
如果您對本系列文章感興趣,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang
開發環境與生產環境分離的原因如下:
在開發時,不可避免會產生大量debug又或是測試的代碼,這些代碼不應出現在生產環境中(也即不應提供給用戶)。
在把頁面部署到服務器時,為了追求極致的技術指標,我們會對代碼進行各種各樣的優化,比如說混淆、壓縮,這些手段往往會徹底破壞代碼本身的可讀性,不利于我們進行debug等工作。
數據源的差異化,比如說在本地開發時,讀取的往往是本地mock出來的數據,而正式上線后讀取的自然是API提供的數據了。
如果硬是要在開發環境和生產環境用完全一樣的代碼,那么必然會付出沉重的代價,這點想必也不用多說了。
下面主要針對兩點來介紹如何分離開發環境和生產環境:一是如何以不同的方式進行編譯,也即如何分別形成開發環境及生產環境的webpack配置文件;二是在業務代碼中如何根據環境的不同而做出不同的處理。
如何分離開發環境和生產環境的webpack配置文件如果同時把一份完整的開發環境配置文件和一份完整的生產環境配置文件列在一起進行比較,那么會出現以下三種情況:
開發環境有的配置,生產環境不一定有,比如說開發時需要生成sourcemap來幫助debug,又或是熱更新時使用到的HotModuleReplacementPlugin。
生產環境有的配置,開發環境不一定有,比如說用來混淆壓縮js用的UglifyJsPlugin。
開發環境和生產環境都擁有的配置,但在細節上有所不同,比如說output.publicPath,又比如說css-loader中的minimize和autoprefixer參數。
更重要的是,實際上開發環境和生產環境的配置文件的絕大部分都是一致的,對于這一致的部分來說,我們堅決要消除冗余,否則后續維護起來不僅麻煩,而且還容易出錯。
怎么做呢?答案很簡單:分拆webpack配置文件成N個小module。原先我們是一個完整的配置文件,有好幾百行,從頭看到尾都頭大了,更別說分離不分離的了。下面來看看我分離的結果:
├─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.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"), };
這樣,你就可以很輕松地處理開發/生產環境配置文件中相同與不同的部分了。
如何分別調用開發/生產環境的配置文件呢?還記得我在《webpack多頁應用架構系列(二):webpack配置常用部分有哪些?》里講過,我們在控制臺調用webpack命令來啟動打包時,可以添加上--config參數來指定webpack配置文件的路徑嗎?我們可以配合上npm scripts來使用,在package.json里定義:
"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。
業務代碼如何判斷生產/開發環境在業務代碼里要判斷生產/開發環境其實很簡單,只需一個變量即可:
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)。
附系列文章目錄(同步更新)webpack多頁應用架構系列(一):一步一步解決架構痛點:https://segmentfault.com/a/1190000006843916
webpack多頁應用架構系列(二):webpack配置常用部分有哪些?:https://segmentfault.com/a/1190000006863968
webpack多頁應用架構系列(三):怎么打包公共代碼才能避免重復?:https://segmentfault.com/a/1190000006871991
webpack多頁應用架構系列(四):老式jQuery插件還不能丟,怎么兼容?:https://segmentfault.com/a/1190000006887523
webpack多頁應用架構系列(五):聽說webpack連less/css也能打包?:https://segmentfault.com/a/1190000006897458
webpack多頁應用架構系列(六):聽說webpack連圖片和字體也能打包?:https://segmentfault.com/a/1190000006907701
webpack多頁應用架構系列(七):開發環境、生產環境傻傻分不清楚?:https://segmentfault.com/a/1190000006952432
webpack多頁應用架構系列(八):教練我要寫ES6!webpack怎么整合Babel?:https://segmentfault.com/a/1190000006992218
webpack多頁應用架構系列(九):總有刁民想害朕!ESLint為你阻擊垃圾代碼:https://segmentfault.com/a/1190000007030775
webpack多頁應用架構系列(十):如何打造一個自定義的bootstrap:https://segmentfault.com/a/1190000007043716
webpack多頁應用架構系列(十一):預打包Dll,實現webpack音速編譯:https://segmentfault.com/a/1190000007104372
webpack多頁應用架構系列(十二):利用webpack生成HTML普通網頁&頁面模板:https://segmentfault.com/a/1190000007126268
webpack多頁應用架構系列(十三):構建一個簡單的模板布局系統:https://segmentfault.com/a/1190000007159115
webpack多頁應用架構系列(十四):No復制粘貼!多項目共用基礎設施
webpack多頁應用架構系列(十五):論前端如何在后端渲染開發模式下夾縫生存
webpack多頁應用架構系列(十六):善用瀏覽器緩存,該去則去,該留則留
本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。
原文地址:https://segmentfault.com/a/1190000006952432
如果您對本系列文章感興趣,歡迎關注訂閱這里:https://segmentfault.com/blog/array_huang
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/80419.html
摘要:本文首發于的技術博客實用至上,非經作者同意,請勿轉載。原文地址如果您對本系列文章感興趣,歡迎關注訂閱這里這系列文章講什么本系列文章主要介紹如何用這一當前流行的構建工具來設計一個多頁應用的架構。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/1190000006843916如果您對本系列文章...
摘要:在上一篇文章多頁應用架構系列二配置常用部分有哪些中,我介紹了如何配置多頁應用的入口,然而,如果僅僅如此操作,帶來的后果就是,打包生成出來的每一個入口文件都會完整包含所有代碼。的初始化常用參數有哪些,給這個包含公共代碼的命個名唯一標識。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/1190...
摘要:本文首發于的技術博客實用至上,非經作者同意,請勿轉載。只是最近學習生態,用起來轉換之余,也不免碰到諸多用上的教程案例,因此便稍作學習。在當前的瀏覽器市場下,想在生產環境用上,是必不可少的。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/1190000006992218如果您對本系列文章感興...
摘要:本文首發于的技術博客實用至上,非經作者同意,請勿轉載。如果你使用了,或類似的,那么,通過編譯前后的代碼相差就很大了,這會造成兩個問題以為例把你的代碼轉成什么樣你自己是無法控制的,這往往導致無法通過的審查。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/1190000007030775如果您...
摘要:本文首發于的技術博客實用至上,非經作者同意,請勿轉載。原文地址如果您對本系列文章感興趣,歡迎關注訂閱這里前言書承上文多頁應用架構系列十如何打造一個自定義的。終于,發現了這一大殺器,打包時間過長的問題得到完美解決。 本文首發于Array_Huang的技術博客——實用至上,非經作者同意,請勿轉載。原文地址:https://segmentfault.com/a/119000000710437...
閱讀 2330·2021-09-30 09:47
閱讀 2949·2019-08-30 11:05
閱讀 2526·2019-08-29 17:20
閱讀 1912·2019-08-29 13:01
閱讀 1721·2019-08-26 13:39
閱讀 1221·2019-08-26 13:26
閱讀 3205·2019-08-23 18:40
閱讀 1810·2019-08-23 17:09