准备工作

2023-05-31 11:58 更新
Webpack 5 对 Node.js 的版本要求最低是 10.13.0 (LTS),因此,如果你还在使用旧版本的 Node.js,请升级它们。

升级 webpack 4 及其相关的插件/加载器

  1. 升级 webpack 4 至最新的可用版本。
  • 当使用webpack >= 4时,升级到最新的webpack 5版本无需额外的操作。
  • 如果您使用的 webpack 版本小于 4,请查看 webpack 4 迁移指南

2. 升级 webpack-cli 到最新的可用版本(如已使用的情况下)
3. 升级所有使用到的插件和加载器为最新的可用版本。
部分插件和加载器可能会有一个 beta 版本,必须使用它们才能与 webpack 5 兼容。 请确保在升级时阅读每个插件/加载器的发布说明,因为最新版本可能只支持webpack 5,而在v4中会运行失败。在这种情况下,建议升级到支持 webpack 4 的最新版本。

确保你的结构没有错误或警告

由于升级了webpack,webpack-cli,plugin以及loader的版本,因此,可能会出现新的错误或警告。在编译过程中请注意是否有废弃警告。
你可以通过如下方式调整 webpack 来获取堆栈信息中的废弃警告,从中找到是哪个插件或者 loader 构建的。

node --trace-deprecation node_modules/webpack/bin/webpack.js

由于webpack 5移除了所有被废弃的特性,因此,需要确保在构建过程中没有webpack的废弃警告才能继续。

请确保设置了模型

将模型设置为 ​production​ 或 ​development​ 以确保相关的默认值被设置。

升级废弃的配置项

如有使用以下的配置项,请升级至最新的版本:

  • optimization.hashedModuleIds: true​ → ​optimization.moduleIds: 'hashed'
  • optimization.namedChunks: true​ → ​optimization.chunkIds: 'named'
  • optimization.namedModules: true​ → ​optimization.moduleIds: 'named'
  • NamedModulesPlugin​ → ​optimization.moduleIds: 'named'
  • NamedChunksPlugin​ → ​optimization.chunkIds: 'named'
  • HashedModuleIdsPlugin​ → ​optimization.moduleIds: 'hashed'
  • optimization.noEmitOnErrors: false​ → ​optimization.emitOnErrors: true
  • optimization.occurrenceOrder: true​ → ​optimization: { chunkIds: 'total-size', moduleIds: 'size' }
  • optimization.splitChunks.cacheGroups.vendors​ → ​optimization.splitChunks.cacheGroups.defaultVendors
  • optimization.splitChunks.cacheGroups.test(module, chunks) ​→ ​optimization.splitChunks.cacheGroups.test(module, { chunkGraph, moduleGraph })
  • Compilation.entries​ → ​Compilation.entryDependencies
  • serve​ → ​serve​ 已被移除,推荐使用 ​DevServer
  • Rule.query​(从 v3 开始被移除)→ ​Rule.options​/​UseEntry.options
  • Rule.loaders​ → ​Rule.use

测试 webpack 5 兼具性

尝试在 webpack 4 的配置中添加如下选项,检查一下构建是否仍然正确的运行。

module.exports = {
// ...
node: {
Buffer: false,
process: false,
},
};

你必须在升级 webpack 5 的配置时,必须删除这些选项。

清理配置

2023-05-31 13:55 更新
现在,让我们升级到 webpack 5:

  • npm: npm 安装 webpack@latest
  • 纱线:纱线添加webpack@latest

如果你之前在升级 webpack 4 时不能将任何插件或加载器升级到最新版本,现在不要忘了升级。

清理配置

  • 请考虑 ​optimization.moduleIds​ 和 ​optimization.chunkIds​ 从你的webpack配置中移除。使用默认值会更合适,因为它们会在 production 模式 下支持长效缓存且可以在 development 模式下进行调试。
  • 当webpack配置中使用了 ​[hash]​ 占位符时,请考虑将其改为 ​[contenthash]​ 。效果一致,但事实证明会更有效。
  • 如果你使用了 Yarn 的 PnP 以及 ​pnp-webpack-plugin​ 插件,你可以将其从配置中移除,因为它已经被默认支持。
  • 如果你使用了带有正确表达式参数的 ​IgnorePlugin​ ,现在已经支持传入一个 ​options​ 对象: ​new IgnorePlugin({ resourceRegExp: /regExp/ })​ 。
  • 如果你使用了类似于 ​node.fs: 'empty'​ ,请使用 ​resolve.fallback.fs: false​ 代替。
  • 如果你在 webpack 的 Node.js API 中使用了 ​watch: true​ ,请移去它。无需按编译器的提示设置,当执行 ​watch()​ 时为 ​true​ ,当执行 ​run()​ 时为 ​false​ 。
  • 如果您确定了 ​rules​ ,则使用 ​raw-loader​ ,​ url-loader​ 或 ​file-loader​ 来加载资源,请使用 资源模板 替代,因为它们可能会在不久的将来被淘洗。
  • 如果你将 ​target​ 标记设置为函数,则应将其更新为 ​false​ ,然后在插件中选择使用该函数。具体示例如下:
