Webpack 5 在模块打包架构上做了大量底层重构,其中较为引人注目的是名为 Gravel Universe(碎石宇宙)的实验特性。它并不是官方文档中高频宣传的卖点,却在复杂工程里展现出独特的构建优化能力。简单来说,碎石宇宙是一种将完整依赖关系图拆分为大量微小、可独立追踪的碎石单元的机制,每个单元对应一组具有相似变更节奏的模块集合。

碎石宇宙的设计原理与依赖图重构
在 Webpack 传统的依赖解析中,所有模块被纳入一张巨大的有向图,任何边缘模块的改动都可能引发整图哈希重算。Gravel Universe 的核心思路是引入一层中间抽象:构建器先扫描全部模块,根据静态导入关系、文件修改时间以及包管理器提供的依赖元数据,将模块聚类为多个碎石单元。这些单元之间尽量弱耦合,单元内部则保持高内聚。
这种重构带来的直接好处是缓存粒度变细。过去使用 cache 配置做持久化时,往往因为某个工具函数文件变更,导致整个 vendor 缓存失效。在碎石宇宙下,仅包含该函数的碎石单元需要重新生成,其余单元直接从磁盘缓存读取。底层通过 contentHash 与 gravelId 双重索引实现快速定位,避免了全量遍历。
从编译器视角看,碎石宇宙还调整了 NormalModule 与 Dependency 的绑定方式。原本一对一的依赖记录在实验分支中被替换为多对多的碎石映射表,这使得 tree-shaking 阶段能更精准地判断某段代码是否属于死代码。以下示例展示了在配置中开启该特性的最小代码:
const path = require('path');
module.exports = {
mode: 'development',
entry: './src/index.js',
experiments: {
gravelUniverse: true
},
cache: {
type: 'filesystem',
buildDependencies: {
config: [path.resolve(__dirname, 'webpack.config.js')]
}
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
与传统分包及 Module Federation 的对比
很多团队习惯用 splitChunks 按 node_modules 或异步入口做切割,这种方式直观但缺乏动态适应性。碎石宇宙并不替代 splitChunks,而是工作在更下层。前者决定文件如何拆成多个 chunk,后者决定模块图如何拆成多个缓存域。当项目引入 Module Federation 实现微前端时,远端容器加载的模块也可被标记为独立碎石,减少本地重建时的跨域依赖计算。
在 monorepo 场景中,多个子包互相引用是常态。传统方案里,修改子包 A 的按钮组件,可能让引用了 A 的所有应用重新打包。碎石宇宙通过引用频次分析,把按钮组件归为稳定碎石,只要其导出签名未变,主应用的对应碎石就命中缓存。我们对比了某中型项目在三种策略下的冷构建耗时:
| 策略 | 冷启动耗时(s) | 缓存命中率 |
|---|---|---|
| 默认配置 | 58 | 12% |
| splitChunks 优化 | 41 | 35% |
| 开启 Gravel Universe | 27 | 68% |
数据表明,碎石宇宙在缓存利用率上优势明显,但也需注意它会增加少量图分析开销。对于模块数低于五百的小型项目,带来的收益可能覆盖不了初始化成本,因此官方将其放在 experiments 中而非默认开启。
落地实践与常见误区
要在生产环境稳妥使用碎石宇宙,建议先通过 CI 跑双配置对比,观察 gravelUniverse 开启前后产物体积与构建日志的差异。一个常见误区是认为开启后就能彻底关闭 splitChunks,实际上两者职责不同,关闭后者会导致浏览器并行请求数失控。正确做法是保留基础分包规则,让碎石宇宙处理缓存域划分。
另一个容易被忽略的点是 cache 目录的清理策略。由于碎石单元数量多,文件系统缓存可能积累大量小文件。应在部署脚本中加入定期清除 node_modules/.cache/webpack 的逻辑,或配置 cache.maxAge 控制失效周期。下面代码演示了带最大存活时间的缓存配置:
module.exports = {
experiments: {
gravelUniverse: true
},
cache: {
type: 'filesystem',
maxAge: 1000 * 60 * 60 * 24 * 7,
storage: {
type: 'filesystem',
directory: '.webpack_cache'
}
}
};
此外,使用 TypeScript 的项目需确保 ts-loader 或 babel 的转译结果具备稳定内容哈希,否则碎石单元会因注释中的时间戳而频繁失效。可在 babel 配置中关闭文件名注入,并在 webpack 的 module.unsafeCache 中补充 gravel 相关白名单,从而让碎石宇宙真正发挥持久化加速价值。
Webpack_5Gravel_Universe模块打包修改时间:2026-08-16 12:44:26