vite

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Vite

Vite

Platform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
平台: 仅支持Web。移动端演示使用Expo搭配Metro打包工具,请查看expo-sdk技能。

Overview

概述

Build tool and development server patterns for Vite 7.x. Provides instant server start, lightning-fast HMR, optimized production builds, and extensive plugin ecosystem with first-class TypeScript support.
Install:
pnpm add -D vite
Vite 7.x的构建工具与开发服务器配置方案。提供即时服务器启动、闪电般的HMR(热模块替换)、优化的生产构建,以及对TypeScript的一流支持和丰富的插件生态系统。
安装:
pnpm add -D vite

Workflows

工作流程

Initial setup:
  1. Create
    vite.config.ts
    with TypeScript types
  2. Install React plugin:
    pnpm add -D @vitejs/plugin-react
  3. Configure path aliases for clean imports
  4. Set up environment variables with
    .env
    files
  5. Test dev server:
    pnpm vite
Production optimization:
  1. Configure build output directory and asset handling
  2. Set up code splitting and chunk optimization
  3. Enable build compression (gzip/brotli)
  4. Configure minification options
  5. Run production build:
    pnpm vite build
  6. Preview build locally:
    pnpm vite preview
初始设置:
  1. 创建带TypeScript类型的
    vite.config.ts
    文件
  2. 安装React插件:
    pnpm add -D @vitejs/plugin-react
  3. 配置路径别名以实现清晰的导入
  4. 使用
    .env
    文件设置环境变量
  5. 测试开发服务器:
    pnpm vite
生产构建优化:
  1. 配置构建输出目录和资源处理规则
  2. 设置代码分割和chunk优化
  3. 启用构建压缩(gzip/brotli)
  4. 配置代码压缩选项
  5. 执行生产构建:
    pnpm vite build
  6. 本地预览构建结果:
    pnpm vite preview

Basic Configuration

基础配置

Minimal vite.config.ts

最简vite.config.ts

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

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    open: true
  },
  build: {
    outDir: 'dist'
  }
});
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    open: true
  },
  build: {
    outDir: 'dist'
  }
});

TypeScript-Aware Config

支持TypeScript的配置

typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@utils': path.resolve(__dirname, './src/utils'),
      '@types': path.resolve(__dirname, './src/types')
    }
  }
});
Update tsconfig.json paths to match:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@hooks/*": ["./src/hooks/*"],
      "@utils/*": ["./src/utils/*"],
      "@types/*": ["./src/types/*"]
    }
  }
}
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@hooks': path.resolve(__dirname, './src/hooks'),
      '@utils': path.resolve(__dirname, './src/utils'),
      '@types': path.resolve(__dirname, './src/types')
    }
  }
});
更新tsconfig.json中的路径以匹配:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"],
      "@hooks/*": ["./src/hooks/*"],
      "@utils/*": ["./src/utils/*"],
      "@types/*": ["./src/types/*"]
    }
  }
}

React Plugin Setup

React插件设置

Basic React Plugin

基础React插件

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

export default defineConfig({
  plugins: [
    react({
      // Babel plugins for React (optional)
      babel: {
        plugins: [
          // Add custom babel plugins here
        ]
      }
    })
  ]
});
Note: Fast Refresh is enabled by default in
@vitejs/plugin-react
. No configuration needed.
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      // React的Babel插件(可选)
      babel: {
        plugins: [
          // 在此添加自定义Babel插件
        ]
      }
    })
  ]
});
注意:
@vitejs/plugin-react
默认启用Fast Refresh,无需额外配置。

React with SWC (Faster Alternative)

使用SWC的React配置(更快的替代方案)

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

export default defineConfig({
  plugins: [
    react({
      // SWC plugins
      plugins: [
        // Add SWC plugins here
      ]
    })
  ]
});
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';

export default defineConfig({
  plugins: [
    react({
      // SWC插件
      plugins: [
        // 在此添加SWC插件
      ]
    })
  ]
});

Environment Variables

环境变量

.env File Structure

.env文件结构

bash
undefined
bash
undefined

.env - Base config (committed)

.env - 基础配置(需提交到版本库)

VITE_APP_NAME=Demo Harness VITE_API_VERSION=v1
VITE_APP_NAME=Demo Harness VITE_API_VERSION=v1

.env.local - Local overrides (gitignored)

.env.local - 本地覆盖配置(需加入git忽略)

.env.development - Dev defaults

.env.development - 开发环境默认配置

VITE_DEBUG=true VITE_API_URL=http://dev.example.com
VITE_DEBUG=true VITE_API_URL=http://dev.example.com

.env.production - Production defaults

.env.production - 生产环境默认配置

VITE_DEBUG=false VITE_API_URL=https://api.example.com

**CRITICAL**: All env vars must start with `VITE_` to be exposed to client code.
VITE_DEBUG=false VITE_API_URL=https://api.example.com

**重要提示:** 所有环境变量必须以`VITE_`开头才能在客户端代码中访问。

Using Environment Variables

使用环境变量

typescript
// ✅ Accessing env vars in code
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE; // 'development' | 'production'

// Type-safe env vars
interface ImportMetaEnv {
  readonly VITE_APP_NAME: string;
  readonly VITE_API_URL: string;
  readonly VITE_API_VERSION: string;
  readonly VITE_DEBUG: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

// ❌ NEVER commit secrets to .env files
// Use .env.local for API keys and credentials
typescript
// ✅ 在代码中访问环境变量
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE; // 'development' | 'production'

// 类型安全的环境变量
interface ImportMetaEnv {
  readonly VITE_APP_NAME: string;
  readonly VITE_API_URL: string;
  readonly VITE_API_VERSION: string;
  readonly VITE_DEBUG: string;
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}

// ❌ 绝对不要将密钥提交到.env文件中
// 使用.env.local存储API密钥和凭证

Configuring Environment Variables

配置环境变量

typescript
import { defineConfig, loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  // Load env file based on mode
  const env = loadEnv(mode, process.cwd(), '');

  return {
    define: {
      // Expose non-VITE_ prefixed vars
      __APP_VERSION__: JSON.stringify(env.npm_package_version)
    },
    server: {
      port: Number(env.PORT) || 5173
    }
  };
});
typescript
import { defineConfig, loadEnv } from 'vite';

export default defineConfig(({ mode }) => {
  // 根据模式加载对应环境文件
  const env = loadEnv(mode, process.cwd(), '');

  return {
    define: {
      // 暴露非VITE_前缀的变量
      __APP_VERSION__: JSON.stringify(env.npm_package_version)
    },
    server: {
      port: Number(env.PORT) || 5173
    }
  };
});

Development Server

开发服务器

Basic Server Configuration

基础服务器配置

typescript
export default defineConfig({
  server: {
    port: 5173,
    strictPort: true, // Exit if port is already in use
    open: true, // Open browser on server start
    cors: true, // Enable CORS

    // Hot Module Replacement
    hmr: {
      overlay: true // Show error overlay
    },

    // File watching
    watch: {
      // Ignore dotfiles
      ignored: ['**/.*']
    }
  }
});
typescript
export default defineConfig({
  server: {
    port: 5173,
    strictPort: true, // 如果端口已被占用则退出
    open: true, // 服务器启动时自动打开浏览器
    cors: true, // 启用CORS

    // 热模块替换
    hmr: {
      overlay: true // 显示错误覆盖层
    },

    // 文件监听
    watch: {
      // 忽略点文件
      ignored: ['**/.*']
    }
  }
});

Proxy Configuration for API

API代理配置

typescript
export default defineConfig({
  server: {
    proxy: {
      // Proxy API requests to backend
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },

      // WebSocket proxy
      '/ws': {
        target: 'ws://localhost:3000',
        ws: true
      },

      // Multiple backends
      '/v1': {
        target: 'http://localhost:3001',
        changeOrigin: true
      },
      '/v2': {
        target: 'http://localhost:3002',
        changeOrigin: true
      }
    }
  }
});
typescript
export default defineConfig({
  server: {
    proxy: {
      // 将API请求代理到后端
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      },

      // WebSocket代理
      '/ws': {
        target: 'ws://localhost:3000',
        ws: true
      },

      // 多后端代理
      '/v1': {
        target: 'http://localhost:3001',
        changeOrigin: true
      },
      '/v2': {
        target: 'http://localhost:3002',
        changeOrigin: true
      }
    }
  }
});