// for webpack 4
{
target: WebExtensionTarget(nodeConfig)
}
// for webpack 5
{
target: false,
plugins: [
WebExtensionTarget(nodeConfig)
]
}

如果通过 import 使用了 WebAssembly,应遵循以下两点:

  • 在配置增加 ​experiments.syncWebAssembly: true​ 配置,以启动废弃提示,获得在webpack 4中的一致为。
  • 在成功升级至 webpack 5 以后,应将 ​experiments​ 的值改为 ​experiments:{ asyncWebAssembly: true }​ 以使用最新规范的 WASM。

重新考虑 ​optimization.splitChunks​ 的配置:

  • 推荐使用默认配置或使用优化。​splitChunks: { chunks: 'all' }​ 配置。
  • 当使用自定义配置时,请删除 ​name: false​ ,并将 ​name: string | function​ 替换为 ​idHint: string | function​ 。
  • 使用 ​optimization.splitChunks.cacheGroups: { default: false, vendors: false }​ 配置可以关闭默认值。但我们不推荐这样做,如果你需要在webpack 5中获得与之相同的效果:请将配置更改为 ​optimization.splitChunks.cacheGroups: { default: false, defaultVendors: false }​ 。

考虑迁移的默认值:

  • 当设置 ​entry: './src/index.js'​ 时,你可以省略它,此为默认值。
  • 当设置 ​output.path: path.resolve(__dirname, 'dist')​ 时:你可以省略它,此为默认值。
  • 当设置 ​output.filename: '[name].js'​ 时:你可以省略它,此为默认值。

需要旧版浏览器的支持?比如IE 11?

  • 如果你在项目中启用了 browserslist ,webpack 5 将会重新使用你的 ​browserslist​ 配置来决定运行时的代码风格。

