easywebpack 3.5.0 新特性一覽: dll工程化和多進程編譯
在 3.5.0 版本之前,項目大以後, webpack 構建打包越來越慢,同時 dll 工程化構建也沒有內置支持。雖然可以通過在 easywebpack 中添加 new webpack.DllPlugin() 和 webpack.DllReferencePlugin() 方式實現 dll 方案,但使用起來還是很繁瑣: 因為需要先單獨為 dll 添加 webpack.config.js 配置, 然後先手動先構建dll,然後在頁面裡面配置dll的引用,最後再構建頁面。easywebpack 3.5.0 從工程化的角度內置支持了。
1 easywebpack 3.5.0 特性一覽
- entry include 支持正則配置
- 支持 css extract hot reload
- 支持 webpack dll 配置和自動化構建, 無需手動先構建dll, 然後再構建頁面
- 簡化 commonsChunk lib 配置, 無需在 onClient 調用 addEntry 設置
- plugins 和 loaders 增加數組的配置的兼容,也就是支持原生配置
- 去掉options節點配置,改為 webpack.config.js 支持原生 Webpack 配置
- 支持多進程 Webpack 編譯, 結合dll功能編譯速度顯著提示,初步測試編譯時間減少2/3, 第三方組件越多和頁面越多,越明顯
- manifest和buildfie合併為新的manifest, 無需 manifest 和 manifestDeps 兼容配置, 同時去掉 buildfie 配置,
- 默認禁用 npm start 啟動檢查 webpack loader 和 plugin 是否安裝的功能, 提高編譯速度。
- stylus 和 less loader 默認有開啟改為禁用, 減少不必要的安裝
- 新增內置插件 webpack-bundle-analyzer 和 stats-webpack-plugin
- node externals 改為 webpack-node-externals 插件實現
- 壓縮插件由webpack內置改為 uglifyjs-webpack-plugin 獨立插件, 從而支持多進程編譯
- easywebpack-cli 增強,提供 dll 編譯以及 easy clean 和 easy open 命令。
- 解決 NODE_ENV=production 導致動態安裝 npm 依賴失敗
- 修復 easywebpack 配置合併覆蓋問題
2 Webpack dll 構建
2.1 當前網上流行的 dll 方案
- 1.需要單獨寫一份 dll 的 webpack 配置文件
- 2.需要手動先編譯 webpack dll manifest 文件
- 3.需要在另一份頁面 webpack 配置文件中引用 dll manifest 文件
- 4.編譯好dll manifest 文件後,再編譯頁面構建
- 5.構建的 dll.js 文件 和 頁面構建生產的 js 文件 手動引入
- 6.dll 配置變更時,需要手動再次重新執行 1 和 4 步驟
2.2 理想中 dll 構建:
- 1.只需要配置 dll 第三方庫信息,無需配置完整的 webpack.config.js
- 2.構建時無需手動編譯dll,有構建工具底層解決 dll編譯和頁面編譯銜接問題。
- 3.構建底層支持 dll.js 文件 和 頁面js 合併注入到頁面。
- 4.從底層支持配置變更,自動重新編譯dll
2.3 easywebpack dll 方案
easywebpack
^3.5.0 版本目前已經解決理想中 dll 構建方案的1,2, 3, 4。
2.3.1 easywebpack dll 配置
只需要在 webpack.config.js
文件添加 dll節點配置即可完成 dll
整個流程。
module.exports = { ... dll:[vue,vuex,axios]}
2.3.2 easywebpack dll 構建流程
使用過 Egg + Vue
或 Egg + React SSR
項目時,本地開發時,我們通過 npm start
一步完成 webpack 編譯 和 egg 項目啟動,簡化了先手動編譯 webpack,然後啟動egg的流程。Egg 項目是如何解決上面 dll 的問題呢?
- npm start 首次啟動時,檢查
webpack.config.js
是否配置了dll
節點信息, 如果配置了,同時 manifest-dll.json 文件不存在,則構建 dll.js 文件,同時生成 manifest-dll.json 文件 和 dll 的 資源依賴 manifest.json 文件。 - dll 構建完成後,自動啟動 webpack 頁面構建,同時把 dll 資源依賴 manifest.json 文件與頁面資源依賴 manifest.json 文件進行合併,同時構造好資源依賴。
- webpack 頁面構建完成後,自動打開瀏覽器。
- 下次 npm start 時,因為 manifest-dll.json 文件存在,所以 1 的步驟跳過,直接進行2 和 3,這時候構建速度會顯著提升。
- easywebpack-cli 提供 easy clean 清理緩存和 easy open 打開緩存目錄命令
常規配置:http://hubcarl.github.io/easywebpack/webpack/base/
3 Egg + Vue/React SSR 多進程編譯
在 Egg + Vue/React SSR 項目開發過程中, 服務端渲染需要單獨構建服務端運行的文件和客戶端運行的文件,這樣就涉及兩份 webpack 配置。 在原有的方案是在 Egg Agent 裡面進行 Webpack 構建的,此時只有 1 個進程編譯, 項目大以後構建速度太慢。 在 egg-webpack ^3.2.4, 版本我們進行支持了多進程編譯。啟動兩個進程分別編譯 前端構建和Node構建。結合 Webpack dll 功能,通過實際項目測試發現,npm start 啟動速度顯著提升,其中一個項目構建速度從 90s 減少到 30s 時間,極大提高開發效率。
該修改非必須,如果沿用之前的配置,就表示採用單進程編譯
- 如果 webpack.config.js 文件在項目根目錄,直接刪除 config/config.local.js 文件的 config.webpack 配置即可
- 如果 webpack.config.js 文件不在項目根目錄,比如在 build/webpack.config.js,那麼需要刪除原有的配置,添加如下配置:
config.webpack={ webpackConfigFile: build/webpack.config.js}
4 uglifyjs-webpack-plugin 壓縮
Webpack 3 內置的壓縮插件 uglifyjs-webpack-plugin
目前還是 0.4.6版本,不支持多進程壓縮。官方文檔計劃在 webpack 4 的時候使用 uglifyjs-webpack-plugin 1.x.x版本。uglifyjs-webpack-plugin 1.x.x版本支持多進程壓縮。easywebpack 3.5.0 版本開始不直接顯示使用 webpack 內置壓縮插件。 如果你顯示安裝了 uglifyjs-webpack-plugin 1.x.x版本,則會使用 1.x.x 版本進行壓縮。
5 commonsChunk 配置簡化
easywebpack 3.5.0 版本支持直接 webpack.config.js
文件添加 lib 節點配置即可完成 commonsChunk
公共庫的配置。
module.exports = { ... lib:[vue,vuex,axios]}
6 css extract 熱更新
easywebpack 在之前的版本支持了 css inline 和 js 的熱更新,但不支持 css extract 熱更新。 easywebpack 通過取巧的方式支持了 css extract 熱更新。easywebpack 構建通過 hotCss 即可開啟 css 熱更新。
module.exports = { ... hotCss: true}
- 在 Egg + Vue SSR 方案中,無需該配置, 因為開發期間使用的是 css inline 方式,可以滿足熱更新要求。
- 在 Egg + React SSR 方案中,無需該配置, easywebpack-react 方案已經開啟了該開關。
css extract 原理:在研究 Webpack 熱更新實現實現原理髮現,修改 extract css 時, 雖然不能實現js的模塊熱更新,但可以通過取巧的方式實現 css 熱更新。 當修改修改 extract css 時,webpack 是能夠監聽到修改的, 同時會發送信息 {"h":"540f0a679c8bcbf12848","c":{"0":true}}
給瀏覽器, 通過與js修改對比發現, 當修改修改 extract css 時, 是沒有模塊ID信息的,c節點信息始終是 {}
或 {"0":true}
,這就為css 刷新提供可能。 通過實現 webpack-hot-middleware
提供的 `subscribeAll
方法,對服務端返回的信息進行解析,如果c節點信息是 {}
或 {"0":true}
, 則遍歷頁面的link css,然後重新設置,讓頁面無感知刷新。具體代碼如下:
var hotClient = require(webpack-hot-middleware/client?noInfo=false&reload=true&quiet=false&autoConnect=false); var currentHash; hotClient.setOptionsAndConnect({ path: EASY_ENV_HOST_URL + /__webpack_hmr }); hotClient.subscribeAll(event => { if (event.action === built && currentHash) { var request = new XMLHttpRequest(); var requestPath = EASY_ENV_PUBLIC_PATH + currentHash + .hot-update.json; request.open("GET", requestPath, true); request.timeout = 5000; request.send(null); request.onreadystatechange = function() { if (request.readyState === 4) { if (request.status === 200) { try { var update = JSON.parse(request.responseText); var c = update.c; if (!c || JSON.stringify(c) === {} || JSON.stringify(c) === {"0":true}) { var links = document.getElementsByTagName(link); for (var i = 0; i < links.length; i++) { var href = links[i].href; if (href && /.css$/.test(href)) { links[i].href = href; console.log([HMR] + href + updated.); } } } } catch (e) { console.log(Get hot-update.json content error, e); } } } }; } currentHash = event.hash; });
7 內置 jsbundle 文件大小和依賴分析工具
為了方便對 webpack 編譯的js 進行大小分析, easywebacpk 內置了 webpack-bundle-analyzer
和 stats-webpack-plugin
兩個插件, 請根據需要自行開啟。
webpack-bundle-analyzer 插件自帶 UI 界面
stats-webpack-plugin 生成 stat.json 文件,然後你需要通過 http://alexkuz.github.io/webpack-chart/或 http://webpack.github.io/analyse/ 工具進行分析。在 webpack.config.js
需要顯示開啟,默認是禁用。
module.exports = { ... plugins: { analyzer:true, stats:true }}
8 webpack 原生配置支持
easywebpack的 webpack.config.js
這份配置不是 Webpack 原生的配置文件, 這是專門給 easywebpack-cli
使用的配置文件. 這份配置簡化了 Webpack 原生配置, 隱藏眾多基礎,loader, plugin 等細節, 只提供5個左右的基本配置項, 其中 loader, plugin 通過開關開啟就可以使用其功能.在構建時, easywebpack-cli
最終會這份簡化的配置轉換為 Webpack 原生配置.
考慮到用戶的使用習慣,easywebpack >=3.5.0 版本已兼容原生 Webpack 配置項,比如 entry, target, node, resolve, externals, module.noParse, module.alias, module.rules, plugins, devtool, performance等配置。
9 manifest 升級
easywebpack 3.5.0 新增自定義插件 webpack-manifest-resource-plugin(^2.0.2) 替換 webpack-manifest-plugin。 之前的 manifest 依賴關係是在 Egg 運行期間解析的,現在改為構建期組裝好資源依賴關係。新生成的 manifest 可以在純前端項目使用,比如 PWA 場景(easywebpack 計劃內置支持 PWA構建, 目前正在調研中......)。
- webpack-manifest-plugin
// ${app_root}/config/manifest.json{ "app/app.js": "/public/js/app/app.2cf6dfd1.js", "app/app.css": "/public/css/app/app.cda9bc64.css", "common.js": "/public/js/common.b59f7169.js", "common.css": "/public/css/common.cda9bc64.css"}
- webpack-manifest-resource-plugin
// ${app_root}/config/manifest.json{ "app/app.js": "/public/js/app/app.2cf6dfd1.js", "app/app.css": "/public/css/app/app.cda9bc64.css", "common.js": "/public/js/common.b59f7169.js", "common.css": "/public/css/common.cda9bc64.css", "deps": { "app/app.js": { "js": [ "/public/js/vendor.337ab787.js", "/public/js/common.b59f7169.js", "/public/js/app/app.2cf6dfd1.js" ], "css": [ "/public/css/common.cda9bc64.css", "/public/css/app/app.cda9bc64.css" ] }}
10 環境變數
為了方便使用, easywebpack 3.5.0 版本 內置了幾個可能經常使用的環境變數:
process.env.NODE_ENV
首先會獲取用戶 process.env.NODE_ENV 值, 如果獲取不到,當構建 prod 模式時設置為 production, 否則為 development。 該設置不會影響原有的 process.env.NODE_ENV 系統環境參數。
EASY_ENV_IS_DEV
是否是開發模式(dev)構建
EASY_ENV_IS_TEST
是否是測試環境模式(test)構建
EASY_ENV_IS_PROD
是否是正式環境模式(prod)構建
EASY_ENV_IS_BROWSER
是否是瀏覽器運行構建模式
EASY_ENV_IS_NODE
否是Node運行構建模式, 也就是 server side render
http://hubcarl.github.io/easywebpack/webpack/env/
11 使用文檔
隨著 easywebpack 3.5.0 版本的發布, easywebpack 文檔進行了重新整理和完善,歡迎查閱:http://hubcarl.github.io/easywebpack
12 相關文檔
純前端項目構建:http://hubcarl.github.io/easywebpack/webpack/base/
Egg + Vue 3.5.0 升級指南:http://hubcarl.github.io/easywebpack/vue/version/Egg + React 3.5.0 升級指南:http://hubcarl.github.io/easywebpack/react/version/推薦閱讀:
※iView 發布 1.0 正式版,43 個 UI 組件助力中後台業務開發
※阿里雲前端工程化方案dawn
※requirejs/seajs和webpack/browserify各自的優勢以及如何取捨?
※web front end Automation Tools
※webpack增量打包