$npx -y skills add rstackjs/agent-skills --skill rspack-split-chunksDiagnose and optimize Rspack optimization.splitChunks configuration. Use this when a user wants better production chunking, safer chunks: "all" defaults, fewer duplicated modules, better long-term caching, cacheGroups design help, maxSize tuning, or debugging over-fetch c
| 1 | # Rspack SplitChunks Optimization |
| 2 | |
| 3 | Use this skill when the task is to recommend, review, or debug `optimization.splitChunks`. If you are using ESM library, it's not the same algorithm of this skill. |
| 4 | |
| 5 | ## Default stance |
| 6 | |
| 7 | - Distinguish repo defaults from recommended production baselines. |
| 8 | - Rspack's built-in default is `chunks: "async"`, but for most production web apps the best starting point is: |
| 9 | |
| 10 | ```js |
| 11 | optimization: { |
| 12 | splitChunks: { |
| 13 | chunks: "all", |
| 14 | }, |
| 15 | } |
| 16 | ``` |
| 17 | |
| 18 | - Keep the default cache groups unless there is a concrete reason to replace them. |
| 19 | - Treat `name` as a graph-shaping option, not a cosmetic naming option. |
| 20 | - Do not use `splitChunks` to reason about JavaScript execution order or tree shaking. For JS, chunk loading/execution order is preserved by the runtime dependency graph, and tree shaking is decided elsewhere. |
| 21 | |
| 22 | Read [`references/repo-behavior.md`](references/repo-behavior.md) when you need the source-backed rationale. |
| 23 | |
| 24 | ## What To Optimize For |
| 25 | |
| 26 | First identify which problem the user actually has: |
| 27 | |
| 28 | - duplicated modules across entry or async boundaries |
| 29 | - a route fetching a large shared chunk with mostly unused modules |
| 30 | - too many tiny chunks |
| 31 | - a vendor/common chunk that changes too often and hurts caching |
| 32 | - an oversized async or initial chunk that should be subdivided |
| 33 | - confusion about whether `splitChunks` affects runtime execution order |
| 34 | |
| 35 | Do not optimize all of these at once. Pick the primary goal and keep the rest as constraints. |
| 36 | |
| 37 | ## Workflow |
| 38 | |
| 39 | ### 1. Start from the safest production baseline |
| 40 | |
| 41 | Unless the user already has a measured problem that requires custom grouping, prefer: |
| 42 | |
| 43 | ```js |
| 44 | optimization: { |
| 45 | splitChunks: { |
| 46 | chunks: "all", |
| 47 | }, |
| 48 | } |
| 49 | ``` |
| 50 | |
| 51 | Why: |
| 52 | |
| 53 | - it lets splitChunks dedupe modules across both initial and async chunks |
| 54 | - it still only loads chunks reachable from the current entry/runtime |
| 55 | - it usually avoids loading unnecessary modules better than hand-written global vendor buckets |
| 56 | |
| 57 | If the existing config disables `default` or `defaultVendors`, assume that is suspicious until proven necessary. |
| 58 | |
| 59 | ### 2. Audit the config for high-risk knobs |
| 60 | |
| 61 | Check these first: |
| 62 | |
| 63 | - fixed `name` |
| 64 | - `cacheGroups.*.name` |
| 65 | - `enforce: true` |
| 66 | - disabled `default` / `defaultVendors` |
| 67 | - broad `test: /node_modules/` rules combined with a single global `name` |
| 68 | - `usedExports: false` |
| 69 | - very small `minSize` |
| 70 | - `maxSize` combined with manual global names |
| 71 | |
| 72 | ### 3. Interpret `name` correctly |
| 73 | |
| 74 | Use this rule: |
| 75 | |
| 76 | - No `name`: splitChunks can keep different chunk combinations separate. |
| 77 | - Same `name`: matching modules are merged into the same named split chunk candidate. |
| 78 | |
| 79 | That means a fixed `name: "vendors"` or `name: "common"` is often the real reason a page starts fetching modules from unrelated dependency chains. |
| 80 | |
| 81 | Prefer these alternatives before adding `name`: |
| 82 | |
| 83 | - keep `name` unset |
| 84 | - use `idHint` if the goal is filename identity, not grouping identity |
| 85 | - narrow the `test` so the cache group is smaller |
| 86 | - split one broad cache group into several focused cache groups |
| 87 | - rely on `maxSize` to subdivide a big chunk instead of forcing a global name |
| 88 | |
| 89 | Use a fixed `name` only when the user explicitly wants one shared asset across multiple entries/routes and accepts the extra coupling. |
| 90 | |
| 91 | ### 4. Preserve the built-in cache groups by default |
| 92 | |
| 93 | Rspack's built-in production-oriented behavior depends heavily on these two groups: |
| 94 | |
| 95 | - `default`: extracts modules shared by at least 2 chunks and reuses existing chunks |
| 96 | - `defaultVendors`: extracts `node_modules` modules and reuses existing chunks |
| 97 | |
| 98 | These defaults are usually the best balance between dedupe and "only fetch what this page needs". |
| 99 | |
| 100 | If you customize `cacheGroups`, do not casually replace these with one manually named vendor bucket. |
| 101 | |
| 102 | ### 5. Use `chunks: "all"` without fear of breaking execution order |
| 103 | |
| 104 | When a module group is split out, Rspack connects the new chunk back to the original chunk groups. That preserves JavaScript loading semantics. |
| 105 | |
| 106 | So: |
| 107 | |
| 108 | - `splitChunks` changes chunk topology |
| 109 | - the runtime still guarantees dependency loading/execution order |
| 110 | - if execution order appears broken, look for other causes first |
| 111 | - this statement is about JavaScript, not CSS order |
| 112 | |
| 113 | ### 6. Use `maxSize` as a refinement tool |
| 114 | |
| 115 | Use `maxSize`, `maxAsyncSize`, or `maxInitialSize` when the problem is "this shared chunk is too large", not when the problem is "I need a stable vendor chunk name". |
| 116 | |
| 117 | Important behavior: |
| 118 | |
| 119 | - `maxSize` runs after a chunk already exists |
| 120 | - the split is deterministic |
| 121 | - modules are grouped by path-derived keys and split near low-similarity boundaries |
| 122 | - similar file paths tend to stay together |
| 123 | |
| 124 | This is usually safer than forcing on |