迁移到 webpack 5
从 v4 迁移到 v5
本指南旨在帮助你在直接使用 webpack 时迁移到 webpack 5。如果你使用更高级别的工具来运行 webpack,请参考该工具的迁移说明。
准备工作
Webpack 5 至少需要 Node.js 10.13.0(LTS),因此请确保升级你的 Node.js(如果你仍在运行旧版本)。
升级 webpack 4 及其插件/加载器
-
将
webpack4 升级到最新的可用版本。-
当使用 webpack >= 4 时,升级到最新的 webpack 4 版本应该不需要额外的指导。
-
如果你使用的 webpack 版本低于 4,请参阅 webpack 4 迁移指南。
-
-
将
webpack-cli升级到最新的可用版本(如果使用)。 -
将所有使用的插件和加载器升级到最新的可用版本。
某些插件和加载器可能有一个测试版本(beta 版本),必须使用该版本才能与 webpack 5 兼容。
升级每个插件/加载器时,请务必阅读其发布说明,因为最新版本可能只支持 webpack 5,而在 v4 中会失败。在这种情况下,建议更新到支持 webpack 4 的最新版本。
Codemods
为了协助从 webpack v4 升级到 v5,Codemod 提供了开源的社区 codemods,可以帮助自动化大部分迁移过程。
请注意,这些不是官方的 webpack codemods,虽然它们旨在简化迁移过程,但可能无法覆盖所有情况。你可能仍需要执行额外的手动步骤来完全完成升级。
bash
npx codemod@latest webpack/v5/migration-recipe
这将从 Codemod registry 运行以下 codemods:
webpack/v5/set-target-to-false-and-update-pluginswebpack/v5/migrate-library-target-to-library-objectwebpack/v5/json-imports-to-default-imports
这些 codemods 中的每一个都自动化了 webpack v5 迁移指南中列出的一项更改。有关可用的 webpack v5 codemods 的完整列表,请参阅 Codemod Registry。
确保你的构建没有错误或警告
由于 webpack、webpack-cli、插件和加载器的版本升级,可能会有新的错误或警告。在构建过程中请注意弃用警告。
你可以通过以下方式调用 webpack 来获取弃用警告的堆栈跟踪,以找出是哪些插件和加载器导致的。
bash
node --trace-deprecation node_modules/webpack/bin/webpack.js
由于 webpack 5 移除了所有已弃用的功能,请确保在构建过程中没有 webpack 弃用警告,以便继续。
确保使用 mode
将 mode 设置为 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: trueoptimization.occurrenceOrder: true→optimization: { chunkIds: 'total-size', moduleIds: 'size' }optimization.splitChunks.cacheGroups.vendors→optimization.splitChunks.cacheGroups.defaultVendorsoptimization.splitChunks.cacheGroups.test(module, chunks)→optimization.splitChunks.cacheGroups.test(module, { chunkGraph, moduleGraph })Compilation.entries→Compilation.entryDependenciesserve→serve已被移除,取而代之的是DevServerRule.query(自 v3 起弃用)→Rule.options/UseEntry.optionsRule.loaders→Rule.use
T> 查看配置选项的详细更改 此处。
测试 webpack 5 兼容性
尝试在 webpack 4 配置中设置以下选项,并检查构建是否仍然正常工作。
js
export default {
// ...
node: {
Buffer: false,
process: false,
},
};
在将配置升级到 webpack 5 时,你必须再次移除这些选项。
T> webpack 5 从配置模式中移除了这些选项,并始终使用 false。
升级到 webpack 5
现在让我们将 webpack 升级到版本 5:
-
npm:
npm install webpack@latest -
Yarn:
yarn add webpack@latest -
pnpm:
pnpm add webpack@latest
如果你在“升级 webpack 4 及其插件/加载器”步骤中无法将某些插件/加载器升级到最新版本,别忘了现在升级它们。
清理配置
-
考虑从 webpack 配置中移除
optimization.moduleIds和optimization.chunkIds。默认值可能更好,因为它们支持生产模式中的长期缓存和开发模式中的调试。 -
在 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。 -
如果你定义了用于加载资源的
raw-loader、url-loader或file-loader的rules,请改用 Asset Modules,因为它们将在不久的将来被弃用。 -
如果你将
target设置为函数,请将其更新为false,并在plugins选项中应用该函数。请参见下面的示例:json// 适用于 webpack 4 { target: WebExtensionTarget(nodeConfig) } // 适用于 webpack 5 { target: false, plugins: [ WebExtensionTarget(nodeConfig) ] }注意:此更改的 Codemod:
bashnpx codemod webpack/v5/set-target-to-false-and-update-plugins(在此处查看 registry。)
-
如果你定义了 output.library 或 output.libraryTarget,请更改属性名称:(output.libraryTarget -> output.library.type,output.library -> output.library.name)。示例
json// 适用于 webpack 4 { output: { library: 'MyLibrary', libraryTarget: 'commonjs2' } } // 适用于 webpack 5 { output: { library: { name: 'MyLibrary', type: 'commonjs2' } } }注意:此更改的 Codemod:
bashnpx codemod webpack/v5/migrate-library-target-to-library-object(在此处查看 registry。)
如果你通过 import 使用 WebAssembly,则应遵循以下两步过程:
- 通过设置
experiments.syncWebAssembly: true启用已弃用的规范,以获得与 webpack 4 中相同的行为。 - 成功迁移到 webpack 5 后,将
experiments的值更改为experiments: { asyncWebAssembly: true },以使用最新版本的 WASM 集成规范。
重新考虑 optimization.splitChunks:
- 建议使用默认值或
optimization.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配置来决定为运行时代码生成哪种代码风格。确保:
- 将
target设置为browserslist,或者移除target让 webpack 自动为你设置browserslist。 - 在 browserslist 配置中添加
IE 11。
- 将
-
如果没有
browserslist,webpack 的运行时代码使用 ES2015 语法(例如箭头函数)来构建更小的包。因此,你需要设置target: ['web', 'es5']以便为不支持 ES2015 语法的浏览器(如 IE11)使用 ES5 语法。 -
对于 Node.js,构建时在
target选项中包含支持的 Node.js 版本,webpack 将自动判断支持哪些语法,例如:target: 'node8.6'。
清理代码
使用 /* webpackChunkName: '...' */
确保理解其意图:
- 这里的 chunk 名称是公开的。
- 它不仅仅是开发时的名称。
- Webpack 将在生产模式和开发模式中使用它来命名文件。
- Webpack 5 即使在未使用
webpackChunkName时,也会在开发模式下自动分配有用的文件名。
从 JSON 模块使用命名导出
新规范不支持此操作,你将收到警告。不要使用:
js
import { version } from "./package.json";
console.log(version);
请使用:
js
import pkg from "./package.json";
console.log(pkg.version);
注意:此更改的 Codemod:
bashnpx codemod webpack/v5/json-imports-to-default-imports(在此处查看 registry。)
清理构建代码
- 使用
const compiler = webpack(...);时,请确保在使用后关闭编译器:compiler.close(callback);。- 这不适用于
webpack(..., callback)形式,它会自动关闭。 - 如果你在监听模式下使用 webpack,直到用户结束进程,此操作是可选的。监听模式下的空闲阶段将用于此类工作。
- 这不适用于
运行单个构建并遵循建议
请务必仔细阅读构建错误/警告。如果没有相应的建议,请创建一个 issue,我们将尽力解决。
重复以下步骤,直到你至少解决了级别 3 或 4:
-
级别 1:模式验证失败。
配置选项已更改。应该有一个带有
BREAKING CHANGE:注释的验证错误,或者一个应该使用哪个选项的提示。 -
级别 2:Webpack 以错误退出。
错误消息应告诉你需要更改什么。
-
级别 3:构建错误。
错误消息应该有一个
BREAKING CHANGE:注释。 -
级别 4:构建警告。
警告消息应告诉你哪些地方可以改进。
-
级别 5:运行时错误。
这很棘手。你可能必须调试才能发现问题。这里很难给出通用建议。但我们在下面列出了一些关于运行时错误的常见建议:
process未定义。- webpack 5 不再包含此 Node.js 变量的 polyfill。避免在前端代码中使用它。
- 想支持浏览器使用?使用 package.json 中的
exports或imports字段,根据环境使用不同的代码。- 也可以使用
browser字段来支持旧的打包器。 - 替代方案:使用
typeof process检查来包裹代码块。请注意,这将对包大小产生负面影响。
- 也可以使用
- 想使用
process.env.VARIABLE来使用环境变量?你需要在配置中使用DefinePlugin或EnvironmentPlugin来定义这些变量。- 考虑改用
VARIABLE,并确保也检查typeof VARIABLE !== 'undefined'。process.env是 Node.js 特有的,应避免在前端代码中使用。
- 考虑改用
- 指向包含
auto的 URL 的 404 错误- 并非所有生态系统工具都已为新的默认自动
publicPath(通过output.publicPath: "auto")做好准备。- 使用静态的
output.publicPath: ""代替。
- 使用静态的
- 并非所有生态系统工具都已为新的默认自动
- 无法读取 undefined 的属性(读取 'call')
- 如果你在运行时看到此错误,它可能与 ModuleConcatenationPlugin 有关。检查你是否在使用该插件,以及你是否已在配置的
plugins部分中包含它,并且该配置还设置为production模式,请从插件列表中移除该插件(即new webpack.optimize.ModuleConcatenationPlugin())。在 webpack 5 中,该插件在生产模式下默认启用,可能会被包含两次。 - 通常,禁用每个插件并测试构建是排查问题来源的好方法。
- 参见:这个 issue 了解更多详情。
- 如果你在运行时看到此错误,它可能与 ModuleConcatenationPlugin 有关。检查你是否在使用该插件,以及你是否已在配置的
-
级别 6:弃用警告。
你可能会收到很多弃用警告。这并不直接是问题。插件需要时间来跟上核心更改。请向插件报告这些弃用。这些弃用只是警告,构建仍然可以工作,只是有一些小的缺点(如性能降低)。
- 你可以通过使用
--no-deprecation标志运行 node 来隐藏弃用警告,例如:node --no-deprecation node_modules/webpack/bin/webpack.js。这应该只是一个临时的解决方法。 - 插件和加载器贡献者可以遵循弃用消息中的建议来改进代码。
- 你可以通过使用
-
级别 7:性能问题。
通常,webpack 5 的性能应该有所提高,但在某些情况下性能也会变差。
以下是一些可以改善情况的方法:
- 分析时间花在哪里。
--profile --progress现在显示一个简单的性能分析node --inspect-brk node_modules/webpack/bin/webpack.js+chrome://inspect/edge://inspect(参见 profiler 标签页)。- 你可以将这些性能分析保存到文件中,并在 issue 中提供。
- 在某些情况下,尝试使用
--no-turbo-inlining标志以获得更好的堆栈跟踪。
- 增量构建中构建模块的时间可以通过恢复到 webpack 4 中的不安全缓存来改善:
module.unsafeCache: true- 但这可能会影响处理代码库某些更改的能力。
- 完整构建
- 用于已弃用功能的向后兼容层通常比新功能的性能更差。
- 创建许多警告会影响构建性能,即使它们被忽略。
- Source Maps 代价高昂。查看文档中的
devtool选项,了解不同选项的比较。 - 防病毒保护可能会影响文件系统访问的性能。
- 持久化缓存有助于改善重复的完整构建。
- Module Federation 允许将应用程序拆分为多个较小的构建。
- 分析时间花在哪里。
一切正常吗?
请发推文说你已成功迁移到 webpack 5。发布推文
不工作吗?
创建一个 issue 并告诉我们你在迁移过程中遇到的问题。
本指南中缺少某些内容吗?
请打开一个 Pull Request 来帮助下一个使用本指南的人。
内部变更
webpack 内部的一些更改,例如:添加类型、重构代码和方法重命名,列在此处供感兴趣的人参考。但它们并不属于常见用例迁移的一部分。
Module.nameForCondition、Module.updateCacheModule和Module.chunkCondition不再是可选的。
Loaders 的 getOptions 方法
Webpack 5 在 loader 上下文中内置了 this.getOptions 方法。这对于那些一直使用先前推荐的 schema-utils 中的 getOptions 方法的加载器来说是一个破坏性更改:
this.getOptions自 webpack 5 起可用- 它支持 JSON 作为查询字符串,而不是 JSON5:
?{arg:true}→?{"arg":true}。使用 JSON5 应被视为已弃用,并应在相应加载器的文档中说明使用 JSON 替代。 loader-utils对解析查询字符串有特定行为(true、false和null不会被解析为string,而是解析为原始值)。新的内置this.getOptions方法不再如此,它使用 Node.js 自带的原生querystring解析。仍然可以在加载器代码中通过this.getOptions方法获取选项后为这些情况添加自定义行为。- 新的
this.getOptions方法的 Schema 参数是可选的,但我们强烈建议为加载器的选项添加 schema 验证。schema 中的title字段可用于自定义验证错误消息,例如:"title": "My Loader ooooptions"将导致错误显示如下: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.
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
