webpack5升级指南

892 阅读3分钟

webpack5介绍

webpack5自2020年10月10日发布至今已有5个多月了,最新版本已经到了 v5.24.4,一起来看下webpack5做了哪些工作:

  • 加入持久化缓存来提高构建性能

    在webpack4中我们也可以利用hard-source-webpack-plugin做到这一点,但是现在官方支持了,构建速度有了大幅提升。

  • 更好的Tree Shaking和代码生成以改善包大小

  • 其它一些突破性的变化,比如在es module、微前端、webAssemble方面的准备

升级指南

在升级之前我们可以先阅读以下官方指南来帮助我们快速处理升级可能会遇到的问题:

环境

npm install webpack@latest webpack-cli@latest html-webpack-plugin@latest webpack-dev-server@latest -S

配置变更

webpack5 做了大量的配置变更,有的废弃了,也有一些新增的配置,这里只讲对 cli 有影响的配置变更

  • optimization.noEmitOnErrors: true 变更为 optimization.emitOnErrors: false;
  • 废弃 webpack.HashedModuleIdsPlugin 插件,变更为默认使用 optimization.moduleIds: 'deterministic'
  • 废弃插件旧属性如 compiler.plugin('after-emit', () => {}),变更为 compiler.hooks.emit.tap('after-emit', () => {})
  • target 需要设置为 webes5,用于表示支持目标的版本
  • ...

持久化缓存

webpack5 拓展了 cache 的功能,缓存生成的 webpack 模块和 chunk,来改善构建速度。开发环境默认设置为cache.type: memory,而生产环境则被禁用,设置为 cache: falsecache.type还支持filesystem配置,缓存将被存储到文件系统,可以在node_modules/.cache/webpack目录看到缓存的二进制文件。

但是缓存策略的设置变得有些复杂,以下文件发生变更的时候都会影响构建输出,都需要清除缓存:

  • webpack.config.js
  • package.json
  • package-lock.json
  • babel.config.js
  • postcssrc.js
  • yarn.lock
  • tsconfig.json
  • 命令行变量
  • 环境变量
  • ...

在 cli 中,我们将这些信息全部考虑进来,生成唯一的hash作为cache.name的值,上述任一信息发生变化都会生成新的hash缓存,再次切换回去,之前的缓存仍可以使用。具体的实现细节(略)

以某个略复杂项目测试结果对比为例:

webpack版本编译体积编译时间备注
5.24.33.58M43.3s首次构建
5.24.33.58M2.51s二次构建

通过上述数据可以看到二次构建时,构建提速 90% 以上。

更好的tree-shaking

webpack5对tree-shaking做了更好的支持,主要是以下几点:

  • webpack 现在能够跟踪对导出的嵌套属性的访问,并清除未使用的导出和混淆导出
  • webpack 可以对模块中的标志进行分析,找出导出和引用之间的依赖关系
  • webpack增加了对CommonJs 构造的支持,允许消除未使用的 CommonJs 导出

在实际项目中,通过bundle-analyzer分析,tree-shaking的效果主要体现在:

  • axios模块由 40.15kb 变为 20.07kb

移除nodejs模块的polyfills

bundle中不在包含nodejs模块的polyfills,包的体积会更小,如果我们有用到nodejs模块,需要手动添加polyfill,如Buffer的兼容:

{
    plugins: [
        new webpack.ProvidePlugin({
            Buffer: ["buffer", "Buffer"]
        })
    ]
}

通过 bundle-analyzer 可以看到,node-libs-browser 被移除,这个模块就是Node.js 核心库的polyfill模块,体积为61.78kb。

命名代码块

在webpack4中,模块编译后的文件名是按顺序自增的数字id,比如 1.js、2.js、*.js,这样存在一个问题,那就是当1.js模块被移除时,后续的模块会补位,这会导致即使后续模块内容没有发生变化,但是文件名发生了变化,之前缓存也就失效了。

在webpack5中,提供了解决方案。在开发环境,optimization.chunkIds 被默认设置为 named,模块名是根据文件路径生成的,如 src_views_pages_order_home_index_vue.js,在生产环境时,则被默认设置为deterministic,模块名是在不同编译中不变的短数字id,有益于长期缓存,如995.js

但是如果为了避免对已有项目缓存造成影响,可以设置为 natural,仍使用原有的自增数字。

模块联邦

module-federation允许跨应用共享模块,相信会在微前端方向会有较大的发挥空间。 这一块留待后续调研后再新开文章分享~