前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >为什么 webpack4 默认支持 ES6 语法的压缩?

为什么 webpack4 默认支持 ES6 语法的压缩?

作者头像
腾讯IVWEB团队
发布2020-06-28 10:43:44
1.2K0
发布2020-06-28 10:43:44
举报

在专栏课程里,有位同学提到过一个很有意思的问题:“我没装 babel,js 入口里写了个箭头函数,运行 webpack 构建命令后,也成功编译了。这是为什么?”。今天就带领大家一起去探讨下这个话题。

在使用 webpack 的时候,很常见的一个构建优化手段就是缩小构建目标。比如在构建阶段只构建 src 里面的模块代码,对于 node_modules 里面所引入的三方包不进行构建操作。

发现问题

如果使用的是 webpack 3.x 版本,编写的构建脚本类似这样的,我们通过设置loader 里面的 exclude 字段避免由于解析 node_modules 里面的模块造成的构建耗时:

代码语言:javascript
复制
const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'happypack/loader',
                exclude: path.join(__dirname, 'node_modules')
            }
        ]
    }
    plugins: [
        new webpack.optimize.UglifyJsPlugin()
    ]
};

我们经常会遇到一个问题,假设引入的 npm 包质量不够高,比如 node_modules 里面有 ES6 的语法,那么 webpack 在 uglify 阶段会报错!下面给出两种常见的出错场景:

ES6 的模板字符串

假设 node_modules 里面存在 ES6 的模板字符串语法,那么在生产环境打包的代码压缩阶段,UglifyJs 会抛出错误。

图片

ES6 的箭头函数

同样的,你使用 ES6 的箭头函数也是无法正常的压缩代码的。

图片

细心的你一定会发现如果使用的是 webpack 4,这个场景描述的问题将不再出现。webpack 4默认支持 ES6 代码的压缩,这个是什么原因呢?

初步分析

如果你有对 webpack 4 的依赖包进行过相关分析,比如直接查阅 package.json 文件或者通过 http://npm.broofa.com/ 网站上进行 webpack 依赖图分析。不难发现 webpack 4 里面使用了 terser-webpack-plugin 插件替代了之前一直使用的 uglifyjs-webpack-plugin 作为它的内置插件。

以 4.39.3 这个版本为例,可以看到它的 package.json 文件的依赖包括了terser-webpack-plugin。

图片

我们进一步分析发现 webpack 的 4.26.0 这个版本有一次提交,它的提交内容是对 webpack 内置插件进行了一次切换。

图片

经过这么一次分析,我们可以知道 webpack 4 之所以具备默认压缩 ES6 代码的能力,离不开 terser-webpack-plugin 所起的作用!

进一步分析

在探究 terser-webpack-plugin 插件的原理前,我们先系统的回顾一下代码压缩插件的历史:

  • 当 uglifyjs-webpack-plugin 版本小于 v1.0 时,它使用的是 uglify-js 依赖
  • 但是 uglify-js 并不支持 ES6, 因此在 uglify-js 仓库的 harmony 分支 Fork 了一个 uglify-es
  • uglifyjs-webpack-plugin 的 v1.x 为了支持 ES6 的压缩语法,将 uglify-js 依赖切换到了 uglify-es
  • 但是 uglify-es 停止维护了: mishoo/UglifyJS2#3156 (comment)
  • uglify-es 的停止维护导致了 terser 被 fork 出来了,并且 terser 处理了没有合入的 PRs,最终创建了一个独立的仓库: https://github.com/fabiosantoscode/terser
  • 随后,terser-webpack-plugin 被创建出来, 它基于 terser,并且具备uglifyjs-webpack-plugin 的同等功能 : https://github.com/webpack-contrib/terser-webpack-plugin
  • 由于 uglifyjs-webpack-plugin v2.x 回退到了 uglify-js, 不再支持 ES6。 因此那些希望支持 ES6 语法压缩的项目必须切换到 terser-webpack-plugin

备注:压缩插件历史的来源 https://github.com/webpack/webpack/commit/311a7285d36b38bada46102967c431e93ff48a89

到这里,我们可以得出一个基本的结论:terser-webpack-plugin 基于 terser 因此它具备 ES6 的压缩能力,uglifyjs-webpack-plugin v2.x 版本基于 uglify-js,无法支持 ES6 的压缩。

插件

依赖

是否支持 ES6(Y/N)

terser-webpack-plugin

terser

Y

uglifyjs-webpack-plugin v1.x

uglify-es

Y

uglifyjs-webpack-plugin v2.x

uglify-js

N

原理探究

代码压缩原理其实挺简单的,也是 AST 的一个经典的应用案例。它的压缩过程通常是:

代码语言:javascript
复制
     JS 源代码 -> AST -> 美化、压缩 -> 新的 AST -> 压缩后的代码 

了解了代码压缩的基本流程后,接下来我们看看源码包含了哪些内容,由于 terser 是从 uglify-es Fork 出来进行修改的,因此它的代码结构和 uglify-js 基本一致,只不过 terser 使用了 ES6 模块的静态分析功能。我们以 terser 的源码为例分析下:

  • ast.js:JS 的抽象语法树的描述信息
  • parse.js:Parser,用于从 JS 源代码分析出 AST
  • minify.js:用于将 AST 优化成更简短的结构
  • output.js:代码生成器,从 AST 输出 压缩后的代码,支持 sourcemap 的生成
  • propmangle.js:对变量的长度进行压缩,通常是单个字符
  • scope.js:分析变量定义/引用位置的信息
  • transform.js:节点遍历

然后,我们来一探 terser 和 uglify-js 的差异。对比了之后,发现一个很大的差异是 AST 的支持上面不同。

分析AST的差异发现,下面是两个文件 diff 对比只在 terser 中才有,而这些刚好对应 ES6 的语法。

代码语言:javascript
复制
AST_Arrow,
AST_Await,
AST_BigInt,
AST_Class,
AST_ClassExpression,
AST_ConciseMethod,
AST_Const,
AST_DefaultAssign,
AST_Destructuring,
AST_Expansion,
AST_Export,
AST_ForOf,
AST_Import,
AST_Let,
AST_NameMapping,
AST_NewTarget,
AST_PrefixedTemplateString,
AST_Super,
AST_SymbolMethod,
AST_TemplateSegment,
AST_TemplateString,
AST_Yield
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 发现问题
    • ES6 的模板字符串
      • ES6 的箭头函数
      • 初步分析
      • 进一步分析
      • 原理探究
      相关产品与服务
      文件存储
      文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档