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 + VueEgg + React SSR 項目時,本地開發時,我們通過 npm start 一步完成 webpack 編譯 和 egg 項目啟動,簡化了先手動編譯 webpack,然後啟動egg的流程。Egg 項目是如何解決上面 dll 的問題呢?

  1. npm start 首次啟動時,檢查 webpack.config.js 是否配置了 dll 節點信息, 如果配置了,同時 manifest-dll.json 文件不存在,則構建 dll.js 文件,同時生成 manifest-dll.json 文件 和 dll 的 資源依賴 manifest.json 文件。
  2. dll 構建完成後,自動啟動 webpack 頁面構建,同時把 dll 資源依賴 manifest.json 文件與頁面資源依賴 manifest.json 文件進行合併,同時構造好資源依賴。
  3. webpack 頁面構建完成後,自動打開瀏覽器。
  4. 下次 npm start 時,因為 manifest-dll.json 文件存在,所以 1 的步驟跳過,直接進行2 和 3,這時候構建速度會顯著提升。
  5. easywebpack-cli 提供 easy clean 清理緩存和 easy open 打開緩存目錄命令

常規配置:hubcarl.github.io/easyw

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-analyzerstats-webpack-plugin 兩個插件, 請根據需要自行開啟。

webpack-bundle-analyzer 插件自帶 UI 界面

stats-webpack-plugin 生成 stat.json 文件,然後你需要通過 alexkuz.github.io/webpawebpack.github.io/analy 工具進行分析。

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

hubcarl.github.io/easyw

11 使用文檔

隨著 easywebpack 3.5.0 版本的發布, easywebpack 文檔進行了重新整理和完善,歡迎查閱:hubcarl.github.io/easyw

12 相關文檔

純前端項目構建:hubcarl.github.io/easyw

Egg + Vue 3.5.0 升級指南:hubcarl.github.io/easyw

Egg + React 3.5.0 升級指南:hubcarl.github.io/easyw


推薦閱讀:

iView 發布 1.0 正式版,43 個 UI 組件助力中後台業務開發
阿里雲前端工程化方案dawn
requirejs/seajs和webpack/browserify各自的優勢以及如何取捨?
web front end Automation Tools
webpack增量打包

TAG:webpack | 前端工程化 | eggjs |