目录
天下武功,唯快不破
新特性
快上车,升级前的准备
升级避坑指南
持续加速
编译结果分析
面向tree-shaking,约束编码
结尾
对于现在的前端项目而言,编译发布几乎是必需操作,有的编译只需要几秒钟,快如闪电,有的却需要10分钟,甚至更多,慢如蜗牛。特别是线上热修复时,分秒必争,响应速度直接影响了用户体验,用户不会有耐心等那么长时间,让你慢慢编译;如果涉及到支付操作,产品损失更是以秒计,每提前哪怕一秒钟发布,在腾讯海量用户面前,都能挽回不小的损失。不仅如此,编译效率的提升,带来的最直观收益就是,开发效率与开发体验双重提升。那么,到底是什么拖慢了webpack打包效率,我们又能做哪些提升呢?
webpack 是目前非常受欢迎的打包工具,截止6天前,webpack4 已更新至 4.28.3
版本,10 个月的时间,小版本更新达几十次之多,可见社区之繁荣。
webpack4 发布时,官方也曾表示,其编译速度提升了 60% ~ 98%。
天下武功,唯快不破
由于本地项目升级到 webpack4 有几个月了,为了获得测试数据,手动将 webpack 降级为 3.12.0 版本,其它配置基本不做改动。
测试时,Mac仅运行常用的IM、邮箱、终端、浏览器等,为了尽可能避免插件对数据的影响,我关闭了一些优化插件,只保留常用的loader、js压缩插件。
以下是分别在 webpack@3.12.0 及 webpack@4.26.1 两种场景下各测 5 次的运行截图。
数据分析如下(单位ms):
纯粹的版本升级,编译速度提升为 45%
,这里我选取的是成熟的线上运行项目,构建速度的提升只有建立在成熟项目上才有意义,demo 项目由于编译文件基数小,难以体现出构建环境的复杂性,测试时也可能存在较大误差。同时与官方数据的差距,主要是因为基于的项目及配置不同。
无论如何,近 50% 的编译速度提升,都值得你尝试升级 webpack4!当然,优化才刚刚开始,请继续往下读。
新特性
为了更流畅的升级 webpack4,我们先要了解它。
webpack4 在大幅度提升编译效率同时,引入了多种新特性:
受 Parcel 启发,支持 0 配置启动项目,不再强制需要 webpack.config.js 配置文件,默认入口
./src/
目录,默认entry./src/index.js
,默认输出./dist
目录,默认输出文件./dist/main.js
。开箱即用 WebAssembly,webpack4提供了wasm的支持,现在可以引入和导出任何一个 Webassembly 的模块,也可以写一个loader来引入C++、C和Rust。(注:WebAssembly 模块只能在异步chunks中使
提供mode属性,设置为
development
将获得最好的开发体验,设置为production
将专注项目编译部署,比如说开启 Scope hoisting 和 Tree-shaking 功能。全新的插件系统,提供了针对插件和钩子的新API,变化如下:
更多插件的工作原理,可以参考:新插件系统如何工作。
所有的 hook 由 hooks 对象统一管理,它将所有的hook作为可扩展的类属性
添加插件时,你需要提供一个名字
开发插件时,你可以选择插件的类型(sync/callback/promise之一)
通过 this.hooks = { myHook: new SyncHook(…) } 来注册hook
快上车,升级前的准备
首先,webpack-dev-server 插件需要升级至最新,同时,由于webpack-cli 承担了webpack4 命令行相关的功能,因此 webpack-cli 也是必需的。
与以往不同的是,mode属性必须指定,否则按照 约定优于配置
原则,将默认按照 production
生产环境编译,如下是警告原文。
WARNING in configuration
The ‘mode’ option has not been set, webpack will fallback to ‘production’ for this value. Set ‘mode’ option to ‘development’ or ‘production’ to enable defaults for each environment.
You can also set it to ‘none’ to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/
有两种方式可以加入mode配置。
在package.json script中指定–mode:
"scripts": {
"dev": "webpack-dev-server --mode development --inline --progress --config build/webpack.dev.config.js",
"build": "webpack --mode production --progress --config build/webpack.prod.config.js"
}
在配置文件中加入mode属性
module.exports = {
mode: 'production' // 或 development
};
升级至webpack4后,一些默认插件由 optimization 配置替代了,如下:
CommonsChunkPlugin废弃,由 optimization.splitChunks 和 optimization.runtimeChunk 替代,前者拆分代码,后者提取runtime代码。原来的CommonsChunkPlugin产出模块时,会包含重复的代码,并且无法优化异步模块,minchunks的配置也较复杂,splitChunks解决了这个问题;另外,将 optimization.runtimeChunk 设置为true(或{name: “manifest”}),便能将入口模块中的runtime部分提取出来。
NoEmitOnErrorsPlugin 废弃,由 optimization.noEmitOnErrors 替代,生产环境默认开启。
NamedModulesPlugin 废弃,由 optimization.namedModules 替代,生产环境默认开启。
ModuleConcatenationPlugin 废弃,由 optimization.concatenateModules 替代,生产环境默认开启。
optimize.UglifyJsPlugin 废弃,由 optimization.minimize 替代,生产环境默认开启。
不仅如此,optimization 还提供了如下默认配置:
optimization: {
minimize: env === 'production' ? true : false, // 开发环境不压缩
splitChunks: {
chunks: "async", // 共有三个值可选:initial(初始模块)、async(按需加载模块)和all(全部模块)