Webpack 5 发布之后,前端构建工具的格局发生了不小的变化。相比 4.x 版本,它在构建性能、模块联邦、缓存机制和 Tree Shaking 等方面都有明显改进。其中 Module Federation(模块联邦)被誉为 Webpack 5 最具想象力的特性,而持久化缓存则直接把二次构建速度提升了一个量级。本文围绕这两个核心特性展开,同时梳理升级过程中容易踩到的破坏性变更,帮助你全面理解这套新构建体系。

Module Federation:微前端的官方解法
模块联邦要解决的核心问题是:多个独立构建、独立部署的应用之间,如何优雅地共享代码。在它出现之前,实现这类需求通常要依赖 npm 包发布、externals 全局变量或者各种微前端框架,成本高且耦合重。Module Federation 允许一个应用在运行时动态加载另一个应用暴露出来的模块,双方只需要各自声明一份配置即可。
先看一个最小可用的配置示例。假设有两个应用:app1 作为消费方(host),app2 作为提供方(remote)。app2 把自己的按钮组件暴露出去:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app2',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.js',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
],
};app1 则声明 remote 的地址,之后在业务代码里就可以像引用普通模块一样引用远程组件:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app1',
remotes: {
app2: 'app2@http://localhost:3002/remoteEntry.js',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
],
};
// 业务代码中异步加载远程组件
const RemoteButton = React.lazy(() => import('app2/Button'));这里有几个关键概念值得展开。remoteEntry.js 是 remote 应用生成的一张“清单”,里面记录了暴露模块的映射关系,host 加载它之后就能按需拉取具体的 chunk。shared 配置则负责依赖共享与去重:设置 singleton 为 true 后,React 这类要求单例的库在整个运行时只会存在一份,避免多个副本导致的报错。需要注意的是,shared 依赖存在版本协商机制,如果 host 与 remote 的版本差异过大,Webpack 会额外加载一个副本,因此团队内部最好约定统一的依赖版本范围。
持久化缓存:二次构建提速的底层逻辑
Webpack 4 的缓存策略比较简陋,开发模式下主要靠 memory-level 的 4.x 自带缓存,一旦进程重启,缓存全部失效,冷启动就要重新编译所有模块。Webpack 5 引入了文件系统缓存(File System Cache),把编译产物按模块粒度序列化到 node_modules/.cache 目录,下次启动时直接从磁盘恢复,命中率高的项目二次构建速度可以提升 60% 到 90%。
配置方式非常简单,开发环境推荐这样写:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 配置文件变化时让缓存失效,避免读到过期产物
config: [__filename],
},
cacheDirectory: 'node_modules/.cache/webpack',
},
};buildDependencies 是很多团队容易忽略的配置。它声明了哪些文件会影响构建结果的正确性,一旦这些文件的内容变化,缓存会自动失效重建。如果把 babel.config.js、postcss.config.js 这类影响编译输出的文件也加进来,就能避免修改了转译配置但缓存没有更新的诡异问题。此外,缓存失效的判定基于内容哈希而不是时间戳,所以在 CI 环境中把 .cache 目录持久化下来,也能获得可观的提速收益。
除了缓存,Webpack 5 在编译阶段还做了不少优化,比如用更细粒度的模块依赖图取代了旧的 Parent-Child 关系,懒编译(Lazy Compilation)可以让开发模式下未被访问的路由完全不参与首次构建。对于大型项目,把 experiments.lazyCompilation 打开后,首屏启动时间往往能砍掉一大半,配合持久化缓存使用效果更佳。
升级前必须了解的破坏性变更
第一个重要变更是 Node.js polyfill 的移除。Webpack 4 会自动为 core-js 这样的浏览器 polyfill 加上 Node 核心模块的垫片,而 Webpack 5 不再这样做。如果前端代码里直接引用了 crypto、path、stream 等模块,构建时会直接报错。解决思路有两条:优先改造代码改用浏览器原生 API,比如用 window.crypto 替代 Node 的 crypto;实在绕不开的,再手动安装并配置 resolve.fallback 指定垫片。
第二个变更是资源模块(Asset Modules)的引入。它内置了处理图片、字体等资源的能力,替代了原先的 raw-loader、url-loader 和 file-loader 三件套。原来的三条规则可以合并为一条:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif|svg|woff2?)$/i,
type: 'asset',
parser: {
dataUrlCondition: {
// 小于 8KB 的资源内联为 base64
maxSize: 8 * 1024,
},
},
},
],
},
};type 字段支持 asset/resource(输出文件)、asset/inline(内联 base64)、asset/source(导出源码)和 asset(自动判断)四种模式,语义比旧 loader 的 url-loader limit 参数清晰得多。第三个变化在 Tree Shaking 方面:Webpack 5 支持嵌套的无用导出消除,还能分析模块导出与运行时副作用之间的关系,CommonJS 与 ESM 混用的场景下摇树效果也更好。此外,output.clean 替代了 CleanWebpackPlugin,新增的 url 协议模块导入等特性也在逐步稳定。
总体来看,Webpack 5 的升级收益集中在构建速度和模块联邦两块。如果你的项目还停留在 4.x,建议先解决 polyfill 与资源模块的迁移问题,再开启文件系统缓存验证构建稳定性,最后评估是否引入 Module Federation 来支撑微前端架构,分步推进的风险会小得多。
Webpack 5Module Federation前端工程化修改时间:2026-09-04 14:30:52