Chapter 03

vite.config.ts 全解

一份带类型推断的 TypeScript 配置文件,把 Vite 调校到正好满足你的项目。

3.1 配置文件的位置与格式

Vite 按以下优先级查找配置文件:

  1. vite.config.ts(推荐——有类型检查)
  2. vite.config.js
  3. vite.config.mjs / vite.config.mts
  4. 自定义位置用 vite --config ./configs/vite.js

3.2 最小配置

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

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

defineConfig 是个简单的 identity 函数,但能让 TypeScript/IDE 认出类型,获得自动补全和类型检查——强烈推荐始终用它包一层

3.3 顶层配置项

root(默认 process.cwd()
项目根目录,含 index.html。若项目结构非标准(如 monorepo 子包),明确指定。
base(默认 '/'
部署时的公共基础路径。部署到 example.com/my-app/ 要设 base: '/my-app/'
publicDir(默认 'public'
静态资源根,里面的文件原样拷贝到产物根。设为 false 禁用。
envDir / envPrefix
环境变量文件目录(默认 root)与前缀(默认 VITE_)——见第 5 章。
cacheDir(默认 node_modules/.vite
依赖预构建缓存目录。清了它相当于 --force 重新构建依赖。
mode
运行模式,命令行 --mode 覆盖。影响 import.meta.env.MODE 与加载哪个 .env 文件。

3.4 resolve:模块解析

import { resolve } from 'node:path';

defineConfig({
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src'),
      '@components': resolve(__dirname, 'src/components'),
    },
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
    // 统一选择包的 "module" / "main" 等字段顺序
    mainFields: ['module', 'jsnext:main', 'jsnext'],
    conditions: ['module', 'browser', 'development|production'],
  },
});
alias 同时要配 tsconfig

Vite 的 alias 只影响运行时;TypeScript 的类型检查会走 tsconfig 的 paths。两者必须同步:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

3.5 server:开发服务器

defineConfig({
  server: {
    host: '0.0.0.0',      // 让局域网可访问
    port: 5173,
    strictPort: true,     // 端口被占就报错,而不是自增
    open: true,           // 启动自动打开浏览器
    https: false,
    cors: true,

    proxy: {                // 反向代理后端
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (p) => p.replace(/^\/api/, ''),
      },
      '/socket.io': {
        target: 'ws://localhost:3000',
        ws: true,
      },
    },

    watch: {
      ignored: ['**/node_modules/**', '**/dist/**'],
    },
  },
});

3.6 build:生产构建

defineConfig({
  build: {
    outDir: 'dist',
    assetsDir: 'assets',            // 产物中静态资源子目录
    assetsInlineLimit: 4096,         // <4KB 的资源 inline 成 base64
    cssCodeSplit: true,              // 每个 chunk 的 CSS 分开
    sourcemap: false,                // 生产不生成 sourcemap
    minify: 'esbuild',               // 'esbuild' | 'terser' | false
    target: 'es2020',               // 输出目标,决定降级
    chunkSizeWarningLimit: 500,      // kB,超过警告

    rollupOptions: {                 // 透传给 Rollup
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom'],
          utils: ['lodash-es', 'date-fns'],
        },
      },
    },
  },
});

manualChunks:代码分割

按"业务变化频率"把包分组——vendor(几乎不变)单独成 chunk,浏览器长期缓存;业务代码频繁变,hash 变,但只这个小 chunk 重下载。

3.7 optimizeDeps:依赖预构建

defineConfig({
  optimizeDeps: {
    include: ['lodash-es', 'axios'],   // 强制预构建
    exclude: ['@your-scope/pkg'],       // 不要预构建(调试 monorepo 时有用)
    force: false,                         // 清缓存重新构建(一次性用命令行 --force)
  },
});

3.8 css / preview / worker 等

defineConfig({
  css: {
    modules: {
      localsConvention: 'camelCaseOnly',
    },
    preprocessorOptions: {
      scss: { additionalData: `@use "@/styles/vars.scss" as *;` },
    },
    devSourcemap: true,
  },

  preview: {
    port: 4173,
    strictPort: true,
  },

  worker: {
    format: 'es',                // worker 产物格式
    plugins: () => [],
  },
});

3.9 条件配置:函数形式

dev 和 build 用不同配置?把导出改成函数:

export default defineConfig(({ command, mode, isSsrBuild }) => {
  if (command === 'serve') {
    return {
      // dev 独有配置
      define: { __DEV__: true },
    };
  } else {
    return {
      // build 独有
      define: { __DEV__: false },
    };
  }
});

参数:

3.10 类型完整的完整示例

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
import { resolve } from 'node:path';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  return {
    base: env.VITE_BASE ?? '/',
    plugins: [react(), tsconfigPaths()],
    resolve: {
      alias: { '@': resolve(__dirname, 'src') },
    },
    server: {
      port: 5173,
      proxy: {
        '/api': { target: env.VITE_API_URL, changeOrigin: true },
      },
    },
    build: {
      target: 'es2022',
      sourcemap: mode === 'staging',
      rollupOptions: {
        output: {
          manualChunks: {
            react: ['react', 'react-dom'],
            router: ['react-router-dom'],
          },
        },
      },
    },
  };
});

3.11 小结