We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
近期原创文章回顾😄
Scope Hoisting 是 webpack3 的新功能,直译为 "作用域提升",它可以让 webpack 打包出来的代码文件更小,运行更快。
在 JavaScript 中,还有“变量提升”和“函数提升”,JavaScript 会将变量和函数的声明提升到当前作用域顶部,而“作用域提升”也类似,webpack 将引入到 JS 文件“提升到”它的引入者的顶部。
首先回顾下没有 Scope Hoisting 时用 webpack 打包下面两个文件:
// main.js export default "hello leo~"; // index.js import str from "./main.js"; console.log(str);
使用 webpack 打包后输出文件内容如下:
[ (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 后,相同源码打包输出结果变为:
[ (function (module, __webpack_exports__, __webpack_require__) { var main = ('hello leo~'); console.log(main); }) ]
对比两种打包方式输出的代码,我们可以看出,启用 Scope Hoisting 后,函数声明变成一个, main.js 中定义的内容被直接注入到 index.js 对应模块中,这样做的好处:
main.js
index.js
我们使用下面 webpack.config.js 配置,打包来看看 webpack 模块机制:
webpack.config.js
// 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, }, };
打包后输出结果(精简后):
通过分析,我们可以得出以下结论:
webpack 打包输出打是一个 IIFE(匿名闭包);
modules 是一个数组,每一项是一个模块初始化函数;
modules
使用 __webpack_require() 来加载模块,返回 module.exports ;
__webpack_require()
module.exports
通过 __webpack_require__(__webpack_require__.s = 0); 启动程序。
__webpack_require__(__webpack_require__.s = 0);
Scope Hoisting 的实现原理其实很简单:分析出模块之间的依赖关系,尽可能将打散的模块合并到一个函数中,前提是不能造成代码冗余。 因此只有那些被引用了一次的模块才能被合并。
由于 Scope Hoisting 需要分析出模块之间的依赖关系,因此源码必须采用 ES6 模块化语句,不然它将无法生效。 原因和4-10 使用 TreeShaking 中介绍的类似。
在 webpack 的 mode 设置为 production 时,会默认自动启用 Scope Hooting。
mode
production
// 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 配置:
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 参数,在输出的日志查看哪些代码做了降级处理:
--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 告诉我们哪些文件因为什么原因导致降级处理了。
ModuleConcatenation bailout
本文主要和大家一起回顾了 Scope Hoisting 基本概念,使用方式和使用后效果对比,希望大家不要只停留在会用 webpack,也要看看其中一些不常见的知识,比如本文介绍的 Scope Hoisting,它对我们项目优化非常有帮助,但平常又很少会去注意。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
近期原创文章回顾😄
一、什么是 Scope Hoisting
Scope Hoisting 是 webpack3 的新功能,直译为 "作用域提升",它可以让 webpack 打包出来的代码文件更小,运行更快。
在 JavaScript 中,还有“变量提升”和“函数提升”,JavaScript 会将变量和函数的声明提升到当前作用域顶部,而“作用域提升”也类似,webpack 将引入到 JS 文件“提升到”它的引入者的顶部。
首先回顾下没有 Scope Hoisting 时用 webpack 打包下面两个文件:
使用 webpack 打包后输出文件内容如下:
再开启 Scope Hoisting 后,相同源码打包输出结果变为:
对比两种打包方式输出的代码,我们可以看出,启用 Scope Hoisting 后,函数声明变成一个,
main.js
中定义的内容被直接注入到index.js
对应模块中,这样做的好处:二、webpack 模块机制
我们使用下面
webpack.config.js
配置,打包来看看 webpack 模块机制:打包后输出结果(精简后):
通过分析,我们可以得出以下结论:
webpack 打包输出打是一个 IIFE(匿名闭包);
modules
是一个数组,每一项是一个模块初始化函数;使用
__webpack_require()
来加载模块,返回module.exports
;通过
__webpack_require__(__webpack_require__.s = 0);
启动程序。三、Scope Hoisting 原理
Scope Hoisting 的实现原理其实很简单:分析出模块之间的依赖关系,尽可能将打散的模块合并到一个函数中,前提是不能造成代码冗余。 因此只有那些被引用了一次的模块才能被合并。
由于 Scope Hoisting 需要分析出模块之间的依赖关系,因此源码必须采用 ES6 模块化语句,不然它将无法生效。 原因和4-10 使用 TreeShaking 中介绍的类似。
四、Scope Hoisting 使用方式
1. 自动启用
在 webpack 的
mode
设置为production
时,会默认自动启用 Scope Hooting。2. 手动启用
在 webpack 中已经内置 Scope Hoisting ,所以用起来很简单,只需要配置ModuleConcatenationPlugin 插件即可:
考虑到 Scope Hoisting 以来 ES6 模块化语法,而现在很多 npm 包的第三方库还是使用 CommonJS 语法,为了充分发挥 Scope Hoisting 效果,我们可以增加以下
mainFields
配置:针对非 ES6 模块化语法的代码,webpack 会降级处理不使用 Scope Hoisting 优化,我们可以在 webpack 命令上增加
--display-optimization-bailout
参数,在输出的日志查看哪些代码做了降级处理:我们写个简单示例代码:
接着打包测试,可以看到控制台输出下面日志:
输出的日志中
ModuleConcatenation bailout
告诉我们哪些文件因为什么原因导致降级处理了。五、总结
本文主要和大家一起回顾了 Scope Hoisting 基本概念,使用方式和使用后效果对比,希望大家不要只停留在会用 webpack,也要看看其中一些不常见的知识,比如本文介绍的 Scope Hoisting,它对我们项目优化非常有帮助,但平常又很少会去注意。
六、参考文章
The text was updated successfully, but these errors were encountered: