专栏首页前端自习课【Webpack】654- 了不起的 Webpack Scope Hoisting 学习指南

【Webpack】654- 了不起的 Webpack Scope Hoisting 学习指南

一、什么是 Scope Hoisting

Scope Hoisting 是 webpack3 的新功能,直译为 "「作用域提升」",它可以让 webpack 打包出来的「代码文件更小」「运行更快」

在 JavaScript 中,还有“变量提升”和“函数提升”,JavaScript 会将变量和函数的声明提升到当前作用域顶部,而“作用域提升”也类似,webpack 将引入到 JS 文件“提升到”它的引入者的顶部。

首先回顾下在没有 Scope Hoisting 时用 webpack 打包下面两个文件:

// main.js
export default "hello leo~";

// index.js
import str from "./main.js";

使用 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 leo~');
  })
]

再开启 Scope Hoisting 后,相同源码打包输出结果变为:

[
  (function (module, __webpack_exports__, __webpack_require__) {
    var util = ('hello leo~');
    console.log(util);
  })
]

对比两种打包方式输出的代码,我们可以看出,启用 Scope Hoisting 后,函数声明变成一个, main.js 中定义的内容被直接注入到 main.js 对应模块中,这样做的好处:

  • 「代码体积更小」,因为函数申明语句会产生大量代码,导致包体积增大(模块越多越明显);
  • 代码在运行时因为创建的函数作用域更少,「内存开销也随之变小」

二、webpack 模块机制

我们使用下面 webpack.config.js 配置,打包来看看 webpack 模块机制:

// 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 是一个数组,每一项是一个模块初始化函数;
  • 使用 __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。

// webpack.config.js

// ...
module.exports = {
    // ...
 mode: "production"
};

2. 手动启用

在 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,它对我们项目优化非常有帮助,但平常又很少会去注意。

六、参考文章

  • 《通过Scope Hoisting优化Webpack输出》
  • 《webpack 的 scope hoisting 是什么?》

本文分享自微信公众号 - 前端自习课(FE-study),作者:王平安

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 了不起的 Webpack Scope Hoisting 学习指南

    Scope Hoisting 是 webpack3 的新功能,直译为 "作用域提升",它可以让 webpack 打包出来的代码文件更小,运行更快。

    pingan8787
  • 通过Scope Hoisting优化Webpack输出

    Scope Hoisting 可以让 Webpack 打包出来的代码文件更小、运行的更快, 它又译作 "作用域提升",是在 Webpack3 中新推出的功能。 ...

    IMWeb前端团队
  • 你可能不知道的9条Webpack优化策略

    本文以我自己的经验向大家分享如何通过一些分析工具、插件以及webpack新版本中的一些新特性来显著提升webpack的打包速度和改善包体积,学会分析打包的瓶颈以...

    前端森林
  • webpack3新特性简介

    6月20号webpack推出了3.0版本,官方也发布了公告。根据公告介绍,webpack团队将未来版本的改动聚焦在社区提出的功能需求,同时将保持一个快速、稳定的...

    用户1217459
  • Webpack 打包优化之体积篇

    谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发展也是如火如荼,百家争鸣;从早期的王者Brow...

    晚晴幽草轩轩主
  • 2020前端性能优化清单(三)

    最好先了解你要处理的内容。盘点出所有资源的清单( JavaScript 、图片、字体、第三方脚本和页面上开销较大的模块,例如轮播、复杂的信息图和多媒体内容),然...

    WecTeam
  • 2020前端性能优化清单(三)

    最好先了解你要处理的内容。盘点出所有资源的清单( JavaScript 、图片、字体、第三方脚本和页面上开销较大的模块,例如轮播、复杂的信息图和多媒体内容),然...

    桃翁
  • 【Webpack】627- 了不起的 Webpack HMR 学习指南(含源码分析)

    Hot Module Replacement(以下简称:HMR 模块热替换)是 Webpack 提供的一个非常有用的功能,它允许在 JavaScript 运行时...

    pingan8787
  • 前端性能优化篇一:webpack性能优化

    当我们不用cli,而是自己搭建项目架子的时候,会用到webpack构建我们的项目,在用webpack构建项目的时候,过长的打包编译时间和庞大冗余的代码会让我们...

    用户6835371
  • webpack 学习笔记系列04-资源处理优化

    TypeScript 约定了 tsconfig.json 文件来存储项目配置,文档链接。

    CS逍遥剑仙
  • 性能优化篇---Webpack构建代码质量压缩

    keyWords
  • 读书笔记——《深入浅出 Webpack》( 送 XMind导图和电子书)

    前阵子刚好遇到几个关于 webpack 方面的需求,特意找了一下这方面的书籍,阅读了一下,收益还是有一点,特此笔记记录一下。

    GopalFeng
  • 「吐血整理」再来一打Webpack面试题

    从头发的浓密程度和干练的走路姿势我察觉到,面前坐着的这位面试官也是一把好手。我像以往一样,准备花3分钟的时间进行自我介绍。在此期间,我的目光被16寸的MacBo...

    童欧巴
  • Rollup

    念念不忘
  • 了不起的 Webpack HMR 学习指南(含源码分析)

    学习时间:2020.06.14 学习章节:《Webpack HMR 原理解析》 [了不起的 Webpack HMR 学习指南.png]

    pingan8787
  • 升级你的webpack(上)-- webpack入门教程(二)

    我负责的一个前端项目之前用到的是webpack1,现需要升级到webpack4,特此记录下升级过程中有一些配置和需要注意的问题,具体会介绍:

    前端林子
  • webpack4:连奏中的进化

    用户1217459
  • visual studio code运行时报错,Cannot find module 'webpack'

    今天运行是visual studio code时,报了一个错误Cannot find module 'webpack' ,网上找了很多方法都没解决。下面一起来...

    Dawnzhang
  • 【Webpack】632- 了不起的 Webpack 构建流程学习

    Webpack 是前端很火的打包工具,它本质上是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 Webpack 处...

    pingan8787

扫码关注云+社区

领取腾讯云代金券