通過Scope Hoisting優化Webpack輸出
Scope Hoisting 可以讓 Webpack 打包出來的代碼文件更小、運行的更快,
它又譯作 "作用域提升",是在 Webpack3 中新推出的功能。單從名字上看不出 Scope Hoisting 到底做了什麼,下面來詳細介紹它。認識 Scope Hoisting
讓我們先來看看在沒有 Scope Hoisting 之前 Webpack 的打包方式。
假如現在有兩個文件分別是 util.js
:
export default Hello,Webpack;n
和入口文件 main.js
:
import str from ./util.js;nconsole.log(str);n
以上源碼用 Webpack 打包後輸出中的部分代碼如下:
[n (function (module, __webpack_exports__, __webpack_require__) {n var __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(1);n console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);n }),n (function (module, __webpack_exports__, __webpack_require__) {n __webpack_exports__["a"] = (Hello,Webpack);n })n]n
在開啟 Scope Hoisting 後,同樣的源碼輸出的部分代碼如下:
[n (function (module, __webpack_exports__, __webpack_require__) {n var util = (Hello,Webpack);n console.log(util);n })n]n
從中可以看出開啟 Scope Hoisting 後,函數申明由兩個變成了一個,util.js
中定義的內容被直接注入到了 main.js
對應的模塊中。
- 代碼體積更小,因為函數申明語句會產生大量代碼;
- 代碼在運行時因為創建的函數作用域更少了,內存開銷也隨之變小。
Scope Hoisting 的實現原理其實很簡單:分析出模塊之間的依賴關係,儘可能的把打散的模塊合併到一個函數中去,但前提是不能造成代碼冗餘。
因此只有那些被引用了一次的模塊才能被合併。由於 Scope Hoisting 需要分析出模塊之間的依賴關係,因此源碼必須採用 ES6 模塊化語句,不然它將無法生效。
原因和4-10 使用 TreeShaking 中介紹的類似。使用 Scope Hoisting
要在 Webpack 中使用 Scope Hoisting 非常簡單,因為這是 Webpack 內置的功能,只需要配置一個插件,相關代碼如下:
const ModuleConcatenationPlugin = require(webpack/lib/optimize/ModuleConcatenationPlugin);nnmodule.exports = {n plugins: [n // 開啟 Scope Hoistingn new ModuleConcatenationPlugin(),n ],n};n
同時,考慮到 Scope Hoisting 依賴源碼需採用 ES6 模塊化語法,還需要配置 mainFields
。
Scope Hoisting 的作用,需要增加以下配置:
module.exports = {n resolve: {n // 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件n mainFields: [jsnext:main, browser, main]n },n};n
對於採用了非 ES6 模塊化語法的代碼,Webpack 會降級處理不使用 Scope Hoisting 優化,為了知道 Webpack 對哪些代碼做了降級處理,
你可以在啟動 Webpack 時帶上--display-optimization-bailout
參數,這樣在輸出日誌中就會包含類似如下的日誌:[0] ./main.js + 1 modules 80 bytes {0} [built]n ModuleConcatenation bailout: Module is not an ECMAScript modulen
其中的 ModuleConcatenation bailout
告訴了你哪個文件因為什麼原因導致了降級處理。
也就是說要開啟 Scope Hoisting 並發揮最大作用的配置如下:
const ModuleConcatenationPlugin = require(webpack/lib/optimize/ModuleConcatenationPlugin);nnmodule.exports = {n resolve: {n // 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件n mainFields: [jsnext:main, browser, main]n },n plugins: [n // 開啟 Scope Hoistingn new ModuleConcatenationPlugin(),n ],n};n
本實例提供項目完整代碼
《深入淺出Webpack》全書在線閱讀鏈接
閱讀原文
推薦閱讀:
※基於 Webpack 3 的 Vue.js 工程項目腳手架
※Webpack 3 的新功能:Scope Hoisting
TAG:webpack |