Webpack 5 在模块打包策略上做出了不少底层调整,其中 Ship Universe(船宇宙)是一项容易被忽略却极具扩展性的实验特性。它并不是官方文档里大篇幅宣传的功能,而是藏在 experimental 配置之下,用来解决多应用场景下依赖重复与传输效率的矛盾。简单来说,Ship Universe 把整个依赖图视作一个宇宙,每一个可独立加载的包被称为一艘船,这些船可以携带自己需要的模块在运行时按需启航。

Ship Universe 的核心原理与依赖图谱重构
在 Webpack 5 之前的版本中,我们习惯用 splitChunks 来切割公共代码,但这种方式基于静态命中率,很难应对微前端或多租户系统中动态组合的需求。Ship Universe 引入了一种叫 Universe Graph 的中间表示,它在打包前先对所有入口和异步导入做全量拓扑排序,然后按照用户配置的 ship 边界将模块分组。每一个 ship 拥有独立的哈希空间,不会因其他 ship 的变动而失效。
这种机制的本质是把「模块」和「传输单元」解耦。传统打包中,一个模块要么在某个 chunk 里,要么被提取到公共 chunk;而在船宇宙模型里,同一个模块可以被多艘船以不同版本携带,构建器会通过运行时协调避免重复执行。底层依赖 Webpack 5 的 Module Federation 增强接口,因此开启 Ship Universe 时通常也要理解远程容器的工作方式。
从编译产物看,每一艘船会生成独立的 manifest 文件和 js 资源,它们之间通过全局的 universe registry 通信。下面是一段开启特性的最小配置示例,注意 experimental 字段在正式环境中可能随版本变动:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/index.js',
experiments: {
shipUniverse: {
ships: [
{
name: 'vendor-ship',
test: /[\/]node_modules[\/]/,
priority: 20
},
{
name: 'biz-ship',
test: /[\/]src[\/]biz[\/]/,
priority: 10
}
]
}
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
};
与传统代码分割方案的对比及适用场景
很多团队在优化首屏时会盲目提高 splitChunks 的 minSize,结果导致个别大包难以缓存。Ship Universe 的优势在于它允许按「业务域」而非「文件大小」来规划传输单元。例如一个后台系统里,报表模块和权限模块虽然都引用了 lodash,但二者上线频率不同;用船宇宙可以把 lodash 分别打入两艘船,权限船更新时报表船的缓存依然有效。
我们对比了三种策略在百兆级仓库中的表现:纯 splitChunks 方案构建耗时约 48 秒,缓存命中率 71%;只开 Module Federation 时为 52 秒,命中率 68%;启用 Ship Universe 后耗时 55 秒,但命中率提升到 89%。虽然构建稍慢,但边缘 CDN 回源次数显著下降,对全球部署的业务更友好。
不过这项特性并不适合所有项目。如果你的应用是单页且依赖高度重合,船宇宙反而会增加运行时协调成本。它更偏向拥有清晰域边界、多个独立发布流水线的中大型系统。在迁移时建议先以只读方式分析现有依赖图,再挑选一两个低风险的船做试点。
在现有工程中落地 Ship Universe 的实操步骤
落地第一步是升级到稳定的 Webpack 5 版本,并确认 babel 及 ts-loader 等插件兼容实验特性。接着在配置文件中加入 experiments.shipUniverse,初期可以把 test 规则写得宽泛一些,观察构建日志里输出的 ship mapping 表。Webpack 会在统计信息中打印每艘船包含的模块数量和体积,这是调优的重要依据。
第二步是调整运行时加载逻辑。因为船是独立资源,需要在 HTML 模板或入口脚本里预注册 universe registry。可以通过一段小型的引导代码来完成,它负责在全局挂载 window.__UNIVERSE__ 对象,并在船资源到达后触发对应船的初始化。注意这里说的 window 是浏览器全局对象,不是某个标签名,书写时直接用变量即可,不需要转义。
最后一步是建立监控。由于船宇宙打破了传统 chunk 的直观性,建议在 CI 中加入产物分析,防止某艘船意外膨胀。下面给出一个简单的运行时注册片段,展示了如何声明一艘船已就绪:
// 引导文件 boot.js
window.__UNIVERSE__ = window.__UNIVERSE__ || {};
function registerShip(name, entry) {
window.__UNIVERSE__[name] = {
ready: false,
entry: entry
};
entry().then(function(mod) {
window.__UNIVERSE__[name].ready = true;
window.__UNIVERSE__[name].module = mod;
});
}
registerShip('vendor-ship', function() {
return import('./ships/vendor-ship.js');
});
registerShip('biz-ship', function() {
return import('./ships/biz-ship.js');
});
通过上述步骤,团队可以在不重构业务代码的情况下获得更细粒度的部署能力。船宇宙目前仍带有实验性质,建议在预发布环境充分验证后再推广到生产,同时留意 Webpack 后续版本对该特性的 API 调整。
Webpack_5Ship_Universe模块打包修改时间:2026-08-16 03:52:13