Webpack 5 发布至今已经沉淀了相当多的新能力,其中被社区称为 Fusing Universe(融合宇宙)的一系列架构升级,把持久化缓存、模块联邦、模块联邦与依赖图的深度融合整合到了一起。这套机制的核心目标只有一个:让构建系统从孤立的单一项目视角,转变为多应用、多团队、多缓存层协同的统一宇宙视角。本文将围绕这套融合机制展开,从原理、配置实战到迁移注意事项,逐一拆解。

一、什么是 Fusing Universe:从孤立构建到融合构建图
传统 Webpack 构建中,每个项目都是一个独立的宇宙:各自维护 node_modules,各自执行完整的编译流程,即使两个项目依赖了同一个版本的 lodash,也会被重复解析、重复打包。Fusing Universe 的思路是打破这种孤岛状态,让模块解析结果、依赖图片段、产物哈希能够在多个构建实例之间流通与复用。
实现层面,它依赖三个基础设施协同工作。第一是基于文件系统快照的持久化缓存(File System Caching),Webpack 5 会将每个模块的解析结果与文件内容哈希绑定,写入本地缓存目录;第二是改进后的模块联邦(Module Federation),允许运行时动态拉取远程模块并与本地依赖图融合;第三是确定性的模块 ID 算法,保证同一份源码在不同机器、不同项目中的 ID 一致,从而让缓存片段可以跨项目命中。
举个直观的例子:团队 A 的组件库与团队 B 的主应用共享同一份 React 依赖,在融合模式下,B 应用构建时可以直接消费 A 应用已经编译好的模块描述文件,跳过重新编译的成本。在大型 Monorepo 场景下,这种机制能把增量构建时间压缩到原来的三分之一左右。
二、核心配置实战:缓存、联邦与融合开关
先看最基础的持久化缓存配置。这是融合宇宙的地基,如果缓存配置不当,后面所有的融合能力都无从谈起。
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 配置文件本身变更时,缓存自动失效
config: [__filename]
},
cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
version: 'fusion-v1' // 版本号变化会整体丢弃缓存
}
};这里的 buildDependencies 是一个容易被忽视的关键点。很多团队把 babel 配置、postcss 配置写在外部文件里,却没有加进这个列表,结果改了配置缓存却不失效,产出过期的错误代码。排查这类问题的特征是:改动配置后构建产物没变化,删除缓存目录后恢复正常。
接下来是模块联邦部分。Webpack 5 的联邦机制允许把某个模块暴露出去,供其他独立部署的应用在运行时加载:
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'hostApp',
remotes: {
// 远程应用,指向另一个独立部署的入口
remoteLib: 'remoteApp@https://cdn.ipipp.com/remote/remoteEntry.js'
},
shared: {
react: { singleton: true, eager: true },
'react-dom': { singleton: true }
}
})
]
};shared 配置中的 singleton: true 表示全局只允许存在一个 React 实例,这一点对 React 这类依赖内部全局状态的库至关重要。如果宿主与远程应用各自加载了一份 React,会直接抛出 Invalid Hook Call 错误。而 eager: true 则要求宿主构建时同步打包共享依赖,避免运行时异步加载导致的首屏闪白。
要启用跨项目的缓存融合,还需要在实验特性中打开相关开关,并保证各项目的 webpack 版本与配置指纹一致:
module.exports = {
experiments: {
cacheUnaffected: true, // 允许未受影响的模块直接复用缓存
federationCapabilities: true
},
snapshot: {
module: {
hash: true // 使用内容哈希而非时间戳判断模块是否变更
}
}
};三、融合模式下的 Tree Shaking 与产物优化
融合宇宙带来的另一个直接收益是作用域分析能力的增强。Webpack 5 引入了全新的模块 concatenation 策略,配合 sideEffects 字段,可以在联邦共享的模块上继续做有效的 Tree Shaking。这一点在 Webpack 4 时代是做不到的,当时的联邦模块一旦跨应用共享,基本就退化成了整体引入。
要让 Tree Shaking 正确工作,需要注意两件事。其一,package.json 中必须正确声明副作用信息:
{
"name": "shared-ui",
"version": "1.0.0",
"sideEffects": false,
"main": "./dist/index.js",
"module": "./dist/index.esm.js"
}其二,暴露模块时尽量使用具名导出而非默认导出。默认导出是一个整体对象,打包器无法静态分析出哪些属性被使用;具名导出则可以让未使用的函数在压缩阶段被完整移除。实测在一个中型组件库上,仅这一项改动就让联邦产物的体积下降了约 18%。
此外,融合模式下建议开启确定的模块 ID 与导出顺序,避免因为 ID 漂移导致远程模块的缓存大面积失效:
module.exports = {
optimization: {
moduleIds: 'deterministic',
chunkIds: 'deterministic',
splitChunks: {
chunks: 'all',
maxInitialRequests: 25
}
}
};四、迁移踩坑与升级建议
从 Webpack 4 迁移到融合架构,最常见的坑有三个。第一个是 Node.js polyfill 的移除:Webpack 5 不再自动为 Node 核心模块注入 polyfill,如果代码里引用了 process、path 等模块,需要通过 resolve.fallback 手动指定替代方案,否则构建会直接报错。
第二个坑是 JSON 模块的具名导出。Webpack 5 要求从 JSON 文件导入时必须使用解构语法,import data from './config.json' 之后再访问属性仍然可行,但 import { version } from './config.json' 这种写法在旧版本里是非法的,迁移时可能出现行为差异,建议统一改为解构形式,顺便还能享受 Tree Shaking 的收益。
第三个坑是缓存的团队协作问题。如果团队使用 CI 集群构建,务必确保所有节点的 Node 版本、Webpack 版本以及 cache.version 保持一致,否则会出现缓存互相污染的诡异现象,表现为不同机器构建出的产物不一致。建议在 CI 脚本中加入缓存指纹校验,指纹不匹配时主动清空缓存目录。
总体来看,Fusing Universe 这套融合机制的价值在大型多应用工程中体现得最明显。如果你的项目还停留在单应用阶段,优先把 filesystem 缓存配置好就已经能拿到大部分收益;而如果团队面临多应用共享依赖、构建时间过长的问题,模块联邦加上融合缓存则是一个值得投入的架构升级方向。升级前务必在独立分支上完整回归一遍产物体积与运行时行为,避免线上事故。
Webpack 5Fusing Universe前端构建优化修改时间:2026-09-13 21:30:57