“物种宇宙”这个说法最初来自 Webpack 核心作者 Tobias Koppers 在描述 Webpack 5 生态愿景时的比喻:不同的构建产物、不同的团队、不同的技术栈,就像宇宙中不同的物种,它们彼此独立演化,却又能通过统一的协议互相协作。这个愿景落到具体实现上,就是模块联邦、持久化缓存、Asset Module 这一批新特性。理解了这一点,再看 Webpack 5 的 Release Notes 就不会觉得是一堆零散功能的堆砌,而是一套完整的生态设计。

模块联邦:物种之间如何共享基因
模块联邦是 Webpack 5 里最亮眼的能力,它解决的是一个老问题:两个独立开发、独立部署的前端应用,如何在运行时共享组件或者依赖,而不是各自打包一份。在没有联邦之前,我们通常靠 externals 加 CDN 的方式抽公共依赖,或者用 npm 包的形式发组件,但前者维护成本高,后者发版节奏完全耦合。
联邦的核心概念有两个角色:host 是消费方,remote 是提供方。remote 通过 exposes 把自己内部的模块暴露出去,host 通过 remotes 声明要引用哪些远程模块。看一个最小配置:
// remote 端(组件提供方)webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'widgetApp',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.jsx',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
],
};// host 端(消费方)
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'shellApp',
remotes: {
widgetApp: 'widgetApp@http://cdn.ipipp.com/remote/remoteEntry.js',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
}),
],
};配置里最值得注意的是 shared 配置项。它声明了共享依赖的协商规则,singleton 设为 true 表示整个页面只允许存在一个 React 实例,否则多个应用各自实例化 React 会导致 hooks 报错。联邦会在运行时对比 host 和 remote 各自持有的依赖版本,取满足语义化范围的最高版本加载,这就是所谓的“基因交换”机制。
在业务代码里,host 侧使用远程组件的方式和平常的动态导入没有区别:
// host 中直接引用 remote 暴露的组件
const RemoteButton = React.lazy(() => import('widgetApp/Button'));
function App() {
return (
<React.Suspense fallback={<div>加载中...</div>}>
<RemoteButton onClick={() => alert('来自远程的按钮')} />
</React.Suspense>
);
}这里必须用懒加载的写法,因为远程模块的加载天然是异步的,remoteEntry.js 需要在运行时通过网络请求拉取。这也是联邦方案的一个隐性成本:首屏会多出一次网络请求,网络不稳定时需要设计降级方案。
持久化缓存与构建性能:让二次构建快到无感
如果说模块联邦解决的是运行时生态问题,那持久化缓存解决的就是开发体验问题。Webpack 4 时代大家普遍用 hard-source-webpack-plugin 来做磁盘缓存,但那个插件经常出现缓存失效甚至构建错乱的情况。Webpack 5 把缓存机制收进了内核,配置非常简单:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 配置文件变化时缓存自动失效
config: [__filename],
},
},
};启用之后,首次冷构建会把每个模块的编译结果、依赖图、resolve 结果全部写入 node_modules/.cache 目录,第二次构建直接读取缓存,只对发生变化的模块重新编译。在中大型项目上,二次构建速度普遍能提升百分之七十以上,改动单个文件时的增量构建经常可以进入秒级。
除了缓存,Webpack 5 在构建性能上还做了几件事。一是长期缓存的算法改进,新的确定性 chunk、module id 和导出名称生成策略,让 hash 值更稳定,业务代码改动不会导致公共库的缓存失效。二是压缩工作移交,生产环境默认内置了 TerserWebpackPlugin 的并行压缩,同时官方推荐把压缩和语法转换尽量交给 SWC 或 esbuild 这类原生工具链,通过 thread-loader 的替代方案减少 JS 单线程的开销。三是 Node.js polyfill 的移除,Webpack 5 不再自动为 core-js 风格的浏览器兼容注入垫片, bundle 体积和构建时间都因此受益,代价是引用了 Node 内置模块的老代码需要手动处理。
Asset Module 与 Tree Shaking:物种自身的进化
回到“物种”这个比喻,联邦是物种之间的协作,而每个物种自身也在进化。Webpack 5 内置了资源处理模块 Asset Module,替代了 file-loader、url-loader、raw-loader 这一套老插件。以前处理一张图片要根据大小判断转 base64 还是拷贝文件,现在只需要一行规则:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|webp|svg)$/i,
type: 'asset', // 自动按大小选择 asset/inline 或 asset/resource
parser: {
dataUrlCondition: { maxSize: 8 * 1024 },
},
},
],
},
};type 字段有四个值可选:asset/resource 输出独立文件,asset/inline 转成 data URI,asset/source 导出源文本,asset 则在两者之间按 dataUrlCondition 自动决策。统一成内置能力之后,资源处理的配置更短,构建链路更少一层插件开销,而且和缓存机制的配合天然更好。
Tree Shaking 方面的改进同样实在。Webpack 5 实现了真正意义上的嵌套导出剔除,比如你从一个工具库里只用了 debounce,即使该库的入口文件重导出了一百个函数,未被使用的部分都能被逐层摇掉。配合 package.json 里的 sideEffects 字段声明,产物体积在不少实际项目里能下降百分之十到二十。另外新增的顶层 await 支持、更智能的代码分割策略(比如根据下载优先级自动拆分 async chunk),都让“物种”自身的打包质量更进一步。
总体来看,Webpack 5 的这批特性确实配得上“物种宇宙”的说法:联邦定义了跨应用的协作协议,持久化缓存重建了构建性能的底线,Asset Module 和 Tree Shaking 则把单应用打包做到了新水准。如果你的项目还是 Webpack 4,升级时需要重点检查 Node polyfill 的依赖和废弃插件的替换,迁移工作通常一两天可以完成,换来的是长期可维护的工程基础设施。
Webpack 5Module Federation前端工程化修改时间:2026-09-11 22:40:46