1---2name: vite-agents-review3description: Use when reviewing Vite configuration, validating a Vite project, checking for common mistakes, or auditing Vite code before deployment. Prevents shipping insecure envPrefix settings, wrong bundler options for the target version, and known anti-patterns. Covers config correctness, plugin hook signatures, HMR patterns, version-specific API usage, build optimization, environment variable security, SSR configuration, and anti-pattern detection. Keywords: review, validation, checklist, audit, anti-pattern, envPrefix, plugin hooks, security, SSR, build optimization, check my Vite config, is my setup correct, verify Vite project.4license: MIT5---67# vite-agents-review89## How to Use This Skill1011Run every check in order. Mark each item PASS or FAIL. A single FAIL in a critical area (Security, Configuration) blocks deployment. Fix all FAILs before approving code.1213---1415## 1. Configuration Checks1617| # | Check | Expected State | Common Failure |18|---|-------|---------------|----------------|19| C-01 | `defineConfig()` wraps config export | ALWAYS use `defineConfig()` for type safety and IDE support | Raw object export loses autocomplete and type checking |20| C-02 | Bundler options match target version | v8: `build.rolldownOptions` / v6-v7: `build.rollupOptions` | Using `rollupOptions` on v8 triggers deprecation; using `rolldownOptions` on v6 is invalid |21| C-03 | Transform config matches target version | v8: `oxc` option / v6-v7: `esbuild` option | Using `esbuild` on v8 is deprecated; using `oxc` on v6 is invalid |22| C-04 | `envPrefix` is NOT empty string | MUST be `'VITE_'` or a non-empty custom prefix | Setting `envPrefix: ''` exposes ALL environment variables to client code |23| C-05 | `appType` matches usage pattern | `'spa'` for single-page, `'mpa'` for multi-page, `'custom'` for SSR/middleware | Wrong `appType` causes missing HTML middleware or unwanted SPA fallback |24| C-06 | `build.target` is appropriate | Use `'baseline-widely-available'` (v7+/v8) or explicit browser list | Setting `'esnext'` for production breaks older browsers |25| C-07 | `loadEnv()` used in config, NOT `import.meta.env` | ALWAYS use `loadEnv(mode, root, prefix)` inside config files | `import.meta.env` is undefined during config resolution |26| C-08 | Conditional config uses function form | `defineConfig(({ command, mode }) => ({...}))` | Forgetting `command`/`mode` parameters leads to static config for all modes |2728---2930## 2. Plugin Checks3132| # | Check | Expected State | Common Failure |33|---|-------|---------------|----------------|34| P-01 | Plugin is a factory function returning object | ALWAYS export a function, NEVER a plain object | Plain objects prevent configuration via options parameter |35| P-02 | Plugin object has `name` property | ALWAYS include `name` string on plugin object | Missing `name` makes errors/warnings untraceable |36| P-03 | `config` hook returns partial config or mutates | Return object is deep-merged; mutations are applied directly | Returning a full config object overwrites user settings |37| P-04 | `configResolved` stores config for later hooks | Store resolved config in closure variable | Accessing `config` parameter outside the hook lifecycle |38| P-05 | `configureServer` adds middleware correctly | Use `server.middlewares.use()` for pre-middleware; return function for post-middleware | Adding post-middleware directly instead of returning a function |39| P-06 | `transformIndexHtml` uses correct order property | `order: 'pre'` for before HTML processing, `order: 'post'` (default) for after | Using deprecated `enforce` property (removed in v7) |40| P-07 | `handleHotUpdate` returns correct type | Return `ModuleNode[]` to narrow updates, `[]` to skip, or `void` for default | Returning wrong type causes HMR failures |41| P-08 | `enforce` property used correctly | `'pre'` runs before core plugins, `'post'` runs after build plugins | Omitting `enforce` when ordering matters causes transform conflicts |42| P-09 | Virtual modules use correct prefix convention | User-facing: `virtual:` prefix; internal: `\0` prefix on resolved ID | Missing `\0` prefix lets other plugins process the virtual module |43| P-10 | `moduleParsed` hook NOT relied upon in dev | NEVER depend on `moduleParsed` during development | This hook is skipped in dev for performance — code silently fails |44| P-11 | v8: `moduleType: 'js'` set in load/transform for non-JS | ALWAYS set `moduleType: 'js'` when returning non-JS content | Rolldown cannot process content without explicit module type |4546---4748## 3. HMR Checks4950| # | Check | Expected State | Common Failure |51|---|-------|---------------|----------------|52| H-01 | `import.meta.hot` guard wraps ALL HMR code | ALWAYS wrap in `if (import.meta.hot) { ... }` | HMR code ships to production, increasing bundle size |53| H-02 | `accept(` has no space before parenthesis | Write `import.meta.hot.accept(` exactly | Vite static analysis fails with `accept (` — HMR silently breaks |54| H-03 | `hot.data` mutated via properties, NEVER reassigned | `import.meta.hot.data.key = value` | `import.meta.hot.data = { key: value }` silently fails |55| H-04 | `accept()` called BEFORE `invalidate()` | ALWAYS call `accept()` first to establish HMR boundary | Calling `invalidate()` without `accept()` has no effect |56| H-05 | `dispose()` used for cleanup of side effects | Register cleanup in `import.meta.hot.dispose(cb)` | Timers, event listeners, WebSocket connections leak across updates |57| H-06 | `prune()` used for module removal cleanup | Register in `import.meta.hot.prune(cb)` when module may be removed | Resources persist after module is no longer imported |5859---6061## 4. Environment Variable Checks6263| # | Check | Expected State | Common Failure |64|---|-------|---------------|----------------|65| E-01 | Only `VITE_*` vars accessed in client code | ALWAYS prefix client-exposed vars with `VITE_` | Non-prefixed vars are `undefined` in `import.meta.env` |66| E-02 | No secrets in `VITE_*` variables | NEVER put API keys, tokens, or passwords in `VITE_*` vars | Client code exposes all `VITE_*` values in browser source |67| E-03 | TypeScript: `ImportMetaEnv` interface defined | Declare in `src/vite-env.d.ts` with `/// <reference types="vite/client" />` | Missing types cause `import.meta.env.VITE_*` to be `any` |68| E-04 | `loadEnv()` used in config, NOT `import.meta.env` | `const env = loadEnv(mode, process.cwd(), '')` | `import.meta.env` is not available during config resolution |69| E-05 | `.env.local` files added to `.gitignore` | ALWAYS gitignore `.env*.local` files | Local secrets committed to version control |7071---7273## 5. Build Checks7475| # | Check | Expected State | Common Failure |76|---|-------|---------------|----------------|77| B-01 | `build.target` matches deployment environment | Set explicit target or use `'baseline-widely-available'` | Default `'esnext'` (if set) breaks older browsers |78| B-02 | Sourcemaps not accidentally exposed in production | Use `'hidden'` or `false` for production deployments | `build.sourcemap: true` exposes source code via `.map` files |79| B-03 | CSS code splitting enabled | Keep `build.cssCodeSplit: true` (default) | Disabling creates single CSS file, hurting load performance |80| B-04 | Library mode: `name` set for UMD/IIFE builds | ALWAYS provide `build.lib.name` when formats include UMD or IIFE | Missing `name` causes build error for global variable |81| B-05 | Library mode: peer deps externalized | Add framework deps to `rolldownOptions.external` (v8) or `rollupOptions.external` (v6-v7) | Bundling React/Vue into library doubles framework in consumer app |82| B-06 | Library mode: `package.json` exports configured | Set `main`, `module`, and `exports` fields | Consumers cannot resolve the library entry point |83| B-07 | `build.minify` appropriate for target | v8 default: `'oxc'` for client; v6-v7: `'esbuild'`; SSR: `false` | Using Terser without installing it, or minifying SSR output |84| B-08 | Chunk size warnings addressed | Investigate chunks exceeding `build.chunkSizeWarningLimit` (500 KiB) | Ignoring warnings leads to slow page loads |8586---8788## 6. SSR Checks8990| # | Check | Expected State | Common Failure |91|---|-------|---------------|----------------|92| S-01 | Middleware mode sets `appType: 'custom'` | ALWAYS pair `server: { middlewareMode: true }` with `appType: 'custom'` | Default SPA fallback interferes with custom server routing |93| S-02 | `ssr.noExternal` configured for deps needing transforms | Add deps with non-ESM code or Vite-processed imports to `ssr.noExternal` | Untransformed CSS imports or JSX crash Node.js at runtime |94| S-03 | `ssrFixStacktrace` in error handlers | ALWAYS call `vite.ssrFixStacktrace(e)` in SSR catch blocks | Stack traces point to transformed code instead of source files |95| S-04 | `import.meta.env.SSR` used for conditional logic | Use `import.meta.env.SSR` to branch server/client code | Using `typeof window` checks that fail in edge runtimes |96| S-05 | SSR build uses `--ssr` flag | Build with `vite build --ssr src/entry-server.js` | Building SSR entry without `--ssr` flag bundles as client code |97| S-06 | SSR manifest generated for preload hints | Add `--ssrManifest` to client build command | Missing preload directives degrade perceived load performance |9899---100101## 7. Security Checks102103| # | Check | Expected State | Common Failure |104|---|-------|---------------|----------------|105| X-01 | `envPrefix` not set to empty string | NEVER use `envPrefix: ''` | Exposes ALL env vars (including `DB_PASSWORD`, `SECRET_KEY`) to client |106| X-02 | `server.fs.strict` not disabled without reason | Keep `server.fs.strict: true` (default) | Disabling allows dev server to serve any file on the machine |107| X-03 | `server.allowedHosts` configured for non-localhost | Set explicit host list when exposing dev server to network | DNS rebinding attacks can access dev server resources |108| X-04 | No secrets in client-exposed code | NEVER put credentials in `VITE_*` env vars, `define`, or client source | All client code is readable in browser DevTools |109| X-05 | Production sourcemaps restricted | Use `build.sourcemap: 'hidden'` or `false` | Public `.map` files expose full source code |110| X-06 | `server.fs.deny` includes sensitive patterns | Keep defaults: `['.env', '.env.*', '*.{crt,pem}', '**/.git/**']` | Removing deny rules exposes secrets and certificates |111112---113114## Validation Summary Template115116```117## Review Results: [Project Name] — [Date]118119### Version: Vite [6.x / 7.x / 8.x]120121| Area | Checks | Pass | Fail | Blocked |122|-----------------|--------|------|------|---------|123| Configuration | 8 | | | |124| Plugins | 11 | | | |125| HMR | 6 | | | |126| Env Variables | 5 | | | |127| Build | 8 | | | |128| SSR | 6 | | | |129| Security | 6 | | | |130| **TOTAL** | **50** | | | |131132### Critical Failures (blocks deployment):133- [list any Security or Configuration FAILs]134135### Non-Critical Failures (fix before merge):136- [list other FAILs]137138### Notes:139- [version-specific observations]140```141142---143144## Reference Links145146- [references/checklist.md](references/checklist.md) -- Complete validation checklist with detailed pass/fail criteria147- [references/examples.md](references/examples.md) -- Good code vs bad code examples for every check area148- [references/anti-patterns.md](references/anti-patterns.md) -- Consolidated anti-patterns from all Vite areas149150### Official Sources151152- https://vite.dev/config/153- https://vite.dev/guide/api-plugin154- https://vite.dev/guide/api-hmr155- https://vite.dev/guide/env-and-mode156- https://vite.dev/guide/ssr157- https://vite.dev/guide/build