HTTPS Development Server

HTTPS开发服务器

typescript
import { defineConfig } from 'vite';
import fs from 'node:fs';

export default defineConfig({
  server: {
    https: {
      key: fs.readFileSync('./.cert/key.pem'),
      cert: fs.readFileSync('./.cert/cert.pem')
    }
  }
});
typescript
import { defineConfig } from 'vite';
import fs from 'node:fs';

export default defineConfig({
  server: {
    https: {
      key: fs.readFileSync('./.cert/key.pem'),
      cert: fs.readFileSync('./.cert/cert.pem')
    }
  }
});

Build Optimization

构建优化

Code Splitting and Chunking

代码分割与Chunk管理

typescript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // Manual chunk splitting
        manualChunks: {
          // Vendor chunks
          'react-vendor': ['react', 'react-dom'],
          'router-vendor': ['react-router-dom'],
          'animation-vendor': ['framer-motion'],

          // Feature-based chunks
          'dashboard': ['./src/components/views/DashboardView.tsx'],
          'reports': ['./src/components/views/ReportsView.tsx']
        },

        // Asset file naming
        assetFileNames: 'assets/[name]-[hash][extname]',
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js'
      }
    },

    // Chunk size warnings
    chunkSizeWarningLimit: 500, // KB

    // Minification
    minify: 'esbuild', // 'terser' | 'esbuild'

    // Source maps
    sourcemap: true, // or 'inline' | 'hidden'

    // Target browsers
    target: 'esnext', // or 'es2015', 'es2020', etc.

    // CSS code splitting
    cssCodeSplit: true
  }
});
typescript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        // 手动分割Chunk
        manualChunks: {
          // 第三方依赖Chunk
          'react-vendor': ['react', 'react-dom'],
          'router-vendor': ['react-router-dom'],
          'animation-vendor': ['framer-motion'],

          // 基于功能的Chunk
          'dashboard': ['./src/components/views/DashboardView.tsx'],
          'reports': ['./src/components/views/ReportsView.tsx']
        },

        // 资源文件命名
        assetFileNames: 'assets/[name]-[hash][extname]',
        chunkFileNames: 'js/[name]-[hash].js',
        entryFileNames: 'js/[name]-[hash].js'
      }
    },

    // Chunk大小警告阈值
    chunkSizeWarningLimit: 500, // KB

    // 代码压缩
    minify: 'esbuild', // 可选值:'terser' | 'esbuild'

    // 源映射
    sourcemap: true, // 可选值:'inline' | 'hidden'

    // 目标浏览器
    target: 'esnext', // 可选值:'es2015', 'es2020'等

    // CSS代码分割
    cssCodeSplit: true
  }
});

Advanced Chunking Strategy

高级Chunk分割策略

typescript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // All node_modules in vendor chunk
          if (id.includes('node_modules')) {
            // Split large vendors
            if (id.includes('framer-motion')) {
              return 'vendor-animation';
            }
            if (id.includes('react') || id.includes('react-dom')) {
              return 'vendor-react';
            }
            return 'vendor';
          }

          // Component-based splitting
          if (id.includes('/components/views/')) {
            const viewName = id.split('/components/views/')[1].split('.')[0];
            return `view-${viewName.toLowerCase()}`;
          }
        }
      }
    }
  }
});
typescript
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // 所有node_modules内容放入vendor chunk
          if (id.includes('node_modules')) {
            // 分割大型依赖
            if (id.includes('framer-motion')) {
              return 'vendor-animation';
            }
            if (id.includes('react') || id.includes('react-dom')) {
              return 'vendor-react';
            }
            return 'vendor';
          }

          // 基于组件的分割
          if (id.includes('/components/views/')) {
            const viewName = id.split('/components/views/')[1].split('.')[0];
            return `view-${viewName.toLowerCase()}`;
          }
        }
      }
    }
  }
});

Compression and Minification

压缩与代码优化

