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(),
],
};
复制代码
本实例提供项目完整代码