Scope Hoisting 可讓 Webpack 打包出來的代碼文件更小、運行的更快, 它又譯做 "做用域提高",是在 Webpack3 中新推出的功能。 單從名字上看不出 Scope Hoisting 到底作了什麼,下面來詳細介紹它。html
讓咱們先來看看在沒有 Scope Hoisting 以前 Webpack 的打包方式。webpack
假如如今有兩個文件分別是 util.js
:web
export default 'Hello,Webpack';
複製代碼
和入口文件 main.js
:bash
import str from './util.js';
console.log(str);
複製代碼
以上源碼用 Webpack 打包後輸出中的部分代碼以下:併發
[
(function (module, __webpack_exports__, __webpack_require__) {
var __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(1);
console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);
}),
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["a"] = ('Hello,Webpack');
})
]
複製代碼
在開啓 Scope Hoisting 後,一樣的源碼輸出的部分代碼以下:模塊化
[
(function (module, __webpack_exports__, __webpack_require__) {
var util = ('Hello,Webpack');
console.log(util);
})
]
複製代碼
從中能夠看出開啓 Scope Hoisting 後,函數申明由兩個變成了一個,util.js
中定義的內容被直接注入到了 main.js
對應的模塊中。 這樣作的好處是:函數
Scope Hoisting 的實現原理其實很簡單:分析出模塊之間的依賴關係,儘量的把打散的模塊合併到一個函數中去,但前提是不能形成代碼冗餘。 所以只有那些被引用了一次的模塊才能被合併。優化
因爲 Scope Hoisting 須要分析出模塊之間的依賴關係,所以源碼必須採用 ES6 模塊化語句,否則它將沒法生效。 緣由和4-10 使用 TreeShaking 中介紹的相似。ui
要在 Webpack 中使用 Scope Hoisting 很是簡單,由於這是 Webpack 內置的功能,只須要配置一個插件,相關代碼以下:spa
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
plugins: [
// 開啓 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
複製代碼
同時,考慮到 Scope Hoisting 依賴源碼需採用 ES6 模塊化語法,還須要配置 mainFields
。 緣由在 4-10 使用 TreeShaking 中提到過:由於大部分 Npm 中的第三方庫採用了 CommonJS 語法,但部分庫會同時提供 ES6 模塊化的代碼,爲了充分發揮 Scope Hoisting 的做用,須要增長如下配置:
module.exports = {
resolve: {
// 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
};
複製代碼
對於採用了非 ES6 模塊化語法的代碼,Webpack 會降級處理不使用 Scope Hoisting 優化,爲了知道 Webpack 對哪些代碼作了降級處理, 你能夠在啓動 Webpack 時帶上 --display-optimization-bailout
參數,這樣在輸出日誌中就會包含相似以下的日誌:
[0] ./main.js + 1 modules 80 bytes {0} [built]
ModuleConcatenation bailout: Module is not an ECMAScript module
複製代碼
其中的 ModuleConcatenation bailout
告訴了你哪一個文件由於什麼緣由致使了降級處理。
也就是說要開啓 Scope Hoisting 併發揮最大做用的配置以下:
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 針對 Npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 開啓 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
複製代碼
本實例提供項目完整代碼