Vite Cursor Rules: Next-Gen Build Tool
Cursor rules for Vite covering vite.config.ts, dev server with HMR, environment variables, CSS handling, build optimization, plugins, library mode, and static asset handling.

Overview
Vite is the dominant build tool for modern web projects, providing a lightning-fast dev server with native ESM and Hot Module Replacement, plus an optimized production build using Rolldown. These cursor rules enforce vite.config.ts conventions, environment variable handling, CSS strategies, plugin usage, build optimization, and library mode so AI assistants generate performant, well-configured Vite projects.
Note:
Enforces vite.config.ts structure, import.meta.env conventions, HMR patterns, CSS modules/PostCSS, build.rollupOptions, plugin ordering, library mode, and environment variable prefixes.
Rules Configuration
---
description: Enforces Vite best practices including vite.config.ts structure, import.meta.env conventions, HMR, CSS handling, build optimization, plugins, library mode, and static asset management.
globs: **/vite.config.ts,**/vite.config.js,index.html,**/.env*,.env.development,.env.production
---
# Vite Best Practices
You are an expert in Vite, modern build tooling, and frontend development workflows.
You understand ESM, HMR, bundling optimization, CSS pipelines, and plugin architectures.
### Configuration (vite.config.ts)
- Use `defineConfig` helper for TypeScript intellisense: `import { defineConfig } from "vite"`
- Set `plugins` array with framework-specific plugins first (react(), vue(), etc.)
- Define `resolve.alias` with `@` for clean imports: `{ "@": path.resolve(__dirname, "./src") }`
- Set `server.port` and `server.open` for dev convenience
- Configure `server.proxy` for API calls: `{ "/api": { target: "http://localhost:8080", changeOrigin: true } }`
- Use `build.outDir` for custom output directory (default: dist)
- Set `base: "/my-app/"` for deployments not at the root path
### Environment Variables
- Use `import.meta.env.VITE_API_URL` in client code (must be prefixed with VITE_)
- Use `import.meta.env.MODE` to check for 'development', 'production', or custom modes
- Use `import.meta.env.PROD` and `import.meta.env.DEV` as boolean shortcuts
- Server-only vars: load with `loadEnv(mode, process.cwd(), "")` in vite.config.ts
- Define `.env`, `.env.local`, `.env.development`, `.env.production` for mode-specific vars
- Never expose secrets in VITE_ prefixed variables — they end up in the client bundle
### Dev Server & HMR
- HMR is enabled by default — no configuration needed for frameworks
- Write HMR-compatible modules: export functions/classes (not global state)
- Use `import.meta.hot.accept()` for custom HMR in vanilla JS/TS
- Use `import.meta.hot.dispose()` to clean up side effects on module replacement
- `npm run dev` starts Vite dev server; use `--host` to expose on network
- Hot reload CSS changes instantly without full page refresh
### CSS Handling
- Import CSS files directly: `import "./styles.css"` (Vite handles resolution)
- Use CSS Modules: `import styles from "./Component.module.css"` — scoped class names
- PostCSS auto-detected from `postcss.config.js` — configure Tailwind, Autoprefixer here
- Use `css.preprocessorOptions` for Sass/Less global variables
- Use `css.modules.localsConvention: "camelCase"` for camelCase class access
- Inline small CSS with `build.cssMinify: "lightningcss"` for faster production builds
### Static Assets
- Import assets directly: `import logo from "./logo.png"` — returns resolved URL
- Use `new URL("./img/icon.png", import.meta.url)` for dynamic asset URLs
- Place files in `public/` for assets served at root without processing (favicon, robots.txt)
- Public assets referenced via absolute path: `/favicon.ico`
- Use `assetsInlineLimit` to inline small assets as base64 (default: 4KB)
- SVGs can be imported as components with `@vitejs/plugin-vue` or `vite-plugin-svgr`
### Build Optimization
- Use `build.rollupOptions` for advanced chunking: `output.manualChunks`
- Split vendor chunks: `{ vendor: ["react", "react-dom"] }`
- Enable `build.minify: "terser"` for legacy browser support (default: esbuild)
- Set `build.target: "es2020"` for modern browsers
- Use `build.sourcemap: true` for debugging production builds
- Enable `build.cssCodeSplit: true` to avoid one massive CSS file
### Plugins
- Framework plugins first: `@vitejs/plugin-react`, `@vitejs/plugin-vue`, `@vitejs/plugin-svelte`
- Use `@vitejs/plugin-legacy` for IE11 support (generates legacy chunks)
- Use `vite-plugin-compression` for gzip/brotli output
- Use `vite-plugin-pwa` for service worker and offline support
- Use `unplugin-auto-import` for auto-importing APIs (React hooks, Vue composables)
- Use `unplugin-icons` for on-demand icon imports
### Library Mode
- Set `build.lib.entry: path.resolve(__dirname, "src/index.ts")`
- Define `build.lib.name: "MyLibrary"` for UMD global name
- Set `build.lib.formats: ["es", "cjs", "umd"]` for multi-format output
- Externalize peer dependencies: `rollupOptions.external: ["react", "react-dom"]`
- Declare `peerDependencies` in package.json matching externals
- Set `build.lib.fileName: (format) => `my-lib.${format}.js`` for custom filenames
Installation
Create vite.mdc in your project's .cursor/rules/ directory and paste the configuration above. Cursor and Windsurf both read .cursor/rules/ — Copilot users place it in .github/copilot-instructions.md instead.
# Create a Vite project
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
Examples
// vite.config.ts — Full configuration with React + path aliases
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
server: {
port: 3000,
open: true,
proxy: {
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
},
},
},
build: {
outDir: "dist",
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ["react", "react-dom"],
},
},
},
},
});
// src/env.d.ts — TypeScript types for import.meta.env
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_APP_TITLE: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// Custom HMR handler for vanilla JS
if (import.meta.hot) {
import.meta.hot.accept((newModule) => {
// Re-run initialization when module updates
newModule.init();
});
import.meta.hot.dispose(() => {
// Clean up event listeners, intervals, etc.
cleanup();
});
}
// Library mode configuration
import { defineConfig } from "vite";
import path from "path";
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, "src/index.ts"),
name: "MyLibrary",
formats: ["es", "cjs"],
fileName: (format) => `my-lib.${format}.js`,
},
rollupOptions: {
external: ["react", "react-dom"],
output: {
globals: {
react: "React",
"react-dom": "ReactDOM",
},
},
},
},
});
Related Resources
Related Articles
Svelte Cursor Rules: Reactive UI and SvelteKit Development
Cursor rules for Svelte and SvelteKit that enforce reactive patterns, stores, routing, and testing. Generate maintainable, accessible, performance-focused UI.
GraphQL Cursor Rules: API Query Language
Cursor rules for GraphQL covering schema-first design, resolvers, queries/mutations, fragments, error handling with unions, subscriptions, and Apollo Server patterns.
Pydantic Cursor Rules: Python Data Validation
Cursor rules for Pydantic covering BaseModel, field types/validators, nested models, ConfigDict, JSON Schema, BaseSettings, discriminated unions, and ORM integration.