只需要确保:
1. 将目标设置为browserslist,或者转移者移除target配置,webpack会自动将其置为 browserslist
2. 在你的 ​browserslist​ 配置中添加​ IE 11​ 。

  • 如果未使用 ​browserslist​ ,webpack 的运行时代码将默认使用 ES2015 语言法(例如,箭头数)来构建一个简洁的 bundle。如果你构建构建的目标环境并不支持 ES2015 的语言(如 IE 11),你需要设置 ​target:['web', 'es5']​ 以使用 ES5 的语言。
  • 对于Node.js环境来说,构建中引入了对Node.js版本的支持,webpack会自动找到对应用版本支持的语言,例如,​target: 'node8.6'​ 。
  • 清理代码

    2023-05-31 14:27 更新

    使用 ​​ 时

    请确保你了解了其含义图:

    • 此处 chunk 的名称本意是 public 的。
    • 它不仅是用于开发模式的名称。
    • webpack 会在 production 以及 development 的模式中使用它对文件进行命名。
    • 即使用不使用 ​webpackChunkName​,webpack 5也会自动在 ​development​ 模式下分配有意义的文件名。

    为 JSON 模块使用工具名称导出

    新规中将不再支持下面这种方式,如此做会发出警告:

    import { version } from './package.json';
    console.log(version);

    请使用如下方式替代:

    import pkg from './package.json';
    console.log(pkg.version);

    清理构造代码

    • 当使用 ​const compiler = webpack(...);​ ,确保在使用完成后,使用​compiler.close(callback);​ 关闭编译器。
    • 这不适合用于自动关闭的 ​webpack(..., callback)​ 。
    • 如果你在监听模式下使用webpack,直接连接到用户绑定进程,此可选。在监听模式下面的空闲阶段将被用于执行此操作。

    运行单个结构并遵循以下建议

    请事务必须仔细阅读构建时的错误/警告。如未发现相关建议,请创建一个issue,我们将尽全力解决。
    重新按照下面步骤,直到你至少解决到 Level 3 或 Level 4:

    • Level 1: 模型(Schema)校试失败

    配置选项已更改。应该要有校试失败的信息并附上 ​BREAKING CHANGE:​ 提示,或提示应用哪一个选项。


    • Level 2: webpack 异常退出并出现错误

    错误信息告诉你哪里需要进行修改。


    • 等级3:构建错误

    错误信息应该要有 BREAKING CHANGE: 提示。


    • Level 4: 构建警告

    警告信息应该告诉你哪里需要进行修改。


    • Level 5: 运行时错误

    这很棘手,你可能需要调试才能找到问题所在。在这里很难给出一个通用的建议。但是我们在下面列出了一些关于运行时错误的常见建议:
    1. ​process​ 未定义。

    • webpack 5 不再引入 Node.js 变化的 polyfill,在前端代码中应用避免免费使用。
    • 想支持浏览器的使用方法?使用 ​exports​ 或 ​imports​ 中的 package.json字符串,会根据环境不同使用不同的代码。
    • 也可以使用 ​browser​ 字段来支持旧的 bundlers。
    • 替代方案。用 ​typeof process​ 检查包裹的代码块。请注意,这将对 bundle 大小产生负面影响。
    • 使用环境变量,如 ​process.env. VARIABLE?​你需要使用 ​DefinePlugin​ 或者  ​EnvironmentPlugin​ 在配置中定义这些变量。
    • 考虑使用 VARIABLE 代替,但需要检查 ​typeof VARIABLE !== 'undefined'​ 。​process.env​ 是 Node.js 特有,应避免在前端中使用。

    2. 404错误将指向包含 auto 的 URL

    • 并非所有生态系统工具都已设置好的新 ​publicPath​ 的默认值 ​output.publicPath: "auto"
    • 使用静态的 ​output.publicPath: ""​ 代替。


    • Level 6: 弃用警告

    你可能会收到很多弃用警告,插件需要时间来赶上内部的变化。请将这些弃用上报给插件。这些弃用只是警告,构建仍然可以正常工作,只是会有小瑕疵(比如性能降低)。

    1. 你使用带有 ​--no-deprecation​ 选项的 node 运行 webpack ,可以可以隐藏废弃告警,例如:  ​node --no-deprecation node_modules/webpack/bin/webpack.js​ 。但这只能作为临时的解决方案。
    2. plugin 和 loader 的开发者,应遵循弃用信息中的建议以改进代码。


    • Level 7: 性能问题

    一般来说,webpack 5 的性能应该会有所提高,但也存在少数情况性能会变差。
    而在这里,你可以做一些事情来改善这种情况:
    1. 通过 Profile 检查时间花费在哪里。

    • --profile --progress​ 可以显示一个简单的性能目标。
    • node --inspect-brk node_modules/webpack/bin/webpack.js + chrome://inspect ​/  ​edge://inspect​  。
    • 你可以将这些性能文件保存到文件中,并在 issues 中提供它们。
    • 尝试使用 ​--no-turbo-inlining​ 选项,在某些情况下可以获得更好的堆栈信息。

    2. 在增量构建时,构建模块的世界可以通过使用像 webpack 4 中的不安全缓存来改善:

    • module.unsafeCache: true
    • 但是这可能会影响处理代码库的一些变化能力。

    3. 全量构建

    • 与新功能相比,弃用特性的向后兼容层通常性能很差。
    • 创建许多警告会影响构建性能,即使它们被忽略。
    • Source Maps 的代价很昂贵。请在文档中查看 ​devtool​ 选项以比较使用不同选项的代价。
    • Anti-Virus(反病毒)保护可能会影响文件系统的访问性能。
    • 持久缓存可以帮助改善重复性的完整构建。
    • Module Federation 允许将应用程序分割成多个较小的构建。
    • 后续工作

      2023-05-31 14:33 更新

      所有的情况都运行得如常吗?

      如果你成功地迁移到webpack 5。请发推@我们。

      运动异常?

      创建一个 issue 并告诉我们在迁移过程中你遇到了问题。

      发现本指南中缺失的东西?

      请提交 Pull Request 以帮助其他开发者更好地使用该指南。

      内核的改变

      如果你对内核感兴趣,这里会列出webpack内核相关的变化,如:添加类型,代码重组和方法重命名等。但这些变化并不会做为迁移通用案例的一部分。

      • Module.nameForCondition​ ,​Module.updateCacheModule​ 以及 ​Module.chunkCondition​ 不再可选。

      loader 的 getOptions 方法

      Webpack 5 发布后,在loader 的上下文中,会带有内部设置的 ​this.getOptions​ 方法。这对于那些使用之前推荐 schema-utils 中的 ​getOptions​ 方法的loader 而言,这是一个更大更新:

      • this.getOptions​ 自 webpack 5 启动支持使用
      • 它支持将 JSON 作查询字符串,而不只是 JSON5:如 ​?{arg:true} ​→ ​?{"arg":true}​。在相关的加载器文档中,应用推荐使用 JSON 而不是推荐使用JSON5。
      • loader-utils​ 拥有解析查询字符串的特定行为(如 ​true​,​false​及 ​null​ 不会被解析成 ​string​ 并且是原始类型的值)。这对新的内部设置 ​this.getOptions​ 方法来说,不再适用,它使用Node原生的 ​querystring​ 方法进入解析。此时,需要在loader中使用 ​this.getOptions​ 获取配置选项之后,根据情况添加自主权为行。
      • 模式(Schema) 参看新的 ​this.getOptions​ 方法而言是可以选择的,但是我们强烈建议给你的加载器选择项添加模式校试。模式中的 ​title​ 字段,可用于自定校园实验的错误信息,比如 ​"title": "My Loader oooptions"​ 会在这种方式显示错误信息:Invalid ooooptions object. My Loader has been initialised using an ooooptions object that does not match the API schema. - ooooptions.foo.bar.baz should be a string.