关于 rspack-split-chunks
rspack-split-chunks 是用于建议、审查和调试 Rspack `optimization.splitChunks` 的 Agent 技能,区分项目默认值与生产基线,并围绕具体分块目标提供指导。
主要功能
- 01审查 splitChunks 配置
- 02说明分块命名与分组
- 03默认保留缓存组
- 04指导分块大小与缓存
- 05借助 stats 分析分块关系
适用场景
- 01选择生产环境分块基线
- 02排查过大的共享分块
- 03减少路由对非必要模块的依赖
- 04审查缓存与分块命名方案
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ rstackjs/ agent-skills --skill rspack-split-chunks安装后在 Claude Code 中输入/rspack-split-chunks确认已加载。
附带文件references/repo-behavior.md
详细介绍
Rspack SplitChunks 优化
在需要推荐、审查或调试 optimization.splitChunks 时使用此技能。如果你使用的是 ESM 库,其算法与此技能不同。
默认立场
- 区分仓库默认配置与推荐的生产环境基线。
- Rspack 内置的默认值是
chunks: "async",但对于大多数生产环境 Web 应用,最佳起点是:
optimization: {
splitChunks: {
chunks: "all",
},
}
- 保留默认缓存组,除非有具体理由需要替换。
- 将
name视为影响图结构的选项,而非仅用于美化名称的选项。 - 不要用
splitChunks来推断 JavaScript 执行顺序或摇树优化。对于 JS,分块加载和执行顺序由运行时依赖图保持,摇树优化则由其他机制决定。
需要基于源代码的依据时,请阅读 references/repo-behavior.md。
优化目标
首先确定用户实际遇到的问题:
- 入口或异步边界之间存在重复模块
- 路由获取了大型共享分块,其中大部分模块并未使用
- 分块过多且过小
- vendor/common 分块变化过于频繁,影响缓存
- 异步分块或初始分块过大,需要进一步拆分
- 不清楚
splitChunks是否会影响运行时执行顺序
不要试图同时优化所有这些问题。选定主要目标,并将其余问题作为约束。
工作流程
1. 从最稳妥的生产环境基线开始
除非用户已经测出需要自定义分组的问题,否则优先采用:
optimization: {
splitChunks: {
chunks: "all",
},
}
原因:
- 允许 splitChunks 在初始分块和异步分块之间去重模块
- 仍然只会加载当前入口/运行时可访问的分块
- 与手动编写的全局 vendor 分组相比,通常更能避免加载不必要的模块
如果现有配置禁用了 default 或 defaultVendors,在证明其必要之前,应先视为可疑配置。
2. 审查配置中的高风险选项
优先检查以下内容:
- 固定的
name cacheGroups.*.nameenforce: true- 禁用了
default/defaultVendors - 宽泛的
test: /node_modules/规则与单个全局name组合使用 usedExports: false- 非常小的
minSize maxSize与手动设置的全局名称组合使用
3. 正确理解 name
遵循以下规则:
- 不设置
name:splitChunks 可以将不同的分块组合分开保留。 - 使用相同的
name:匹配的模块会合并到同一个具名拆分分块候选项中。
这意味着,固定设置 name: "vendors" 或 name: "common",往往才是导致某个页面开始获取来自无关依赖链的模块的真正原因。
在添加 name 之前,优先考虑以下替代方案:
- 不设置
name - 如果目标是标识文件名而非分组标识,则使用
idHint - 缩小
test的匹配范围,让缓存组更小 - 将一个宽泛的缓存组拆分为多个针对性更强的缓存组
- 依靠
maxSize拆分大型分块,而不是强制使用全局名称
只有当用户明确希望多个入口/路由共用一个资源,并接受由此带来的额外耦合时,才使用固定的 name。
4. 默认保留内置缓存组
Rspack 面向生产环境的内置行为很大程度上依赖以下两个组:
default:提取至少由 2 个分块共享的模块,并复用现有分块defaultVendors:提取node_modules模块,并复用现有分块
这些默认配置通常能在去重与“只获取此页面所需内容”之间取得最佳平衡。
如果自定义 cacheGroups,不要轻率地用一个手动命名的 vendor 组替换这些默认组。
5. 使用 chunks: "all",无需担心执行顺序被打乱
拆分出模块组时,Rspack 会将新分块重新连接到原始分块组,从而保留 JavaScript 加载语义。
因此:
splitChunks会改变分块拓扑结构- 运行时仍会保证依赖项的加载和执行顺序
- 如果执行顺序似乎被打乱,请先排查其他原因
- 此处的说法针对 JavaScript,不涉及 CSS 顺序
6. 将 maxSize 用作细化工具
当问题是“这个共享分块太大”时,使用 maxSize、maxAsyncSize 或 maxInitialSize;当问题是“我需要一个稳定的 vendor 分块名称”时,不要使用它们。
重要行为:
maxSize会在分块已存在后运行- 拆分具有确定性
- 模块会按从路径派生的键分组,并在相似度较低的边界附近拆分
- 文件路径相似的模块通常会归在一起
这通常比强行创建一个巨大的命名 vendor 分块更安全,因为它能保留分块图语义,同时细分热点区域。
7. 有意使用 usedExports
如果用户有多个运行时或入口,并希望每个运行时的共享分块更精简,建议保持启用 usedExports。
如果他们设置 usedExports: false,则应预期共享范围更广,而且公共分块可能更大。
这仍然不是 tree shaking。它只会改变 splitChunks 如何跨运行时对模块分组。
8. 将 enforce: true 视为应急手段
enforce: true 会绕过多个常规限制。只有当用户明确希望无论 minSize、minChunks 和请求限制如何都进行拆分时,才使用它。
如果某项配置看起来过于激进且难以解释,请先检查 enforce,再考虑更改其他内容。
按目标给出的建议
改善默认的生产环境分块
建议:
optimization: {
splitChunks: {
chunks: "all",
},
}
避免:
- 禁用
default - 禁用
defaultVendors - 未衡量实际问题前就添加
name
避免获取非必要模块
建议:
- 移除固定的
name - 保持缓存组范围较窄
- 如果仍希望在初始分块间去重,则保留
chunks: "all" - 每次更改后检查哪些路由现在依赖共享分块
避免:
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: "all",
name: "vendors",
enforce: true
}
}
这种模式通常会创建一个共享范围过大的分块,导致许多页面都必须获取它。
改善缓存,同时避免过度合并
建议:
- 不设置
name - 使用
idHint - 在配置的其他位置保留
chunkIds: "deterministic"或其他稳定的 ID 策略 - 仅当包边界稳定且重要时,才将宽泛的分组拆分为更小、更聚焦的分组
只有在用户明确表示更看重缓存复用而非路由隔离时,才使用固定的 name。
拆分大型共享分块
建议:
optimization: {
splitChunks: {
chunks: "all",
maxSize: 200000,
},
}
然后调整:
- 异步分块是主要问题时,调整
maxAsyncSize - 首次加载压力更重要时,调整
maxInitialSize - 如果生成的分块名称不应暴露路径结构,则启用
hidePathInfo
保留有意共享的分块
只有当用户提出类似以下需求时,才建议使用命名分块:
- “所有页面都应共享一个 React vendor 资源”
- “我希望使用一个 framework 分块,以便在不同路由间复用缓存”
即便如此,也要明确说明取舍:
- 缓存命中率更高
- 路由之间的耦合更强
- 页面可能会获取不会立即执行的模块
审查清单
审查用户的配置时,请明确回答:
- 目标是去重、缓存稳定性、请求数量,还是路由隔离?
- 与当前配置相比,
chunks: "all"是否是更好的基准? name是否意外地将多个候选项变成了一个强制共享分块?- 是否没有充分理由就禁用了
default或defaultVendors? idHint是否能在不改变分组的情况下满足命名需求?- 与宽泛的手动 vendor/common 分组相比,
maxSize是否更合适? - 最终结果是否仍能确保每个页面只获取可达的分块?
最小化统计设置
如果任务涉及诊断,请索取或生成能够揭示分块关系的统计信息:
stats: {
chunks: true,
chunkRelations: true,
chunkOrigins: true,
entrypoints: true,
modules: false
}
然后比较:
- 哪些入口点引用了哪些共享分块
- 某项更改是否为入口点添加了指向较大共享分块的新依赖边
- 是否存在仅因固定的
name而产生的大型共享分块
常见问题
为什么我仍然会看到重复模块?
常见原因:
- 共享候选项太小,提取它无法满足
minSize - 候选项不满足
minSizeReduction - 不满足
minChunks - 请求预算限制拒绝了拆分
chunks/test/cacheGroups实际上没有选中相同的分块组合
如果重复模块很小,不要以为这是 bug。Rspack 可能会有意将它保留在原处,因为将它拆分出去会产生更差的分块。
splitChunks 会影响 JS 执行顺序吗?
不会。
splitChunks只会更改分块边界和依赖边- JS 加载和执行顺序属于运行时问题
- 如果出现 JS 顺序问题,请优先检查运行时/引导代码、副作用或应用代码
splitChunks 会影响摇树优化吗?
不会。
- 摇树优化由模块图分析控制,例如
sideEffects、usedExports和死代码消除 splitChunks在之后运行,只会将已选中的模块重新组织到各个分块中splitChunks.usedExports只是针对特定运行时分块组合的分组提示;它本身并非摇树优化
splitChunks 会影响 CSS 顺序吗?
可能会。
- 此注意事项适用于 CSS 顺序,而非 JS 执行顺序
mini-css-extract-plugin或experiments.css等提取 CSS 的流程可能会因 splitChunks 改写分块组而观察到最终 CSS 顺序发生变化- 如果 CSS 顺序很关键,请谨慎将顺序敏感的样式拆分到不同分块中
参见 web-infra-dev discussion #12。
可直接复用的简要结论
- “保留
chunks: \"all\"和默认缓存组,除非你有意强制共享,否则移除name。” - “在 Rspack splitChunks 中,
name不只是文件名提示;它会改变分组行为。” - “
splitChunks不会控制 JS 执行顺序或摇树优化;它只会改变分块拓扑结构。” - “在提取 CSS 的场景中,
splitChunks可能会影响 CSS 顺序,因此应将 CSS 视为单独的注意事项。” - “如果问题在于单个分块过大,
maxSize是更安全的工具。”