Webpack 5 发布之后,前端构建工具的格局被重新划分了一次。官方把它内部代号为 Federation 时代的开端,社区里甚至有人用撕碎宇宙这样的说法来形容这次升级对旧构建模式的颠覆。抛开夸张的修辞不谈,Webpack 5 确实带来了三项足以改变工程架构的能力:模块联邦、持久化缓存和更彻底的 Tree Shaking。这篇文章会逐一拆解它们的原理和落地方式,并附上可以直接参考的配置代码。

一、Module Federation:让多个应用在运行时互相共享代码
模块联邦是 Webpack 5 最具想象力的特性。在它出现之前,如果两个独立部署的前端应用想共享某个组件或工具库,只能靠 npm 私有包加发版,或者用 externals 把公共依赖挂到 window 上。这两种方式要么迭代慢,要么容易产生版本冲突。模块联邦的思路是:每个应用都可以在构建时声明自己愿意暴露哪些模块,同时声明自己需要消费哪些远程模块,运行时由 Webpack 动态加载并拼装到一起。
它的核心概念有两个:host 是消费方,remote 是提供方。remote 通过 exposes 把内部模块暴露出去,host 通过 remotes 声明远程地址。来看一个最小配置示例:
// remote 应用(提供方)webpack.config.js
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 } }
})
]
};
// host 应用(消费方)webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'hostApp',
remotes: {
remoteApp: 'remoteApp@http://cdn.ipipp.com/remoteEntry.js'
},
shared: { vue: { singleton: true } }
})
]
};
配置里最值得注意的是 shared 这个选项。它告诉 Webpack:vue 这个依赖在 host 和 remote 之间只加载一份实例,singleton: true 进一步保证全局唯一,避免出现两个 Vue 实例导致状态不同步的经典问题。需要注意的是,共享依赖的版本协商发生在运行时,如果双方版本差距过大且没有声明所需的版本范围,加载会直接报错,这一点在灰度发布时要特别小心。
二、持久化缓存:二次构建从分钟级降到秒级
Webpack 4 时代的缓存只有内存层面的 cache: true,进程一退出缓存就没了。Webpack 5 引入了基于文件系统的持久化缓存,配置一次之后,第一次构建照常完整执行,之后每次构建都会把每个模块的处理结果序列化到 node_modules/.cache/webpack 目录下,下次构建时先校验文件内容的哈希值,没变的模块直接复用结果,跳过整个解析、转换过程。
// webpack.config.js
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 配置文件本身变化时,缓存自动失效
config: [__filename]
},
cacheDirectory: 'D:\project\.cache\webpack',
version: '1.0.0'
}
};
这里有一个非常容易踩的坑:buildDependencies 默认只包含配置文件,如果你在构建流程中依赖了 babel 配置、postcss 配置或者其他自定义脚本,就必须手动把它们加进去,否则改了这些文件但缓存没有失效,会出现改了配置却不生效的诡异现象,排查起来相当折磨人。另外 version 字段适合用来做手动的缓存分段,比如依赖升级后换一个版本号,强制全量重建。
实测下来,中大型项目的二次冷启动构建时间通常能压缩到原来的五分之一甚至更低,CI 环境如果能持久化缓存目录,收益会更明显。不过要注意缓存目录会随时间膨胀,建议在 CI 上设置定期清理策略。
三、更彻底的 Tree Shaking 与嵌套无用代码消除
如果说前两个特性是撕碎了应用之间的边界,那 Tree Shaking 的增强就是撕碎代码内部的无用部分。Webpack 5 引入了全新的模块级分析和作用域提升改进,支持对 CommonJS 导出的一部分场景进行分析,同时增加了对嵌套的无副作用模块的消除能力。最实用的一个变化是对顶层 await 的支持,配合 sideEffects 声明,可以让打包器更精准地判断哪些文件可以整文件删除。
// package.json
{
"name": "my-utils",
"sideEffects": false
}
// 业务代码中引入
import { debounce } from 'my-utils';
// 如果 my-utils 声明了 sideEffects: false
// 未被使用的 throttle 等导出会被完整剔除
需要注意的是,sideEffects: false 是一个对全包生效的承诺,如果你的包里有 polyfill 或者依赖执行顺序的副作用文件,就应该改用数组形式列出这些例外路径,例如 "sideEffects": ["./src/polyfill.js", "*.css"]。乱声明导致的 bug 往往表现为样式丢失或全局变量未初始化,定位起来比较隐蔽。
四、升级建议与兼容性检查
从 Webpack 4 迁移到 5,官方移除了不少遗留能力:Node.js polyfill 不再自动注入,如果你在浏览器端代码里直接用了 process 或 path,需要手动安装对应的 polyfill 或者改写代码;json-module 等废弃选项也一并清理了。升级前建议先跑一遍构建,把所有 deprecation warning 处理干净,再切换主版本。
对于 loader 和插件生态,主流的 css-loader、babel-loader、vue-loader 早已全面兼容 Webpack 5,真正容易出问题的是公司内部沉淀的老插件,它们可能依赖了被移除的内部 API。整体来看,只要完成迁移,持久化缓存带来的构建提速加上模块联邦打开的微前端想象空间,这次升级的性价比非常高,值得在合适的时间窗口推进。
Webpack 5Module Federation持久化缓存修改时间:2026-09-16 15:36:44