Webpack 5 发布已经有一段时间,但不少团队仍然停留在旧版本的使用习惯上,没有真正利用新版本带来的性能红利。事实上,Webpack 5 在构建性能、代码拆分和跨应用共享模块这三个方向上都有突破性改进。本文将从持久化缓存、更智能的代码分割以及模块联邦三个核心特性入手,结合配置示例与最佳实践,帮助你理解这些能力背后的原理,并在项目中快速落地。

持久化缓存:让二次构建快起来
Webpack 5 之前,社区通常依赖 webpack-loader 的 cacheDirectory 选项或第三方插件(如 hard-source-webpack-plugin)来实现文件系统缓存,但这类方案稳定性较差,偶尔会出现缓存失效甚至构建结果错误的问题。Webpack 5 将文件系统缓存内置为官方能力,只需在配置中开启 cache: { type: 'filesystem' },构建产物和中间模块就会被缓存到 node_modules/.cache/webpack 目录中,二次构建时可以直接跳过大部分解析和转换工作。
来看一个典型的配置示例:
// webpack.config.js
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 推荐把配置文件本身作为构建依赖,配置变更时缓存自动失效
config: [__filename]
},
cacheDirectory: 'node_modules/.cache/webpack',
version: '1.0.0'
}
};
配置中有几个细节值得注意。buildDependencies 用来声明哪些文件变更时应该让缓存整体失效,把 webpack 配置文件、babel 配置文件加进去可以避免缓存污染。version 字段则适合在升级依赖或切换分支时手动变更,用于强制生成一套新的缓存。实际测试中,中大型项目的二次构建时间通常能缩短 60% 到 80%,效果非常明显。
需要提醒的是,如果项目中有自定义 loader,需要确保 loader 的输出是确定性的,否则可能导致缓存命中后产物不一致。另外,CI 环境中可以通过缓存 node_modules/.cache 目录来加速流水线构建,这也是很多团队容易忽略的优化点。
更智能的 Code Splitting 策略
代码分割一直是控制首屏体积的关键手段。Webpack 5 在 splitChunks 的默认策略上做了调整:默认只拆分异步引入的模块,且对 node_modules 中的模块统一处理为一个 chunk,同时提高了最小尺寸阈值(minSize 从 30KB 提升到 20KB 且逻辑更精细,配合 minRemainingSize 避免生成过小的 chunk)。这意味着默认配置下生成的文件数量更少、更集中,减少了 HTTP 请求的碎片化。
下面是一个兼顾 vendor 拆分与按需加载的配置示例:
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 250000,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: -10,
reuseExistingChunk: true
},
common: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
除了配置层面的改进,Webpack 5 对 Tree Shaking 也做了增强。新版能够分析嵌套的导出结构,识别 export * from 场景下未使用的导出项,配合 package.json 中的 sideEffects 字段,可以更彻底地剔除死代码。对于体积敏感的组件库,建议显式声明副作用信息,例如:
{
"name": "my-ui-lib",
"sideEffects": false
}
如果库中存在需要保留的样式文件或 polyfill,则可以写成数组形式,逐条列出有副作用的文件路径。这些细节处理得当,最终产物体积往往能减少 10% 以上。
模块联邦:跨应用共享模块的新范式
模块联邦(Module Federation)是 Webpack 5 最具想象力的特性。它允许多个独立构建、独立部署的应用在运行时互相暴露和消费模块,公共依赖也可以共享同一份实例。这在微前端架构中特别有价值:宿主应用可以远程加载子应用暴露的组件,而不需要把子应用的代码打进自己的包里。
先看提供方(远程应用)的配置:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'remoteApp',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.vue'
},
shared: {
vue: { singleton: true, requiredVersion: '^3.0.0' }
}
})
]
};
再看消费方(宿主应用)如何引用远程模块:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'hostApp',
remotes: {
remoteApp: 'remoteApp@https://cdn.ipipp.com/remoteEntry.js'
},
shared: {
vue: { singleton: true, requiredVersion: '^3.0.0' }
}
})
]
};
宿主应用中可以直接异步引入远程组件:const Button = defineAsyncComponent(() => import('remoteApp/Button'))。shared 配置中的 singleton: true 保证了宿主与远程应用共用同一个 Vue 实例,避免了多实例带来的状态错乱问题,这是使用共享依赖时最重要的一个开关。
使用模块联邦时还需要注意版本协商机制:当宿主和远程的共享依赖版本不兼容时,Webpack 会在控制台给出警告并各自加载自己的版本,因此团队间约定好 requiredVersion 范围非常关键。此外,远程应用的 remoteEntry.js 本质上是一个运行时加载器,它需要异步加载,所以入口处要用 async boundary(例如 import('./bootstrap') 的方式)来保证共享依赖在应用初始化前完成协商。
升级建议与常见问题
从 Webpack 4 迁移到 5 时,有几个兼容性问题需要重点关注。首先是 Node.js 版本要求提升到 10.13 以上;其次,node.polyfill 不再默认注入,如果代码中依赖了 process、path 等浏览器端垫片,需要手动安装并在 resolve.fallback 中配置,否则构建时会直接报错。
其次是废弃 API 的清理。例如 webpack.optimize.ModuleConcatenationPlugin 之类的插件在新版本中已经移除或合并进默认行为,配置里残留的旧插件会导致构建失败。建议升级时先跑一次完整构建,根据报错逐项排查,再逐步开启缓存和模块联邦等新能力。
总体来说,Webpack 5 的这些特性并不是孤立的:持久化缓存改善开发体验,更智能的代码分割优化线上加载,模块联邦则打开了跨团队协作的新思路。如果你的项目仍在使用旧版本,升级投入的成本通常在一两天内,而带来的长期收益是持续性的,值得尽快排上迭代计划。
Webpack 5Code Splitting模块联邦修改时间:2026-08-31 14:59:08