近期原創文章回顧😄html
Scope Hoisting 是 webpack3 的新功能,直譯爲 "「做用域提高」",它可讓 webpack 打包出來的「代碼文件更小」,「運行更快」。前端
在 JavaScript 中,還有「變量提高」和「函數提高」,JavaScript 會將變量和函數的聲明提高到當前做用域頂部,而「做用域提高」也相似,webpack 將引入到 JS 文件「提高到」它的引入者的頂部。webpack
首先回顧下在沒有 Scope Hoisting 時用 webpack 打包下面兩個文件:git
// main.js
export default "hello leo~";
// index.js
import str from "./main.js";
console.log(str);
複製代碼
使用 webpack 打包後輸出文件內容以下:es6
[
(function (module, __webpack_exports__, __webpack_require__) {
var __WEBPACK_IMPORTED_MODULE_0__main_js__ = __webpack_require__(1);
console.log(__WEBPACK_IMPORTED_MODULE_0__main_js__["a"]);
}),
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["a"] = ('hello leo~');
})
]
複製代碼
再開啓 Scope Hoisting 後,相同源碼打包輸出結果變爲:github
[
(function (module, __webpack_exports__, __webpack_require__) {
var main = ('hello leo~');
console.log(main);
})
]
複製代碼
對比兩種打包方式輸出的代碼,咱們能夠看出,啓用 Scope Hoisting 後,函數聲明變成一個, main.js
中定義的內容被直接注入到 main.js
對應模塊中,這樣作的好處:web
咱們使用下面 webpack.config.js
配置,打包來看看 webpack 模塊機制:npm
// webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'none',
optimization: {
usedExports: true,
},
};
複製代碼
打包後輸出結果(精簡後): 經過分析,咱們能夠得出如下結論:json
modules
是一個數組,每一項是一個模塊初始化函數;
__webpack_require()
來家在模塊,返回
module.exports
;
__webpack_require__(__webpack_require__.s = 0);
啓動程序。
Scope Hoisting 的實現原理其實很簡單:分析出模塊之間的依賴關係,儘量將打散的模塊合併到一個函數中,前提是不能形成代碼冗餘。 所以「只有那些被引用了一次的模塊才能被合併」。segmentfault
因爲 Scope Hoisting 須要分析出模塊之間的依賴關係,所以源碼「必須採用 ES6 模塊化語句」,否則它將沒法生效。 緣由和4-10 使用 TreeShaking 中介紹的相似。
在 webpack 的 mode
設置爲 production
時,會默認自動啓用 Scope Hooting。
// webpack.config.js
// ...
module.exports = {
// ...
mode: "production"
};
複製代碼
在 webpack 中已經內置 Scope Hoisting ,因此用起來很簡單,只須要配置ModuleConcatenationPlugin 插件便可:
// webpack.config.js
// ...
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
};
複製代碼
考慮到 Scope Hoisting 以來 ES6 模塊化語法,而如今不少 npm 包的第三方庫仍是使用 CommonJS 語法,爲了充分發揮 Scope Hoisting 效果,咱們能夠增長如下 mainFields
配置:
// webpack.config.js
// ...
const webpack = require('webpack');
module.exports = {
// ...
resolve: {
// 針對 npm 中的第三方模塊優先採用 jsnext:main 中指向的 ES6 模塊化語法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
new webpack.optimize.ModuleConcatenationPlugin()
]
};
複製代碼
針對非 ES6 模塊化語法的代碼,webpack 會降級處理不使用 Scope Hoisting 優化,咱們能夠在 webpack 命令上增長 --display-optimization-bailout
參數,在輸出的日誌查看哪些代碼作了降級處理:
// package.json
{
// ...
"scripts": {
"build": "webpack --display-optimization-bailout"
}
}
複製代碼
咱們寫個簡單示例代碼:
// index.js
import str from "./main.js";
const { name } = require('./no-es6.js');
// main.js
export default "hello leo~";
// no-es6.js
module.exports = {
name : "leo"
}
複製代碼
接着打包測試,能夠看到控制檯輸出下面日誌:
輸出的日誌中 ModuleConcatenation bailout
告訴咱們哪些文件由於什麼緣由致使降級處理了。
本文主要和你們一塊兒回顧了 Scope Hoisting 基本概念,使用方式和使用後效果對比,但願你們不要只停留在會用 webpack,也要看看其中一些不常見的知識,好比本文介紹的 Scope Hoisting,它對咱們項目優化很是有幫助,但日常又不多會去注意。
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787/Leo_Reading/issues |
ES小冊 | js.pingan8787.com |
語雀知識庫 | Cute-FrontEnd |