mcpField
R
rspack-split-chunks

rspack-split-chunks

github.com/rstackjs开发97177 次安装6 天前更新
代码仓库

关于 rspack-split-chunks

rspack-split-chunks 是用于建议、审查和调试 Rspack `optimization.splitChunks` 的 Agent 技能,区分项目默认值与生产基线,并围绕具体分块目标提供指导。

主要功能

  1. 01审查 splitChunks 配置
  2. 02说明分块命名与分组
  3. 03默认保留缓存组
  4. 04指导分块大小与缓存
  5. 05借助 stats 分析分块关系

适用场景

  1. 01选择生产环境分块基线
  2. 02排查过大的共享分块
  3. 03减少路由对非必要模块的依赖
  4. 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.*.name
  • enforce: 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 分块,以便在不同路由间复用缓存”

即便如此,也要明确说明取舍:

  • 缓存命中率更高
  • 路由之间的耦合更强
  • 页面可能会获取不会立即执行的模块

审查清单

审查用户的配置时,请明确回答:

  1. 目标是去重、缓存稳定性、请求数量,还是路由隔离?
  2. 与当前配置相比,chunks: "all" 是否是更好的基准?
  3. name 是否意外地将多个候选项变成了一个强制共享分块?
  4. 是否没有充分理由就禁用了 default 或 defaultVendors?
  5. idHint 是否能在不改变分组的情况下满足命名需求?
  6. 与宽泛的手动 vendor/common 分组相比,maxSize 是否更合适?
  7. 最终结果是否仍能确保每个页面只获取可达的分块?

最小化统计设置

如果任务涉及诊断,请索取或生成能够揭示分块关系的统计信息:

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 是更安全的工具。”

评论

支持 Markdown