build-tooling-vite-webpack-review
Reviews Vite and Webpack build/chunking configuration and bundle-size composition for duplicate dependencies, unsplit vendor chunks, and tree-shaking failures, always version-labeling config since Vite 8 replaced Rollup-era manualChunks with Rolldown-based codeSplitting.
Install
npx skills add https://github.com/VincentChuWaiChow/vanguard-frontier-agentic/tree/master/skills/frontend/build-tooling-vite-webpack-review
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install vincentchuwaichow-vanguard-frontier-agentic@llmmart
git clone https://github.com/VincentChuWaiChow/vanguard-frontier-agentic.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole vincentchuwaichow/vanguard-frontier-agentic collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Build Tooling (Vite/Webpack) Review
Purpose
Bundler config advice that doesn't match the installed major version is worse than no advice — it produces a config diff that silently no-ops, throws at build time, or (worst case) applies to the wrong bundler engine entirely. Vite ships two build engines depending on version and config shape (Rollup-backed rollupOptions, or Rolldown-backed rolldownOptions), and Vite 8 removed the object form of manualChunks outright. This skill reviews Vite/Webpack build and chunking configuration itself — the config file, not the resulting bundle bytes — and treats the target bundler's exact major version as a required input, not an assumption, before proposing any config diff.
When to use
Use this skill when the user asks to:
- review or tune Vite
build.rollupOptions/build.rolldownOptionsor Webpackoptimization.splitChunkschunking configuration, - diagnose a duplicate-dependency-across-chunks defect or an unsplit vendor chunk caused by chunking config (not by application-level import boundaries),
- evaluate a proposed bundler migration (Webpack to Vite, Rollup-backed Vite to Rolldown-backed Vite, or a Vite major-version upgrade) for build-time and config-compatibility impact,
- diagnose a tree-shaking failure that traces back to bundler/build config (module format,
sideEffectsfield interaction with the bundler, barrel-file re-exports defeating static analysis) rather than to source-code side effects, - set up or review a CI bundle-size budget gate at the build-tool level (build script, CI job config).
When NOT to use
- Setting or auditing the numeric size budget itself, ranking analyzer contributors by byte weight vs. execution cost, or deciding route/component-level code-splitting boundaries — hand off to
bundle-budget-code-splitting-reviewfor that; this skill reviews the bundler config mechanism, not the budget methodology or split-boundary decision. - Verifying that tree-shaking actually eliminated dead code via a before/after byte diff, or auditing
sideEffects: falsecorrectness on a specific package — hand off totree-shaking-dead-code-reviewfor that; this skill only flags build-config patterns (barrel imports, module-format mismatches) that are known to defeat tree-shaking, it does not verify the outcome. - Non-bundler build tooling (Babel-only transpilation pipelines with no bundling step, TypeScript
tsc-only builds, esbuild/Rolldown used as a library outside Vite/Webpack) — different config surface, not in scope here.
Context7 Documentation Protocol
Vite's build-engine and chunking API surface changed between major versions — do not prescribe a config from memorized training data.
- Call
ToolSearchwith query"context7"(or"select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs") to load the Context7 tools if not already loaded this session. - Call
mcp__Context7__resolve-library-idfor each bundler in scope (/vitejs/vite, Webpack,/rollup/rollup, and/rolldown/rolldownif the project's Vite build is Rolldown-backed) before prescribing any chunking configuration. - Call
mcp__Context7__query-docsfor the specific mechanism — e.g. "rollupOptions.output.manualChunks vs rolldownOptions.output.codeSplitting", "splitChunks cacheGroups defaults", "manualChunks object form vs function form" — before ruling on it. Do this per review; do not reuse a prior session's memory of bundler internals. - Known version-sensitive facts verified via Context7 as of this skill's
updateddate:- Vite's migration guide documents that the object form of
build.rollupOptions.output.manualChunkswas removed, and the function form was deprecated; the replacement isbuild.rolldownOptions.output.codeSplitting, which takes agroupsarray of{ name, test }entries (Rolldown's declarative chunk-grouping API). Do not hand a project on that config path amanualChunks: { vendor: [...] }object-form snippet — it will not apply. - Rollup itself (used directly, or via Vite versions/configs that still route through
rollupOptions) continues to support both the object form and function form ofoutput.manualChunksper Rollup's own configuration docs — the removal is specific to Vite's option surface and its migration path toward Rolldown, not a Rollup-wide deprecation. Confirm which bundler engine actually processes the config (rollupOptionsvsrolldownOptionskey) before applying either party's rules. - Vite ships a built-in
splitVendorChunkPluginthat composes with function-formmanualChunksbut explicitly logs a warning and no-ops when combined with the object form — treat "vendor chunk isn't splitting and there's a console warning aboutsplitVendorChunk" as a symptom of this specific interaction, not a generic bug report.
- Vite's migration guide documents that the object form of
- Webpack's
optimization.splitChunkssurface (cacheGroups,chunks: 'all' | 'async' | 'initial',minSize,maxInitialRequests) is comparatively stable across recent majors per Context7-grounded docs, including its documented defaults (minSize: 20000,defaultVendors/defaultcache groups withpriority: -10/-20) — still confirm the installed Webpack major before asserting a specific default, since defaults have shifted across major versions historically. - If Context7 is unavailable or returns no relevant match for the installed bundler, fall back to
official_docsand mark the claimdocumentation-based (Context7 unavailable)rather than presenting it as freshly verified. - Never invent a bundler config key, CLI flag, or plugin option that no queried source confirms.
Lean operating rules
- Confirm the installed Vite major version and which output-options key (
rollupOptionsvsrolldownOptions) the project's own config already uses before proposing a diff — these are two different bundler engines with two different chunking APIs, and giving the wrong era's config is a concrete, verified failure, not a style choice. - Distinguish Vite's dev-server behavior (native ESM, no bundling, chunking config irrelevant) from its production build behavior (bundled via Rollup or Rolldown depending on version/config); every recommendation in this skill applies only to the production build path.
- Flag barrel-file (
index.tsre-export) imports and wildcard imports of large libraries (icon sets, date libraries, utility libraries) as build-config-relevant tree-shaking risks when the project's module format or bundler settings can't statically resolve them — name the specific named/subpath-import fix, and hand off totree-shaking-dead-code-reviewto verify the byte-level outcome. - Treat a duplicate-dependency-across-chunks finding as a chunk-grouping config defect (fix
manualChunks/codeSplitting/cacheGroups), not an application-code defect — do not propose restructuring import statements to solve what a config change solves more directly. - Require a stated measured baseline (current bundle output, build time) before endorsing any bundler or bundler-major migration, plus a rollback path (pinned lockfile entry, ability to revert the config key).
- Recommend a CI bundle-size budget gate at the build-tool/CI-job level for any budget-critical route that lacks one, rather than treating build-config review as a one-time audit — but define the numeric budget itself only via
bundle-budget-code-splitting-review. - Do not evaluate bundle-size numbers as if they were field/RUM Core Web Vitals data; a build's stats output is lab data from a CI build unless explicitly stated otherwise.
- Never accept "it built without errors" as evidence a chunking config change is correct — a removed or renamed option key can silently no-op (see the Vite 8
manualChunksobject-form removal) rather than error.
References
Load these only when needed:
- Vite chunking config reference — use when reviewing or writing
rollupOptions.output.manualChunksorrolldownOptions.output.codeSplitting, or diagnosing which bundler engine a Vite config actually invokes. - Webpack splitChunks reference — use when reviewing or writing
optimization.splitChunks,cacheGroups, orruntimeChunkconfiguration. - Migration and config-diff safety — use before endorsing a bundler migration or a chunking-config change, to confirm baseline capture, rollback path, and the verification steps that must precede calling a config change complete.
Response minimum
Return, at minimum:
- the bundler and confirmed major version (and, for Vite, the confirmed output-options key:
rollupOptionsorrolldownOptions) the guidance targets, - build-config findings (duplicate-dependency chunk-grouping defects, config keys that no longer apply for the confirmed version, barrel-file/module-format patterns defeating tree-shaking) with file/line evidence,
- proposed chunking/config diff (not applied), labeled lab vs field for any performance number cited,
- evidence level (
live evidence,user-provided sanitized evidence,documentation-based, orinference), - migration caveat (baseline + rollback) if a bundler or bundler-major change is recommended, and a handoff note to
bundle-budget-code-splitting-reviewortree-shaking-dead-code-reviewif the user's actual question is budget-setting or tree-shaking verification rather than config review.
Files (vanguard-frontier-agentic)
-
references
-
migration-and-config-diff-safety.md 5.1 KB
# Migration and Config-Diff Safety Use this reference before endorsing any bundler migration (Webpack to Vite, Rollup-backed Vite to Rolldown-backed Vite, or a Vite/Webpack major-version bump) or before calling any chunking-config change complete. ## What people get wrong The naive assumption is: > The build succeeded with the new config, so the migration/change is done. Wrong on two counts. First, a removed-but-not-erroring option (see `references/vite-chunking-config.md` on the Vite `manualChunks` object-form removal) means a "successful" build can silently be running a different chunking strategy than the team believes — success is not evidence of equivalence. Second, "the build succeeded" says nothing about whether the resulting bundle composition, chunk count, or build time actually moved in the intended direction, or whether a rollback path exists if it didn't. ## Non-negotiable rules 1. **Capture a measured baseline before any config or bundler change is applied.** At minimum: current chunk list with sizes (from the existing build's stats/manifest output), current total build time, and current bundler/major version. Without this, "did the migration help" is unanswerable after the fact. 2. **State the rollback path explicitly before endorsing the change.** For a config-only change, this is typically "revert this diff, config keys are additive/isolated." For a bundler-major or engine-swap migration (e.g., adopting Rolldown-backed Vite), confirm whether the change is a single reversible config-key swap or whether it also touches lockfile-pinned plugin versions that may not be compatible with the prior engine — a plugin written against Rollup's plugin API is not guaranteed compatible with Rolldown's plugin API even where the two claim general compatibility; confirm via Context7 rather than assuming. 3. **Never treat "build succeeded, no errors" as proof a chunking-config change took effect.** Require a chunk-list diff (names, count, sizes) between before and after. An unchanged chunk list after an intentional config edit means the edit likely didn't apply — check for the specific silent-no-op patterns named in the Vite and Webpack references before assuming the config is simply already optimal. 4. **Do not endorse a bundler migration on build-time or DX grounds alone without also stating the bundle-composition impact**, or explicitly noting that composition impact is unverified. A faster build with an unreviewed change in chunk boundaries can trade build-time wins for runtime request-count or duplicate-dependency regressions — that trade-off must be named, not silently accepted. 5. **Flag any migration proposal that lacks a stated baseline or rollback path as incomplete**, regardless of how confident the proposal otherwise sounds — this is the same discipline this skill applies to config-key claims: unverified confidence is not evidence. 6. **When the user's actual goal is a numeric bundle-size budget or code-splitting boundary decision** (not a config-mechanism review), hand off to `bundle-budget-code-splitting-review` rather than expanding this skill's scope to cover budget methodology. 7. **When the user's actual goal is verifying that a config change eliminated dead code** (byte-level tree-shaking outcome, `sideEffects` correctness), hand off to `tree-shaking-dead-code-review` rather than asserting a tree-shaking outcome from config inspection alone — this skill can flag config patterns *known to defeat* tree-shaking (barrel imports, module-format mismatches) but does not verify the resulting byte-level outcome itself. ## Minimal safe review flow 1. Confirm the current bundler, major version, and (for Vite) the active output-options key (`rollupOptions` vs `rolldownOptions`). 2. Capture the baseline: current chunk list/sizes and current build time, from user-provided build output or stats file — do not fabricate baseline numbers. 3. Ground every config-key claim via Context7 for the confirmed version before proposing a diff (see the Context7 Documentation Protocol in `SKILL.md`). 4. Propose the config diff, not an applied change — this is a static-review skill; it does not run builds. 5. State the verification command the user (or their CI) must run to confirm the diff took effect (e.g., `npm run build -- --report` or the project's equivalent stats-output invocation) and what a successful before/after diff looks like. 6. State the rollback path explicitly, even if it is as simple as "revert this config diff." ## When to push back Push back if the user asks for: - a bundler-major or engine (Rollup-to-Rolldown) migration with no stated baseline and "we'll measure it after," - a chunking-config change accepted as complete purely because the build didn't error, - merging all of `node_modules` into a single vendor chunk (Webpack) or an equivalent broad grouping (Vite) presented as a universal best practice rather than a named caching/parallelism trade-off, - a `manualChunks` config change on a Vite project without first confirming which output-options key and Vite major are actually in play. Those are not shortcuts. They are a config diff without evidence it does what it claims. -
vite-chunking-config.md 7.1 KB
# Vite Chunking Configuration Use this reference when reviewing or writing Vite's production-build chunking configuration, or when a project reports a chunking config that "used to work" and no longer applies. > Version note: this reference reflects Context7-grounded Vite documentation as of this skill's `updated` date. Vite's build-engine option surface has changed across major versions — re-verify against `mcp__Context7__query-docs` for `/vitejs/vite` before applying any snippet below to a specific installed version, and confirm the version with the project's own lockfile or `vite --version` output rather than assuming it from `package.json` ranges. ## What people get wrong The naive assumption is: > "Vite chunking config" is one API — `manualChunks` — and it works the same across every Vite version. Wrong. Vite's production build is not one bundler; it is a build-engine seam. Depending on the Vite major version and which output-options key the config uses, the actual bundling engine is either: - **Rollup**, addressed via `build.rollupOptions.output.manualChunks`, or - **Rolldown** (a Rust-based bundler with a Rollup-compatible API surface, but its own option shapes for some features), addressed via `build.rolldownOptions.output.codeSplitting`. A config snippet that is correct for one engine can silently no-op under the other. This is not a deprecation warning you can ignore — Vite's own migration guide documents the object form of `manualChunks` as **removed**, not merely discouraged. ## Officially grounded shape (what Vite/Rollup/Rolldown docs actually say) Per Context7-grounded Vite build/migration docs and Rollup's own configuration docs: - **Rollup's `output.manualChunks`** (used when the config's build path routes through `rollupOptions`) supports two forms: - **Object form**: `manualChunks: { 'vendor-react': ['react', 'react-dom'] }` — maps a chunk name to an explicit array of module specifiers. Rollup's own docs describe this as the simpler, safer form. - **Function form**: `manualChunks(id) { if (id.includes('node_modules')) return 'vendor'; }` — receives the module ID (and `{ getModuleInfo, getModuleIds }`) and returns a chunk name string or `null`/`undefined` to leave the module unassigned. Rollup's docs note `output.onlyExplicitManualChunks` is itself a separate, deprecated option slated to become Rollup 5's default behavior — confirm this hasn't shifted before relying on implicit fallback chunking. - Rollup itself has **not** removed either form; the removal described below is specific to Vite's own option surface on its migration path toward Rolldown. - **Vite's `build.rollupOptions.output.manualChunks`** — per Vite's migration guide (grounded via Context7): the **object form is removed** and the **function form is deprecated**. A project still passing `manualChunks: { vendor: [...] }` to `rollupOptions.output` on a Vite version past this removal will see the option ignored, not an error — this is the single most common false-negative in this review. - **Vite's `build.rolldownOptions.output.codeSplitting`** — the documented replacement. Per Vite's build guide and Rolldown's own `manualCodeSplitting` reference, this takes a declarative shape: ```javascript export default defineConfig({ build: { rolldownOptions: { output: { codeSplitting: { groups: [ { name: 'vendor-react', test: /node_modules\/(react|react-dom)/ }, { name: 'chunk', test: 'chunk.css' }, ], }, }, }, }, }) ``` Each entry in `groups` is a `{ name, test }` pair; `test` can match on module ID pattern. This is a declarative alternative to `manualChunks`'s imperative function form, intended to avoid circular-dependency footguns that hand-written `manualChunks` functions can introduce. - **`splitVendorChunkPlugin`** — Vite ships a built-in plugin implementing a `vendor` chunk heuristic (any `node_modules` module, not CSS, statically imported by an entry point) as a `manualChunks` function. Per its own source (grounded via Context7): when composed with a user-supplied **function-form** `manualChunks`, it wraps and chains the two; when composed with an **object-form** `manualChunks`, it detects the object form and **logs a console warning that it has no effect**, then does nothing. A project reporting "the vendor-splitting plugin isn't working, no error, just a console warning" is very likely hitting exactly this interaction. ## Non-negotiable review rules 1. **Confirm the output-options key before applying either ruleset.** Grep the Vite config for `rollupOptions` vs `rolldownOptions` under `build`. These are not interchangeable, and a chunking snippet written for one silently does nothing under the other. 2. **Confirm the installed Vite major.** Do not infer it from a `^7.0.0`-style semver range in `package.json` alone — a caret range can resolve to a version past a documented removal. Prefer lockfile-resolved version or a reported `vite --version` if available as user-provided evidence. 3. **If the config uses `rollupOptions.output.manualChunks` as an object**, and the confirmed Vite major is on/after the version where Vite's migration guide documents the removal, flag this as a silent no-op, not a style nit — the chunking strategy the team believes is active is not running. 4. **If the config uses `rollupOptions.output.manualChunks` as a function**, treat it as valid but flag it as a forward-migration item toward `rolldownOptions.output.codeSplitting`, per Vite's own deprecation notice — do not present the function form as the long-term recommended pattern. 5. **When migrating a `manualChunks` function to `codeSplitting` groups**, do not assume a 1:1 mechanical translation. A `manualChunks` function can express arbitrary conditional logic (e.g., branching on `getModuleInfo(id).importers`); `codeSplitting`'s `groups` array is pattern-match-based (`test` against module ID). Confirm each branch of the original function has an equivalent `test` pattern before calling the migration complete — untranslatable branches are a real migration risk, not a formality. 6. **Do not conflate Vite's dev-server module graph with its build chunking.** Chunking config has zero effect on `vite dev`; it applies only to `vite build`. A user reporting a "chunking problem" during local dev is describing something this config cannot cause. ## Verification targets - The confirmed Vite major (from lockfile or reported CLI version) and the output-options key actually present in `vite.config.*`. - For a `manualChunks` object-form finding: the exact Vite version threshold from `mcp__Context7__query-docs` against `/vitejs/vite`'s migration guide, quoted, not paraphrased from memory. - For a proposed `codeSplitting` groups migration: each `groups[].test` pattern mapped explicitly back to the branch of the prior `manualChunks` function it replaces. - A build output diff (chunk list, sizes) confirming the new config actually changed the chunk boundaries — an unchanged chunk list after a config edit is evidence the edit didn't take effect, not evidence the config was already optimal. -
webpack-splitchunks-config.md 6.3 KB
# Webpack SplitChunksPlugin Configuration Use this reference when reviewing or writing Webpack's `optimization.splitChunks` configuration, `cacheGroups`, or `runtimeChunk` settings. > Version note: confirm the installed Webpack major via `mcp__Context7__query-docs` against Webpack's own docs before asserting a specific default value below applies — `SplitChunksPlugin` defaults have shifted across major versions historically, and this reference documents the currently Context7-grounded defaults, not a version-pinned guarantee. ## What people get wrong The naive assumption is: > `optimization.splitChunks: { chunks: 'all' }` is "the vendor-splitting setting" and turning it on is the whole job. Incomplete. `chunks: 'all'` only changes *which* chunks (`async`, `initial`, or both) are eligible for splitting — it does not by itself define a vendor group, a size threshold, or a request-count ceiling. Webpack's actual chunk-splitting behavior is the product of several settings interacting: `chunks`, `minSize`, `minChunks`, `maxAsyncRequests`, `maxInitialRequests`, `enforceSizeThreshold`, and the `cacheGroups` map. Reviewing only `chunks` and ignoring the rest of the object produces a config that "does something" without the reviewer knowing what. ## Officially grounded shape (what Webpack docs actually say) Per Context7-grounded Webpack docs (`SplitChunksPlugin` reference and code-splitting/caching guides): - **Default `optimization.splitChunks` shape**, documented explicitly: ```javascript optimization: { splitChunks: { chunks: "async", minSize: 20000, minRemainingSize: 0, minChunks: 1, maxAsyncRequests: 30, maxInitialRequests: 30, enforceSizeThreshold: 50000, cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, } ``` The default `chunks: "async"` means only dynamically-imported (`import()`) chunks are eligible for splitting out of the box — a project relying on defaults and expecting *initial* (entry-point) chunks to also get vendor-split needs to explicitly set `chunks: "all"`, either globally or per cache group. - **Explicit vendor cache group** — the documented pattern for pulling all `node_modules` code into a named `vendors` chunk: ```javascript optimization: { runtimeChunk: 'single', splitChunks: { cacheGroups: { vendor: { test: /[\\/]node_modules[\\/]/, name: 'vendors', chunks: 'all', }, }, }, }, ``` Webpack's own caching guide pairs this with `runtimeChunk: 'single'` specifically for long-term-caching correctness — extracting the webpack runtime/manifest into its own chunk so that changes to application code don't invalidate the vendor chunk's content hash. A `vendor` cache group added without `runtimeChunk: 'single'` is a common half-fix: the vendor chunk hash still churns on unrelated app changes because the runtime is bundled with it. - **Custom cache-group merging** — Webpack's docs note that merging all of `node_modules` into a single `vendors` chunk via a broad `test: /node_modules/` cache group "is not generally recommended" as a default strategy, but can be a deliberate trade-off for long-term caching in specific deployment setups. Treat a broad single-vendor-chunk config as an explicit trade-off to confirm with the team, not a default best practice to apply unprompted. ## Non-negotiable review rules 1. **Read the whole `splitChunks` object, not just `chunks`.** `minSize`, `maxInitialRequests`, and `enforceSizeThreshold` jointly determine whether a module that "should" be split actually gets split. A module below `minSize` (default 20000 bytes) will not become its own chunk regardless of `cacheGroups` targeting, unless a cache group's own `enforce: true` overrides that. 2. **Confirm `chunks` scope per cache group, not just globally.** A global `chunks: 'async'` with a `vendor` cache group that doesn't override `chunks: 'all'` will not split vendor code out of the initial/entry bundle — only out of dynamically-imported chunks. This is the most common "I added a vendor cache group and nothing changed in the initial bundle" defect. 3. **Pair any named vendor cache group with `runtimeChunk: 'single'` when the goal is long-term-caching stability**, and say so explicitly if the config is missing it — otherwise the vendor chunk's cache-busting behavior won't match what the team expects. 4. **Do not propose a broad `test: /node_modules/` single-vendor-chunk config as a default recommendation.** Per Webpack's own docs, this is an explicit trade-off (fewer, larger, more cache-stable chunks vs. finer-grained, more parallel-loadable chunks), not a universal best practice — surface it as a choice with a named trade-off, not a fix. 5. **Confirm the installed Webpack major before asserting any specific default value** (e.g., `minSize: 20000`) — quote the value from `mcp__Context7__query-docs` against the confirmed major rather than this reference's cached snapshot, since defaults have changed across majors historically. 6. **Distinguish `optimization.splitChunks` (automatic, heuristic-driven) from explicit multi-entry configuration** (`entry: { index: ..., another: ... }`) — a duplicate-dependency finding across two *entry points* (not two dynamically-split chunks) is a `splitChunks` cache-group problem, not an entry-config problem; do not propose merging entries as the fix when the actual defect is a missing/misconfigured cache group. ## Verification targets - The confirmed Webpack major and the full resolved `optimization.splitChunks` object (defaults plus overrides), not just the cache-group diff. - The `chunks` scope value effective for the specific cache group in question (group-level override, if present, wins over the global setting). - A build stats output (`webpack --json` or `webpack-bundle-analyzer` treemap) confirming the proposed cache-group change actually produced the intended chunk split, with a before/after chunk-name and chunk-size comparison. - Whether `runtimeChunk` is configured, when reviewing a named vendor cache group intended for long-term-caching stability.
-
-
metadata.json 1.5 KB
{ "id": "build-tooling-vite-webpack-review", "name": "Build Tooling (Vite/Webpack) Review", "type": "skill", "provider": "frontend", "harnesses": [ "codex", "claude-code", "cursor", "gemini", "kiro", "other" ], "summary": "Reviews Vite and Webpack build configuration, code-splitting/chunking strategy, and bundle-size budgets, version-labeling every recommendation because Vite 8's Rolldown-based codeSplitting API replaced the Rollup-era manualChunks option.", "source_type": "original", "official_docs": [ "https://vite.dev/guide/build.html", "https://vite.dev/guide/migration.html", "https://webpack.js.org/guides/code-splitting/", "https://webpack.js.org/plugins/split-chunks-plugin/" ], "security_notes": "Bundle-analyzer output shared outside the org must not include source maps that reveal internal API paths or accidentally-inlined environment values. Any dependency with an install-time script that runs during the build must be reviewed before it's allowed to affect the production bundle. Static-review-only skill: it reads and greps build config and source; it does not execute builds, install dependencies, or run bundler CLIs. Treat any credential-shaped string found in a pasted build config, CI job definition, or analyzer report as unsafe to echo in the transcript.", "last_verified": "2026-07-02", "path": "skills/frontend/build-tooling-vite-webpack-review", "author": "github: VincentChuWaiChow", "version": "0.1.0" } -
SKILL.md 9.8 KB
--- name: build-tooling-vite-webpack-review description: Reviews Vite and Webpack build/chunking configuration and bundle-size composition for duplicate dependencies, unsplit vendor chunks, and tree-shaking failures, always version-labeling config since Vite 8 replaced Rollup-era manualChunks with Rolldown-based codeSplitting. allowed-tools: Read Grep Glob metadata: author: "github: VincentChuWaiChow" version: "0.1.0" updated: "2026-07-02" category: compute --- # Build Tooling (Vite/Webpack) Review ## Purpose Bundler config advice that doesn't match the installed major version is worse than no advice — it produces a config diff that silently no-ops, throws at build time, or (worst case) applies to the wrong bundler engine entirely. Vite ships two build engines depending on version and config shape (Rollup-backed `rollupOptions`, or Rolldown-backed `rolldownOptions`), and Vite 8 removed the object form of `manualChunks` outright. This skill reviews Vite/Webpack build and chunking *configuration itself* — the config file, not the resulting bundle bytes — and treats the target bundler's exact major version as a required input, not an assumption, before proposing any config diff. ## When to use Use this skill when the user asks to: - review or tune Vite `build.rollupOptions`/`build.rolldownOptions` or Webpack `optimization.splitChunks` chunking configuration, - diagnose a duplicate-dependency-across-chunks defect or an unsplit vendor chunk caused by chunking config (not by application-level import boundaries), - evaluate a proposed bundler migration (Webpack to Vite, Rollup-backed Vite to Rolldown-backed Vite, or a Vite major-version upgrade) for build-time and config-compatibility impact, - diagnose a tree-shaking failure that traces back to bundler/build config (module format, `sideEffects` field interaction with the bundler, barrel-file re-exports defeating static analysis) rather than to source-code side effects, - set up or review a CI bundle-size budget gate at the build-tool level (build script, CI job config). ## When NOT to use - Setting or auditing the *numeric* size budget itself, ranking analyzer contributors by byte weight vs. execution cost, or deciding route/component-level code-splitting boundaries — hand off to `bundle-budget-code-splitting-review` for that; this skill reviews the bundler config mechanism, not the budget methodology or split-boundary decision. - Verifying that tree-shaking actually eliminated dead code via a before/after byte diff, or auditing `sideEffects: false` correctness on a specific package — hand off to `tree-shaking-dead-code-review` for that; this skill only flags build-config patterns (barrel imports, module-format mismatches) that are *known to defeat* tree-shaking, it does not verify the outcome. - Non-bundler build tooling (Babel-only transpilation pipelines with no bundling step, TypeScript `tsc`-only builds, esbuild/Rolldown used as a library outside Vite/Webpack) — different config surface, not in scope here. ## Context7 Documentation Protocol Vite's build-engine and chunking API surface changed between major versions — do not prescribe a config from memorized training data. 1. Call `ToolSearch` with query `"context7"` (or `"select:mcp__Context7__resolve-library-id,mcp__Context7__query-docs"`) to load the Context7 tools if not already loaded this session. 2. Call `mcp__Context7__resolve-library-id` for each bundler in scope (`/vitejs/vite`, Webpack, `/rollup/rollup`, and `/rolldown/rolldown` if the project's Vite build is Rolldown-backed) before prescribing any chunking configuration. 3. Call `mcp__Context7__query-docs` for the specific mechanism — e.g. "rollupOptions.output.manualChunks vs rolldownOptions.output.codeSplitting", "splitChunks cacheGroups defaults", "manualChunks object form vs function form" — before ruling on it. Do this per review; do not reuse a prior session's memory of bundler internals. 4. Known version-sensitive facts verified via Context7 as of this skill's `updated` date: - Vite's migration guide documents that the **object form** of `build.rollupOptions.output.manualChunks` was **removed**, and the **function form** was **deprecated**; the replacement is `build.rolldownOptions.output.codeSplitting`, which takes a `groups` array of `{ name, test }` entries (Rolldown's declarative chunk-grouping API). Do not hand a project on that config path a `manualChunks: { vendor: [...] }` object-form snippet — it will not apply. - Rollup itself (used directly, or via Vite versions/configs that still route through `rollupOptions`) continues to support both the object form and function form of `output.manualChunks` per Rollup's own configuration docs — the removal is specific to Vite's option surface and its migration path toward Rolldown, not a Rollup-wide deprecation. Confirm which bundler engine actually processes the config (`rollupOptions` vs `rolldownOptions` key) before applying either party's rules. - Vite ships a built-in `splitVendorChunkPlugin` that composes with function-form `manualChunks` but explicitly logs a warning and no-ops when combined with the object form — treat "vendor chunk isn't splitting and there's a console warning about `splitVendorChunk`" as a symptom of this specific interaction, not a generic bug report. 5. Webpack's `optimization.splitChunks` surface (`cacheGroups`, `chunks: 'all' | 'async' | 'initial'`, `minSize`, `maxInitialRequests`) is comparatively stable across recent majors per Context7-grounded docs, including its documented defaults (`minSize: 20000`, `defaultVendors`/`default` cache groups with `priority: -10`/`-20`) — still confirm the installed Webpack major before asserting a specific default, since defaults have shifted across major versions historically. 6. If Context7 is unavailable or returns no relevant match for the installed bundler, fall back to `official_docs` and mark the claim `documentation-based (Context7 unavailable)` rather than presenting it as freshly verified. 7. Never invent a bundler config key, CLI flag, or plugin option that no queried source confirms. ## Lean operating rules - Confirm the installed Vite major version and which output-options key (`rollupOptions` vs `rolldownOptions`) the project's own config already uses before proposing a diff — these are two different bundler engines with two different chunking APIs, and giving the wrong era's config is a concrete, verified failure, not a style choice. - Distinguish Vite's dev-server behavior (native ESM, no bundling, chunking config irrelevant) from its production build behavior (bundled via Rollup or Rolldown depending on version/config); every recommendation in this skill applies only to the production build path. - Flag barrel-file (`index.ts` re-export) imports and wildcard imports of large libraries (icon sets, date libraries, utility libraries) as build-config-relevant tree-shaking risks when the project's module format or bundler settings can't statically resolve them — name the specific named/subpath-import fix, and hand off to `tree-shaking-dead-code-review` to verify the byte-level outcome. - Treat a duplicate-dependency-across-chunks finding as a chunk-grouping *config* defect (fix `manualChunks`/`codeSplitting`/`cacheGroups`), not an application-code defect — do not propose restructuring import statements to solve what a config change solves more directly. - Require a stated measured baseline (current bundle output, build time) before endorsing any bundler or bundler-major migration, plus a rollback path (pinned lockfile entry, ability to revert the config key). - Recommend a CI bundle-size budget gate at the build-tool/CI-job level for any budget-critical route that lacks one, rather than treating build-config review as a one-time audit — but define the numeric budget itself only via `bundle-budget-code-splitting-review`. - Do not evaluate bundle-size numbers as if they were field/RUM Core Web Vitals data; a build's stats output is lab data from a CI build unless explicitly stated otherwise. - Never accept "it built without errors" as evidence a chunking config change is correct — a removed or renamed option key can silently no-op (see the Vite 8 `manualChunks` object-form removal) rather than error. ## References Load these only when needed: - [Vite chunking config reference](references/vite-chunking-config.md) — use when reviewing or writing `rollupOptions.output.manualChunks` or `rolldownOptions.output.codeSplitting`, or diagnosing which bundler engine a Vite config actually invokes. - [Webpack splitChunks reference](references/webpack-splitchunks-config.md) — use when reviewing or writing `optimization.splitChunks`, `cacheGroups`, or `runtimeChunk` configuration. - [Migration and config-diff safety](references/migration-and-config-diff-safety.md) — use before endorsing a bundler migration or a chunking-config change, to confirm baseline capture, rollback path, and the verification steps that must precede calling a config change complete. ## Response minimum Return, at minimum: - the bundler and confirmed major version (and, for Vite, the confirmed output-options key: `rollupOptions` or `rolldownOptions`) the guidance targets, - build-config findings (duplicate-dependency chunk-grouping defects, config keys that no longer apply for the confirmed version, barrel-file/module-format patterns defeating tree-shaking) with file/line evidence, - proposed chunking/config diff (not applied), labeled lab vs field for any performance number cited, - evidence level (`live evidence`, `user-provided sanitized evidence`, `documentation-based`, or `inference`), - migration caveat (baseline + rollback) if a bundler or bundler-major change is recommended, and a handoff note to `bundle-budget-code-splitting-review` or `tree-shaking-dead-code-review` if the user's actual question is budget-setting or tree-shaking verification rather than config review.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.