skills/rspack-split-chunks/SKILL.md
Diagnose 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 caused by `name` and forced chunk merging.
npx skillsauth add rstackjs/agent-skills rspack-split-chunksInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
chunks: "async", but for most production web apps the best starting point is:optimization: {
splitChunks: {
chunks: "all",
},
}
name as a graph-shaping option, not a cosmetic naming option.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.Read references/repo-behavior.md when you need the source-backed rationale.
First identify which problem the user actually has:
splitChunks affects runtime execution orderDo not optimize all of these at once. Pick the primary goal and keep the rest as constraints.
Unless the user already has a measured problem that requires custom grouping, prefer:
optimization: {
splitChunks: {
chunks: "all",
},
}
Why:
If the existing config disables default or defaultVendors, assume that is suspicious until proven necessary.
Check these first:
namecacheGroups.*.nameenforce: truedefault / defaultVendorstest: /node_modules/ rules combined with a single global nameusedExports: falseminSizemaxSize combined with manual global namesname correctlyUse this rule:
name: splitChunks can keep different chunk combinations separate.name: matching modules are merged into the same named split chunk candidate.That means a fixed name: "vendors" or name: "common" is often the real reason a page starts fetching modules from unrelated dependency chains.
Prefer these alternatives before adding name:
name unsetidHint if the goal is filename identity, not grouping identitytest so the cache group is smallermaxSize to subdivide a big chunk instead of forcing a global nameUse a fixed name only when the user explicitly wants one shared asset across multiple entries/routes and accepts the extra coupling.
Rspack's built-in production-oriented behavior depends heavily on these two groups:
default: extracts modules shared by at least 2 chunks and reuses existing chunksdefaultVendors: extracts node_modules modules and reuses existing chunksThese defaults are usually the best balance between dedupe and "only fetch what this page needs".
If you customize cacheGroups, do not casually replace these with one manually named vendor bucket.
chunks: "all" without fear of breaking execution orderWhen a module group is split out, Rspack connects the new chunk back to the original chunk groups. That preserves JavaScript loading semantics.
So:
splitChunks changes chunk topologymaxSize as a refinement toolUse 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".
Important behavior:
maxSize runs after a chunk already existsThis is usually safer than forcing one giant named vendor chunk, because it keeps chunk graph semantics while subdividing hot spots.
usedExports deliberatelyIf the user has multiple runtimes/entries and wants leaner shared chunks per runtime, prefer keeping usedExports enabled.
If they set usedExports: false, expect broader sharing and potentially larger common chunks.
This is still not tree shaking. It only changes how splitChunks groups modules across runtimes.
enforce: true as an escape hatchenforce: true bypasses several normal guardrails. Use it only when the user intentionally wants a split regardless of minSize, minChunks, and request limits.
If a config looks aggressive and hard to explain, check enforce before changing anything else.
Recommend:
optimization: {
splitChunks: {
chunks: "all",
},
}
Avoid:
defaultdefaultVendorsname before measuring a real problemRecommend:
namechunks: "all" if dedupe across initial chunks is still desiredAvoid:
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
chunks: "all",
name: "vendors",
enforce: true
}
}
That pattern often creates one over-shared chunk that many pages must fetch.
Recommend:
name unsetidHintchunkIds: "deterministic" or other stable id strategies elsewhere in the configUse a fixed name only if the user explicitly prefers cache reuse over route isolation.
Recommend:
optimization: {
splitChunks: {
chunks: "all",
maxSize: 200000,
},
}
Then tune:
maxAsyncSize when async chunks are the pain pointmaxInitialSize when first-load pressure matters morehidePathInfo if generated part names should not leak path structureRecommend a named chunk only when the user says something like:
Even then, call out the tradeoff explicitly:
When reviewing a user's config, explicitly answer:
chunks: "all" a better baseline than the current config?name accidentally turn multiple candidates into one forced shared chunk?default or defaultVendors disabled without a strong reason?idHint satisfy the naming goal without changing grouping?maxSize a better fit than a broad manual vendor/common bucket?When the task includes diagnosis, ask for or generate stats that expose chunk relations:
stats: {
chunks: true,
chunkRelations: true,
chunkOrigins: true,
entrypoints: true,
modules: false
}
Then compare:
nameCommon reasons:
minSizeminSizeReductionminChunkschunks / test / cacheGroups do not actually select the same chunk combinationIf the duplicate module is tiny, do not assume this is a bug. Rspack may intentionally keep it in place because splitting it out would create a worse chunk.
No.
splitChunks only changes chunk boundaries and dependency edgesNo.
sideEffects, usedExports, and dead-code eliminationsplitChunks runs later and only reorganizes already-selected modules into chunkssplitChunks.usedExports is only a grouping hint for runtime-specific chunk combinations; it is not tree shaking itselfYes, potentially.
mini-css-extract-plugin or experiments.css can observe changed final CSS order after splitChunks rewrites chunk groupsSee web-infra-dev discussion #12.
chunks: \"all\", keep the default cache groups, and remove name unless you intentionally want forced sharing."name is not just a filename hint in Rspack splitChunks; it changes grouping behavior."splitChunks does not control JS execution order or tree shaking; it only changes chunk topology."splitChunks can affect CSS order in extracted-CSS scenarios, so treat CSS as a separate caveat."maxSize is the safer tool when the problem is one chunk being too large."development
Debug Rstest issues systematically, including performance regressions. First determine whether the slowdown is in build startup or test execution, then run controlled config or code experiments and compare before/after timings.
development
Opinionated Rslib recommendations for modern JS/TS npm package design covering pure ESM, strict TypeScript, explicit exports, small stable APIs, pragmatic dependencies, accurate sideEffects, correct declarations, package validation, provenance, README.md, and AGENTS.md. Use when the user wants to make a JS/TS package more modern, check whether the current package setup is healthy, review package.json/exports/types/dependencies/docs/release readiness, or apply a modern library baseline.
development
Create or update draft GitHub releases for the current project's main GitHub repository, then organize GitHub-generated release notes into user-friendly sections without rewriting release note items. Use for preparing, formatting, categorizing, creating, or updating GitHub release notes or draft releases, including optional highlights when the user asks for them.
tools
Migrate ESLint or other linters to Rslint. Use when asked to replace ESLint flat config, lint scripts, VS Code ESLint settings, inline directives, rules, presets, plugins, or lint dependencies with Rslint equivalents.