typescript
import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';

// Install: pnpm add -D vite-plugin-compression2
export default defineConfig({
  plugins: [
    // Gzip compression
    compression({
      algorithm: 'gzip',
      include: /\.(js|css|html|svg)$/
    }),

    // Brotli compression
    compression({
      algorithm: 'brotliCompress',
      include: /\.(js|css|html|svg)$/
    })
  ],

  build: {
    // esbuild is faster, terser produces smaller output
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true, // Remove console.log in production
        drop_debugger: true
      }
    }
  }
});
typescript
import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';

// 安装:pnpm add -D vite-plugin-compression2
export default defineConfig({
  plugins: [
    // Gzip压缩
    compression({
      algorithm: 'gzip',
      include: /\.(js|css|html|svg)$/
    }),

    // Brotli压缩
    compression({
      algorithm: 'brotliCompress',
      include: /\.(js|css|html|svg)$/
    })
  ],

  build: {
    // esbuild速度更快,terser生成的输出体积更小
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true, // 生产环境移除console.log
        drop_debugger: true
      }
    }
  }
});

CSS and Styling

CSS与样式

PostCSS and Tailwind Integration

PostCSS和Tailwind集成

typescript
// vite.config.ts
export default defineConfig({
  css: {
    postcss: './postcss.config.js',

    // CSS modules configuration
    modules: {
      localsConvention: 'camelCase',
      scopeBehaviour: 'local'
    },

    // Preprocessor options
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`
      }
    }
  }
});
javascript
// postcss.config.js
export default {
  plugins: {
    'tailwindcss': {},
    'autoprefixer': {}
  }
};
typescript
// vite.config.ts
export default defineConfig({
  css: {
    postcss: './postcss.config.js',

    // CSS Modules配置
    modules: {
      localsConvention: 'camelCase',
      scopeBehaviour: 'local'
    },

    // 预处理器选项
    preprocessorOptions: {
      scss: {
        additionalData: `@import "@/styles/variables.scss";`
      }
    }
  }
});
javascript
// postcss.config.js
export default {
  plugins: {
    'tailwindcss': {},
    'autoprefixer': {}
  }
};

CSS Code Splitting

CSS代码分割

typescript
export default defineConfig({
  build: {
    cssCodeSplit: true, // Split CSS per chunk

    rollupOptions: {
      output: {
        assetFileNames: (assetInfo) => {
          // Organize CSS files
          if (assetInfo.name?.endsWith('.css')) {
            return 'css/[name]-[hash][extname]';
          }
          return 'assets/[name]-[hash][extname]';
        }
      }
    }
  }
});
typescript
export default defineConfig({
  build: {
    cssCodeSplit: true, // 按Chunk分割CSS

    rollupOptions: {
      output: {
        assetFileNames: (assetInfo) => {
          // 整理CSS文件
          if (assetInfo.name?.endsWith('.css')) {
            return 'css/[name]-[hash][extname]';
          }
          return 'assets/[name]-[hash][extname]';
        }
      }
    }
  }
});

Static Assets

静态资源

Asset Handling Patterns

资源处理方式

typescript
// Importing assets (returns URL string)
import logo from './assets/logo.png';
import styles from './styles.module.css';

// Explicit URL imports
import assetUrl from './asset.png?url';

// Raw content import
import rawSvg from './icon.svg?raw';

// Worker import
import Worker from './worker?worker';

// JSON import
import data from './data.json';
typescript
// 导入资源(返回URL字符串)
import logo from './assets/logo.png';
import styles from './styles.module.css';

// 显式URL导入
import assetUrl from './asset.png?url';

// 原始内容导入
import rawSvg from './icon.svg?raw';

// Worker导入
import Worker from './worker?worker';

// JSON导入
import data from './data.json';

Public Directory

公共目录

/public
  /images
    logo.svg
  /fonts
    custom-font.woff2
  favicon.ico
typescript
// Public assets are served at root and NOT processed
// Reference with absolute path
<img src="/images/logo.svg" alt="Logo" />

// ❌ Don't import from public
// import logo from '/public/images/logo.svg'; // Wrong!

// ✅ Import from src/assets for processing
import logo from '@/assets/logo.svg'; // Correct
/public
  /images
    logo.svg
  /fonts
    custom-font.woff2
  favicon.ico
typescript
// 公共目录下的资源会被部署到根路径且不经过处理
// 使用绝对路径引用
<img src="/images/logo.svg" alt="Logo" />

// ❌ 不要从public目录导入
// import logo from '/public/images/logo.svg'; // 错误!

// ✅ 从src/assets导入以进行处理
import logo from '@/assets/logo.svg'; // 正确

Asset Configuration

资源配置

typescript
export default defineConfig({
  // Public base path
  base: '/', // or '/my-app/' for subdirectory hosting

  publicDir: 'public', // Default

  build: {
    assetsDir: 'assets', // Output directory for assets
    assetsInlineLimit: 4096, // Inline assets < 4kb as base64

    rollupOptions: {
      output: {
        assetFileNames: (assetInfo) => {
          const info = assetInfo.name.split('.');
          const ext = info[info.length - 1];

          // Organize by file type
          if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
            return 'images/[name]-[hash][extname]';
          }
          if (/woff2?|ttf|otf|eot/i.test(ext)) {
            return 'fonts/[name]-[hash][extname]';
          }
          return 'assets/[name]-[hash][extname]';
        }
      }
    }
  }
});
typescript
export default defineConfig({
  // 公共基础路径
  base: '/', // 子目录部署时使用'/my-app/'

  publicDir: 'public', // 默认值

  build: {
    assetsDir: 'assets', // 资源输出目录
    assetsInlineLimit: 4096, // 小于4kb的资源会被内联为base64

    rollupOptions: {
      output: {
        assetFileNames: (assetInfo) => {
          const info = assetInfo.name.split('.');
          const ext = info[info.length - 1];

          // 按文件类型整理
          if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
            return 'images/[name]-[hash][extname]';
          }
          if (/woff2?|ttf|otf|eot/i.test(ext)) {
            return 'fonts/[name]-[hash][extname]';
          }
          return 'assets/[name]-[hash][extname]';
        }
      }
    }
  }
});

Preview Mode

预览模式

Preview Production Build

预览生产构建结果

typescript
export default defineConfig({
  preview: {
    port: 4173,
    strictPort: true,
    open: true,

    // Proxy config (same as dev server)
    proxy: {
      '/api': 'http://localhost:3000'
    },

    // CORS
    cors: true,

    // Headers
    headers: {
      'Cache-Control': 'public, max-age=31536000'
    }
  }
});
Commands:
bash
undefined
typescript
export default defineConfig({
  preview: {
    port: 4173,
    strictPort: true,
    open: true,

    // 代理配置(与开发服务器相同)
    proxy: {
      '/api': 'http://localhost:3000'
    },

    // CORS
    cors: true,

    // 请求头
    headers: {
      'Cache-Control': 'public, max-age=31536000'
    }
  }
});
命令:
bash
undefined

Build for production

执行生产构建

pnpm vite build
pnpm vite build

Preview production build locally

本地预览生产构建结果

pnpm vite preview
pnpm vite preview

Preview on specific port

在指定端口预览

pnpm vite preview --port 8080
undefined
pnpm vite preview --port 8080
undefined

Vite 7 Notes

Vite 7.x说明

Vite 7.x introduces:
  • Rolldown - New bundler written in Rust for faster builds (optional)
  • Improved TypeScript support
  • Better tree-shaking
  • Enhanced HMR performance
For demos, the default configuration works well. Advanced bundler options are not typically needed.
Vite 7.x新增特性:
  • Rolldown - 用Rust编写的新打包工具,构建速度更快(可选)
  • 改进的TypeScript支持
  • 更优的Tree-shaking
  • 增强的HMR性能
对于演示项目,默认配置已足够好用,通常不需要高级打包工具选项。

Complete Production Config

完整生产环境配置

typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compression } from 'vite-plugin-compression2';
import path from 'node:path';

export default defineConfig(({ mode }) => {
  const isDev = mode === 'development';

  return {
    plugins: [
      react(),
      // Compression for production (requires vite-plugin-compression2)
      !isDev && compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
      !isDev && compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ })
    ].filter(Boolean),

    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
        '@components': path.resolve(__dirname, './src/components'),
        '@hooks': path.resolve(__dirname, './src/hooks'),
        '@utils': path.resolve(__dirname, './src/utils'),
        '@types': path.resolve(__dirname, './src/types')
      }
    },

    server: {
      port: 5173,
      strictPort: true,
      open: true,
      hmr: {
        overlay: true
      },
      proxy: {
        '/api': {
          target: 'http://localhost:3000',
          changeOrigin: true
        }
      }
    },

    build: {
      outDir: 'dist',
      sourcemap: !isDev,
      minify: isDev ? false : 'terser',
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      },
      rollupOptions: {
        output: {
          manualChunks: {
            'react-vendor': ['react', 'react-dom'],
            'router-vendor': ['react-router-dom'],
            'animation-vendor': ['framer-motion']
          },
          assetFileNames: (assetInfo) => {
            const info = assetInfo.name.split('.');
            const ext = info[info.length - 1];
            if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
              return 'images/[name]-[hash][extname]';
            }
            if (/woff2?|ttf|otf|eot/i.test(ext)) {
              return 'fonts/[name]-[hash][extname]';
            }
            return 'assets/[name]-[hash][extname]';
          },
          chunkFileNames: 'js/[name]-[hash].js',
          entryFileNames: 'js/[name]-[hash].js'
        }
      },
      chunkSizeWarningLimit: 500
    },

    preview: {
      port: 4173,
      strictPort: true,
      open: true
    }
  };
});
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compression } from 'vite-plugin-compression2';
import path from 'node:path';

export default defineConfig(({ mode }) => {
  const isDev = mode === 'development';

  return {
    plugins: [
      react(),
      // 生产环境启用压缩(需要vite-plugin-compression2)
      !isDev && compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
      !isDev && compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ })
    ].filter(Boolean),

    resolve: {
      alias: {
        '@': path.resolve(__dirname, './src'),
        '@components': path.resolve(__dirname, './src/components'),
        '@hooks': path.resolve(__dirname, './src/hooks'),
        '@utils': path.resolve(__dirname, './src/utils'),
        '@types': path.resolve(__dirname, './src/types')
      }
    },

    server: {
      port: 5173,
      strictPort: true,
      open: true,
      hmr: {
        overlay: true
      },
      proxy: {
        '/api': {
          target: 'http://localhost:3000',
          changeOrigin: true
        }
      }
    },

    build: {
      outDir: 'dist',
      sourcemap: !isDev,
      minify: isDev ? false : 'terser',
      terserOptions: {
        compress: {
          drop_console: true,
          drop_debugger: true
        }
      },
      rollupOptions: {
        output: {
          manualChunks: {
            'react-vendor': ['react', 'react-dom'],
            'router-vendor': ['react-router-dom'],
            'animation-vendor': ['framer-motion']
          },
          assetFileNames: (assetInfo) => {
            const info = assetInfo.name.split('.');
            const ext = info[info.length - 1];
            if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
              return 'images/[name]-[hash][extname]';
            }
            if (/woff2?|ttf|otf|eot/i.test(ext)) {
              return 'fonts/[name]-[hash][extname]';
            }
            return 'assets/[name]-[hash][extname]';
          },
          chunkFileNames: 'js/[name]-[hash].js',
          entryFileNames: 'js/[name]-[hash].js'
        }
      },
      chunkSizeWarningLimit: 500
    },

    preview: {
      port: 4173,
      strictPort: true,
      open: true
    }
  };
});

Best Practices

最佳实践

  • Use path aliases for clean imports and avoid ../../../ hell
  • Prefix client env vars with VITE_ for automatic exposure
  • Split large vendors into separate chunks for better caching
  • Enable compression for production builds (gzip + brotli)
  • Use .env.local for secrets and never commit to git
  • Configure proxy for API calls to avoid CORS in development
  • Preview builds locally before deploying to catch issues
  • Organize assets by type in build output for better CDN caching
  • Enable sourcemaps in production for debugging (or use 'hidden')
  • Use esbuild for faster builds, terser for smaller output
  • Set base path correctly for subdirectory deployments
  • Test HMR after config changes to ensure Fast Refresh works
  • 使用路径别名 实现清晰的导入,避免多层相对路径
  • 客户端环境变量前缀 使用VITE_以自动暴露到代码中
  • 分割大型依赖 为独立的chunk以提升缓存效率
  • 生产构建启用压缩(gzip + brotli)
  • 使用.env.local 存储密钥,绝对不要提交到版本库
  • 配置代理 解决开发环境API请求的CORS问题
  • 部署前本地预览构建结果 提前发现问题
  • 按类型组织构建输出中的资源 优化CDN缓存
  • 生产环境启用源映射 便于调试(或使用'hidden'模式)
  • 开发环境用esbuild 提升速度,生产环境用terser减小体积
  • 子目录部署时正确设置基础路径
  • 配置变更后测试HMR 确保Fast Refresh正常工作

Anti-Patterns

反模式

  • ❌ Forgetting VITE_ prefix on environment variables
  • ❌ Importing from /public directory instead of src/assets
  • ❌ Committing .env.local with API keys
  • ❌ Not configuring path aliases (causes messy imports)
  • ❌ Using terser in development (unnecessary slowdown)
  • ❌ Disabling CSS code splitting for large apps
  • ❌ Not setting strictPort (silent port conflicts)
  • ❌ Ignoring chunk size warnings (impacts load time)
  • ❌ Missing tsconfig.json paths when using aliases
  • ❌ Hardcoding localhost URLs (use env vars)
  • ❌ Not testing preview mode before deployment
  • ❌ Placing all vendors in single chunk (defeats caching)
  • ❌ Configuring proxy for demos (demos are static, no backend)
  • ❌ 环境变量忘记添加VITE_前缀
  • ❌ 从/public目录导入资源而非src/assets
  • ❌ 提交包含API密钥的.env.local文件
  • ❌ 不配置路径别名(导致导入路径混乱)
  • ❌ 开发环境使用terser(不必要的性能损耗)
  • ❌ 大型应用禁用CSS代码分割
  • ❌ 不设置strictPort(端口冲突无提示)
  • ❌ 忽略Chunk大小警告(影响加载速度)
  • ❌ 使用别名时未同步tsconfig.json中的路径
  • ❌ 硬编码localhost地址(使用环境变量替代)
  • ❌ 部署前不测试预览模式
  • ❌ 将所有依赖放入单个chunk(失去缓存优势)
  • ❌ 演示项目配置代理(演示项目为静态资源,无后端)

Feedback Loops

反馈机制

Dev server performance:
bash
undefined
开发服务器性能:
bash
undefined

Check HMR speed

检查HMR速度

Should be < 50ms for most updates

大多数更新应小于50ms

Chrome DevTools → Network → Filter by "vite"

Chrome开发者工具 → 网络 → 筛选"vite"


**Build analysis:**
```bash

**构建分析:**
```bash

Analyze bundle size

分析包体积

pnpm vite build --mode production
pnpm vite build --mode production

Output shows chunk sizes

输出会显示各个chunk的大小

dist/js/vendor-react-abc123.js 142.34 kB

dist/js/vendor-react-abc123.js 142.34 kB

dist/js/index-def456.js 87.21 kB

dist/js/index-def456.js 87.21 kB


**Preview testing:**
```bash

**预览测试:**
```bash

Always preview before deploying

部署前务必预览

pnpm vite build && pnpm vite preview
pnpm vite build && pnpm vite preview

Test:

测试内容:

- All routes work

- 所有路由正常工作

- Assets load correctly

- 资源加载正常

- API proxy works (if configured)

- API代理正常(如果配置了)

- No console errors

- 控制台无错误


**Environment validation:**
```typescript
// Add runtime checks for required env vars
if (!import.meta.env.VITE_API_URL) {
  throw new Error('VITE_API_URL is required');
}

**环境变量验证:**
```typescript

为必填环境变量添加运行时检查

if (!import.meta.env.VITE_API_URL) { throw new Error('VITE_API_URL是必填项'); }
undefined