Learn-skills.dev web-tooling-vite
Vite config, path aliases, vendor chunk splitting, environment-specific builds, Rolldown codeSplitting, Sass modern API, build targets, module preload
git clone https://github.com/NeverSight/learn-skills.dev
T=$(mktemp -d) && git clone --depth=1 https://github.com/NeverSight/learn-skills.dev "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/skills-md/agents-inc/skills/web-tooling-vite" ~/.claude/skills/neversight-learn-skills-dev-web-tooling-vite && rm -rf "$T"
data/skills-md/agents-inc/skills/web-tooling-vite/SKILL.mdVite Build Tool Patterns
Quick Guide: Vite is the build tool for frontend apps. Keep path aliases in sync between
andvite.config.ts(or usetsconfig.jsonin Vite 8). Use vendor chunk splitting (resolve.tsconfigPathsin Vite 7,manualChunksin Vite 8). UsecodeSplitting.groupsfor environment-specific builds. Vite 8 uses Rolldown by default withloadEnv().build.rolldownOptionsCurrent versions: Vite 8 (stable, March 2026) with Rolldown bundler. Vite 7 (June 2025) still widely deployed.
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
, named constants)import type
(You MUST keep path aliases in sync between
and vite.config.ts
- mismatches cause import resolution failures)tsconfig.json
(You MUST use
in Vite 8+ - build.rolldownOptions
is a deprecated alias)build.rollupOptions
(You MUST use
for chunk splitting in Vite 8 - object-form codeSplitting.groups
is removed, function-form deprecated)manualChunks
(You MUST use
instead of deprecated build.modulePreload.polyfill
)build.polyfillModulePreload
(You MUST use Sass modern API (default in Vite 6+) - legacy API is removed in Vite 7+)
</critical_requirements>
Auto-detection: Vite, vite.config.ts, vite.config.js, manualChunks, advancedChunks, codeSplitting, loadEnv, rolldownOptions, rollupOptions, modulePreload, resolve.alias, resolve.tsconfigPaths, build.target, baseline-widely-available
When to use:
- Configuring Vite build tool for frontend applications
- Setting up path aliases with tsconfig sync
- Vendor chunk splitting for production builds
- Environment-specific build configuration (dev/staging/prod)
- Migrating from Vite 7 (Rollup) to Vite 8 (Rolldown)
- Configuring module preload, build targets, or Sass preprocessing
When NOT to use:
- Server-side build processes (Docker builds, CI/CD pipelines)
- Linter or formatter configuration (separate tooling skill)
- TypeScript compiler options (separate tooling skill)
Key patterns covered:
- Path aliases with tsconfig sync (and Vite 8
)resolve.tsconfigPaths - Vendor chunk splitting (
for Vite 7,manualChunks
for Vite 8)codeSplitting - Environment-specific builds with
andloadEnvdefine - Module preload configuration
- Sass modern API configuration
- Environment API (experimental, primarily for framework authors)
- Build target selection (
)baseline-widely-available
Detailed resources:
- examples/core.md - Full code examples for all patterns
- reference.md - Quick-lookup tables, migration checklist, external links
<philosophy>
Philosophy
Vite should be fast, zero-config by default, and environment-aware. The build tool stays out of your way during development (instant HMR) and optimizes aggressively for production (chunk splitting, minification, tree-shaking).
When to use this skill:
- Configuring or optimizing Vite builds
- Setting up path aliases, chunk splitting, or environment configs
- Migrating between Vite major versions (7 to 8)
- Configuring Sass, build targets, or module preload
When NOT to use:
- Runtime application code (this is build-time configuration only)
- SSR meta-framework configuration (handled by meta-framework skills)
- CI/CD pipeline configuration
<patterns>
Core Patterns
Pattern 1: Path Aliases
Configure path aliases in both
vite.config.ts and tsconfig.json to eliminate deep relative imports. In Vite 8, use resolve.tsconfigPaths: true instead of manual resolve.alias.
// Vite 7: manual resolve.alias resolve: { alias: { "@": path.resolve(__dirname, "./src"), "@components": path.resolve(__dirname, "./src/components"), }, }, // Vite 8: built-in tsconfig path resolution resolve: { tsconfigPaths: true, // reads from tsconfig.json automatically },
Key point:
resolve.tsconfigPaths is disabled by default (performance cost). Enable only if using tsconfig paths. See examples/core.md for complete configs.
Pattern 2: Vendor Chunk Splitting
Split vendor dependencies into separate chunks for better caching. API differs between Vite 7 and 8.
// Vite 7: manualChunks (object form) build: { rollupOptions: { output: { manualChunks: { "vendor": ["react", "react-dom"], }, }, }, }, // Vite 8: codeSplitting.groups (regex-based) build: { rolldownOptions: { output: { codeSplitting: { groups: [ { name: "vendor", test: /[\\/]node_modules[\\/]react(-dom)?[\\/]/ }, ], }, }, }, },
Key point: In Vite 8, object-form
manualChunks is removed and function-form is deprecated. Rolldown generates a runtime.js chunk alongside code-split groups. See examples/core.md for full examples.
Pattern 3: Environment-Specific Builds
Use
loadEnv() for environment-aware configuration and define for build-time constants.
export default defineConfig(({ mode }) => { const env = loadEnv(mode, process.cwd(), ""); return { define: { __APP_VERSION__: JSON.stringify(process.env.npm_package_version), }, build: { sourcemap: mode === "development", minify: mode === "production", }, }; });
Key point: The third argument to
loadEnv() ("") loads all env vars, not just VITE_-prefixed ones. Use --mode flag for environment selection. See examples/core.md for full config with scripts.
Pattern 4: Module Preload Configuration
build: { modulePreload: { polyfill: false, // disable for modern-only targets resolveDependencies: (filename, deps, { hostId, hostType }) => { return deps.filter((dep) => !dep.includes("large-vendor")); }, }, },
Key point:
build.polyfillModulePreload is deprecated. Use build.modulePreload.polyfill (current API since Vite 6).
Pattern 5: Sass Configuration (Vite 6+)
css: { preprocessorOptions: { scss: { // modern API is the default in Vite 6+ — no need to specify additionalData: `@use "@/styles/variables" as *;`, }, }, },
Key point: Legacy API (
api: 'legacy') is removed in Vite 7+. Migrate @import to @use/@forward with namespaced access (variables.$color-primary).
Pattern 6: Environment API (Experimental)
Primarily for framework authors. Remains in RC phase as of Vite 8. Most apps do not need this.
environments: { client: { build: { outDir: "dist/client" } }, ssr: { build: { outDir: "dist/server", ssr: true } }, },
See examples/core.md for full multi-environment config.
Pattern 7: Dev Server Proxy
</patterns>const DEV_SERVER_PORT = 3000; const API_PROXY_TARGET = "http://localhost:8000"; server: { port: DEV_SERVER_PORT, proxy: { "/api": { target: API_PROXY_TARGET, changeOrigin: true }, }, },
<decision_framework>
Decision Framework
Vite Version Selection
Which Vite version? ├─ New project (March 2026+)? │ └─ Vite 8 (Rolldown bundler, fastest builds) ✓ ├─ Existing Vite 7 project? │ ├─ Build performance is a bottleneck? │ │ └─ YES → Migrate to Vite 8 (10-30x faster) │ └─ NO → Stay on Vite 7 (stable, no migration needed) └─ Existing Vite 6 project? └─ Plan upgrade to Vite 7 first, then Vite 8
Chunk Splitting Strategy
How to split chunks? ├─ Vite 8 (Rolldown)? │ ├─ Simple vendor separation? │ │ └─ codeSplitting.groups with regex patterns ✓ │ └─ Complex splitting (size limits, shared modules)? │ └─ codeSplitting with maxSize/minSize/minShareCount ├─ Vite 7 (Rollup)? │ ├─ Simple vendor separation? │ │ └─ manualChunks object form ✓ │ └─ Complex splitting logic? │ └─ manualChunks function form └─ Vite 7 with rolldown-vite (experimental)? └─ advancedChunks.groups (renamed to codeSplitting in Vite 8)
Path Alias Strategy
How to configure path aliases? ├─ Vite 8? │ ├─ All aliases match tsconfig paths? │ │ └─ Use resolve.tsconfigPaths: true ✓ │ └─ Need aliases beyond tsconfig paths? │ └─ Use resolve.alias (manual configuration) ├─ Vite 7 or earlier? │ └─ Use resolve.alias + sync with tsconfig.json manually ✓ └─ Any version? └─ ALWAYS keep tsconfig paths in sync with Vite aliases
Build Target Selection
Choosing build.target? ├─ Supporting legacy browsers (< Safari 16)? │ └─ Use @vitejs/plugin-legacy ├─ Modern browsers only? │ ├─ Smallest possible bundle? │ │ └─ 'esnext' │ └─ Otherwise → 'baseline-widely-available' (default) ✓ └─ Specific browser requirements? └─ Use explicit array: ['chrome111', 'safari16.4']
See reference.md for quick-lookup tables and migration checklist.
</decision_framework>
<red_flags>
RED FLAGS
High Priority Issues:
- ❌ Using
in Vite 8 (deprecated alias forbuild.rollupOptions
- may warn)build.rolldownOptions - ❌ Using object-form
in Vite 8 (removed; usemanualChunks
)codeSplitting.groups - ❌ Using deprecated
(usebuild.polyfillModulePreload
)build.modulePreload.polyfill - ❌ Using deprecated
(removed in Vite 7+)splitVendorChunkPlugin - ❌ Using
(removed in Vite 7; usetarget: 'modules'
)'baseline-widely-available' - ❌ Using Sass legacy API
(removed in Vite 7+)api: 'legacy' - ❌ Path aliases in
but notvite.config.ts
(or vice versa)tsconfig.json
Medium Priority Issues:
- ⚠️ No vendor chunk splitting in production builds (large initial bundles)
- ⚠️ Same build config for all environments (slow dev builds, exposed source maps in prod)
- ⚠️ Hardcoded API URLs instead of environment variables
- ⚠️ Using Environment API in production apps (still RC phase)
- ⚠️ Function-form
in Vite 8 (deprecated, migrate tomanualChunks
)codeSplitting
Common Mistakes:
- Forgetting to sync tsconfig paths with Vite resolve.alias (build works, IDE fails or vice versa)
- Committing
files with secrets (use.env
, add to.env.local
).gitignore - Setting
in development mode (slows rebuilds significantly)minify: true - Always generating sourcemaps in production (exposes source code)
Gotchas & Edge Cases:
- Vite 8:
is a deprecated alias forbuild.rollupOptions
- works but will warnbuild.rolldownOptions - Vite 8: Rolldown generates a
chunk when usingruntime.jscodeSplitting.groups - Vite 8: Default browser targets: Chrome 111+, Edge 111+, Firefox 114+, Safari 16.4+
- Vite 8:
disabled by default due to performance costresolve.tsconfigPaths - Vite 8: Install size ~15MB larger than Vite 7 (lightningcss + Rolldown)
- Vite 8:
is a no-op (Rolldown handles CJS natively)build.commonjsOptions - Vite 8: CSS minification uses Lightning CSS, JS minification uses Oxc (both replaced esbuild)
- Vite 8:
config option is deprecated - auto-converts toesbuild
, but not all options are supported (no property mangling, nooxc
option)supported - Vite 7: Node.js 18 dropped - requires Node.js 20.19+ or 22.12+
- Vite 7: Sass legacy API completely removed
- Vite 7:
removedsplitVendorChunkPlugin - Vite 7: Default target changed from
to'modules''baseline-widely-available' - Rolldown:
renamed toadvancedChunks
in Vite 8codeSplitting - Rolldown:
is a target, not a strict limitcodeSplitting.maxSize - Rolldown:
defaults to true - may pull in more than expectedincludeDependenciesRecursively
files are loaded based on.env
flag, not--modeNODE_ENV
third argument (loadEnv()
) loads all env vars, not just""
-prefixed onesVITE_
</red_flags>
<critical_reminders>
CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
, named constants)import type
(You MUST keep path aliases in sync between
and vite.config.ts
- mismatches cause import resolution failures)tsconfig.json
(You MUST use
in Vite 8+ - build.rolldownOptions
is a deprecated alias)build.rollupOptions
(You MUST use
for chunk splitting in Vite 8 - object-form codeSplitting.groups
is removed, function-form deprecated)manualChunks
(You MUST use
instead of deprecated build.modulePreload.polyfill
)build.polyfillModulePreload
(You MUST use Sass modern API (default in Vite 6+) - legacy API is removed in Vite 7+)
Failure to follow these rules will cause build failures, broken imports, or deprecated API warnings.
</critical_reminders>