近期原创文章回顾😄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 |