vite-impl-project-setup

Use when creating a new Vite project, adding Vite to an existing project, or configuring TypeScript and framework plugins. Prevents missing vite-env.d.ts for TypeScript or using wrong tsconfig setting

SKILL.md

GitHub

vite-impl-project-setup

Quick Reference

Project Creation (create-vite)

Package Manager Command
npm npm create vite@latest my-app -- --template react-ts
pnpm pnpm create vite my-app --template react-ts
yarn yarn create vite my-app --template react-ts

Omit --template for interactive template selection.

Available Templates

Template TypeScript Variant Framework Plugin
vanilla vanilla-ts None
react react-ts @vitejs/plugin-react (Babel)
react-swc react-swc-ts @vitejs/plugin-react-swc (SWC)
vue vue-ts @vitejs/plugin-vue
preact preact-ts @preact/preset-vite
lit lit-ts None
svelte svelte-ts @sveltejs/vite-plugin-svelte
solid solid-ts vite-plugin-solid
qwik qwik-ts None (Qwik CLI)

CLI Commands

Command Alias Default Port Purpose
vite vite dev / vite serve 5173 Start dev server with HMR
vite build — — Production build to dist/
vite preview — 4173 Preview production build locally

Common CLI Flags

Flag Example Purpose
--port <number> vite --port 3000 Set dev server port
--open vite --open Open browser on start
--mode <mode> vite build --mode staging Set mode (loads .env.staging)
--force vite --force Re-bundle dependencies, ignore cache
--host vite --host Expose on LAN (0.0.0.0)

Critical Warnings

ALWAYS set isolatedModules: true in tsconfig.json — Vite transpiles TypeScript without type information. Without this flag, code that relies on cross-file type analysis (like const enum re-exports) will silently produce incorrect output.

NEVER rely on Vite for type checking — Vite performs transpile-only. ALWAYS run tsc --noEmit separately for type safety, either in CI or as a parallel dev process.

NEVER set envPrefix to '' in vite.config.ts — this exposes ALL environment variables (including secrets like DB_PASSWORD) to client-side code.

NEVER omit /// <reference types="vite/client" /> from vite-env.d.ts — without it, TypeScript cannot resolve import.meta.env, asset imports (.svg, .png), or HMR types.


Decision Tree: New Project Setup

Need a new Vite project?
├── Greenfield project → Use create-vite with --template
│   ├── React project?
│   │   ├── Need fastest dev builds → react-swc-ts (SWC compiler)
│   │   └── Need Babel plugins → react-ts (Babel compiler)
│   ├── Vue project? → vue-ts
│   ├── Svelte project? → svelte-ts
│   ├── No framework? → vanilla-ts
│   └── Other framework? → Check create-vite templates list
│
├── Adding Vite to existing project → Manual setup
│   ├── Install vite as devDependency
│   ├── Create vite.config.ts with framework plugin
│   ├── Move/create index.html at project root
│   ├── Add <script type="module" src="/src/main.ts"> to index.html
│   └── Add dev/build/preview scripts to package.json
│
└── TypeScript project?
    ├── ALWAYS set isolatedModules: true in tsconfig.json
    ├── ALWAYS create src/vite-env.d.ts with /// reference types
    ├── ALWAYS run tsc --noEmit separately for type checking
    └── ALWAYS use type-only imports: import type { T } from '...'

Project Structure

my-app/
├── index.html                 # Entry point (MUST be at project root)
├── public/                    # Static assets (copied as-is, no processing)
│   └── favicon.ico
├── src/
│   ├── main.ts                # Application entry (referenced from index.html)
│   ├── App.tsx                # Root component (framework-dependent)
│   ├── vite-env.d.ts          # Vite client type declarations
│   └── assets/                # Processed assets (hashed in build)
│       └── logo.svg
├── vite.config.ts             # Vite configuration
├── tsconfig.json              # TypeScript configuration
├── package.json               # Dependencies and scripts
└── .gitignore                 # Source control exclusions

ALWAYS place index.html at the project root — Vite uses it as the entry point, NOT inside public/ or src/. The dev server maps <root>/index.html to http://localhost:5173/.


TypeScript Configuration

Required tsconfig.json Settings

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "isolatedModules": true,
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "types": ["vite/client"]
  },
  "include": ["src"]
}

Critical Settings Explained

Setting Value Why
isolatedModules true REQUIRED — Vite transpiles each file independently without type info
useDefineForClassFields true Matches ES2022+ class field semantics used by Vite
noEmit true Vite handles emit; tsc is for type checking only
moduleResolution "bundler" Matches Vite's module resolution strategy
types ["vite/client"] Provides types for import.meta.env, asset imports, HMR API

vite-env.d.ts (REQUIRED)

/// <reference types="vite/client" />

This file MUST exist in src/ to provide TypeScript with Vite-specific type definitions. It enables types for:

  • import.meta.env.VITE_* variables
  • Asset imports (import logo from './logo.svg')
  • import.meta.hot HMR API

Type Checking Workflow

Vite does NOT type-check — it only transpiles. ALWAYS run type checking separately:

{
  "scripts": {
    "dev": "vite",
    "build": "tsc --noEmit && vite build",
    "preview": "vite preview",
    "typecheck": "tsc --noEmit",
    "typecheck:watch": "tsc --noEmit --watch"
  }
}

Framework Plugin Setup

Framework Plugin Table

Framework Plugin Package Import Config
React (Babel) @vitejs/plugin-react import react from '@vitejs/plugin-react' plugins: [react()]
React (SWC) @vitejs/plugin-react-swc import react from '@vitejs/plugin-react-swc' plugins: [react()]
Vue @vitejs/plugin-vue import vue from '@vitejs/plugin-vue' plugins: [vue()]
Vue JSX @vitejs/plugin-vue-jsx import vueJsx from '@vitejs/plugin-vue-jsx' plugins: [vue(), vueJsx()]
Svelte @sveltejs/vite-plugin-svelte import { svelte } from '@sveltejs/vite-plugin-svelte' plugins: [svelte()]

Minimal vite.config.ts (React + TypeScript)

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

export default defineConfig({
  plugins: [react()],
})

JSX Configuration (Non-Framework)

For Vite 8+ (Oxc transformer):

export default defineConfig({
  oxc: {
    jsx: {
      runtime: 'classic',
      pragma: 'h',
      pragmaFrag: 'Fragment',
    },
  },
})

For Vite 6/7 (esbuild transformer):

export default defineConfig({
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment',
    jsxInject: `import { h, Fragment } from 'preact'`,
  },
})

CSS Preprocessor Setup

Install the preprocessor package only — NO Vite plugins needed:

Preprocessor Install Command File Extensions
Sass npm add -D sass-embedded .scss, .sass
Less npm add -D less .less
Stylus npm add -D stylus .styl, .stylus

ALWAYS prefer sass-embedded over sass — it is significantly faster for large projects.


Source Control (.gitignore)

node_modules
dist
*.local
.env.local
.env.*.local

ALWAYS ignore node_modules and dist. ALWAYS ignore .env.local and .env.*.local — these contain environment-specific secrets. NEVER ignore vite.config.ts, tsconfig.json, or package-lock.json / pnpm-lock.yaml — these are required for reproducible builds.


Reference Links

Official Sources