Communitygithub.com

Vite 模式

Vite 构建工具模式,涵盖配置、插件、HMR、环境变量、代理设置、SSR、库模式、依赖预构建和构建优化。当使用 vite.config.ts、Vite 插件或基于 Vite 的项目时激活。

Vite 模式 是什么?

该技能为使用 Vite 8+ 的项目提供了全面的构建工具和开发服务器模式。它涵盖了配置、环境变量、代理设置、库模式、依赖预构建以及常见的生产环境陷阱。该技能适用于配置 vite.config.ts、设置 .env 文件、优化构建输出以及发布库等场景。它解释了 Vite 在开发模式下作为原生 ESM 模块服务器、在生产模式下使用 Rolldown 或 Rollup 进行打包、以及使用 esbuild 进行依赖预构建的工作原理。该技能还提供了关于插件、HMR API、安全实践(如 VITE_ 前缀边界)和性能优化(如避免桶文件和使用显式导入扩展)的实用示例。它被优化用于 Claude Code、Cursor 和 Codex 等 AI 编码代理。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/vite-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Vite 模式 是做什么的?

适用于 Vite 8+ 项目的构建工具和开发服务器模式。涵盖配置、环境变量、代理设置、库模式、依赖预构建和常见生产陷阱。

使用时机

  • 配置 vite.config.ts 或 vite.config.js
  • 设置环境变量或 .env 文件
  • 配置开发服务器代理以实现 API 后端
  • 优化构建输出(代码分割、压缩、资源)
  • 使用 build.lib 发布库
  • 调试依赖预构建或 CJS/ESM 互操作
  • 调试 HMR、开发服务器或构建错误
  • 选择或排序 Vite 插件

工作原理

  • 开发模式 将源文件作为原生 ESM 提供 —— 不进行打包。转换按需在每个模块请求时进行,这就是为什么冷启动快且 HMR 精确。
  • 构建模式 使用 Rolldown (v7+) 或 Rollup (v5–v6) 打包应用程序以用于生产,具有树摇、代码分割和基于 Oxc 的压缩功能。
  • 依赖预构建 使用 esbuild 将 CJS/UMD 依赖转换为 ESM 一次,并将结果缓存在 node_modules/.vite 下,以便后续启动跳过此工作。
  • 插件 在开发和生产之间共享统一的接口 —— 相同的插件对象既适用于开发服务器的按需转换,也适用于生产管道。
  • 环境变量 在构建时静态内联。VITE_ 前缀的变量成为打包后的公共常量;没有前缀的变量对客户端代码不可见。

示例

配置结构

基本配置

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

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: { '@': new URL('./src', import.meta.url).pathname },
  },
})

条件配置

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

export default defineConfig(({ command, mode }) => {
  const env = loadEnv(mode, process.cwd())   // 仅 VITE_ 前缀(安全)

  return {
    plugins: [react()],
    server: command === 'serve' ? { port: 3000 } : undefined,
    define: {
      __API_URL__: JSON.stringify(env.VITE_API_URL),
    },
  }
})

关键配置选项

键默认值描述
root'.'项目根目录(index.html 所在位置)
base'/'部署资源的公共基础路径
envPrefix'VITE_'客户端暴露环境变量的前缀
build.outDir'dist'输出目录
build.minify'oxc'压缩器('oxc'、'terser' 或 false)
build.sourcemapfalsetrue、'inline' 或 'hidden'

插件

必备插件

大部分插件需求由少数几个维护良好的包覆盖。在编写自己的插件之前,优先使用这些。

插件用途使用时机
@vitejs/plugin-react-swc通过 SWC 实现 React HMR + 快速刷新React 应用的默认选择(比 Babel 变体更快)
@vitejs/plugin-react通过 Babel 实现 React HMR + 快速刷新仅当你需要 Babel 插件时(emotion、MobX 装饰器)
@vitejs/plugin-vueVue 3 SFC 支持Vue 应用
vite-plugin-checker在工作线程中运行 tsc + ESLint,并带有 HMR 覆盖层任何 TypeScript 应用 —— Vite 在 vite build 期间不进行类型检查
vite-tsconfig-paths遵守 tsconfig.json 中的 paths 别名任何已在 tsconfig.json 中有别名的情况
vite-plugin-dts在库模式下生成 .d.ts 文件发布 TypeScript 库
vite-plugin-svgr将 SVG 导入为 React 组件使用 SVG 作为组件的 React 应用
rollup-plugin-visualizer打包树图/旭日图报告定期打包大小审计(使用 enforce: 'post')
vite-plugin-pwa零配置 PWA + Workbox支持离线功能的应用

关键提示: vite build 会转译但不会进行类型检查。除非添加 vite-plugin-checker 或在 CI 中运行 tsc --noEmit,否则类型错误会静默地进入生产环境。

编写自定义插件

编写自定义插件的情况很少见 —— 大多数需求已被现有插件覆盖。当你确实需要一个时,从在 vite.config.ts 中内联开始,只有在重复使用时才提取出来。

// vite.config.ts —— 最小内联插件
function myPlugin(): Plugin {
  return {
    name: 'my-plugin',                       // 必需,必须唯一
    enforce: 'pre',                           // 'pre' | 'post'(可选)
    apply: 'build',                           // 'build' | 'serve'(可选)
    transform(code, id) {
      if (!id.endsWith('.custom')) return
      return { code: transformCustom(code), map: null }
    },
  }
}

关键钩子: transform(修改源码)、resolveId + load(虚拟模块)、transformIndexHtml(注入 HTML)、configureServer(添加开发中间件)、hotUpdate(自定义 HMR —— 在 v7+ 中取代已弃用的 handleHotUpdate)。

虚拟模块 使用 \0 前缀约定 —— resolveId 返回 '\0virtual:my-id',这样其他插件会跳过它。用户代码导入 'virtual:my-id'。

有关完整插件 API,请参阅 vite.dev/guide/api-plugin。在开发过程中使用 vite-plugin-inspect 调试转换管道。

HMR API

框架插件(@vitejs/plugin-react、@vitejs/plugin-vue 等)会自动处理 HMR。仅在构建自定义状态存储、开发工具或需要跨更新持久化状态的与框架无关的工具时,才直接使用 import.meta.hot。

// src/store.ts —— 普通模块的手动 HMR
if (import.meta.hot) {
  // 跨更新持久化状态(必须 修改,绝不能重新赋值 .data)
  import.meta.hot.data.count = import.meta.hot.data.count ?? 0

  // 在模块被替换之前清理副作用
  import.meta.hot.dispose((data) => clearInterval(data.intervalId))

  // 接受此模块自身的更新
  import.meta.hot.accept()
}

所有 import.meta.hot 代码在生产构建中都会被树摇掉 —— 无需移除保护代码。

环境变量

Vite 按顺序加载 .env、.env.local、.env.[mode] 和 .env.[mode].local(后面的覆盖前面的);*.local 文件被 gitignore,用于本地密钥。

客户端访问

只有 VITE_ 前缀的变量会暴露给客户端代码:

import.meta.env.VITE_API_URL   // 字符串
import.meta.env.MODE            // 'development' | 'production' | 自定义
import.meta.env.BASE_URL        // base 配置值
import.meta.env.DEV             // 布尔值
import.meta.env.PROD            // 布尔值
import.meta.env.SSR             // 布尔值

在配置中使用环境变量

// vite.config.ts
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd())          // 仅 VITE_ 前缀(安全)
  return {
    define: {
      __API_URL__: JSON.stringify(env.VITE_API_URL),
    },
  }
})

安全

VITE_ 前缀不是安全边界

任何以 VITE_ 为前缀的变量在构建时都会被静态内联到客户端打包产物中。压缩、Base64 编码和禁用源映射不会隐藏它。一个坚定的攻击者可以从已发布的 JavaScript 中提取任何 VITE_ 变量。

规则: 只有公共值(API URL、特性标志、公钥)放入 VITE_ 变量。密钥(API 令牌、数据库 URL、私钥)必须位于服务器端,通过 API 或无服务器函数提供。

loadEnv('') 陷阱

// 错误:将 '' 作为第三个参数传递会加载所有环境变量 —— 包括服务器密钥 ——
// 并使它们可通过 `define` 内联到客户端代码中。
const env = loadEnv(mode, process.cwd(), '')

// 正确:显式前缀列表
const env = loadEnv(mode, process.cwd(), ['VITE_', 'APP_'])

生产环境中的源映射

生产环境中的源映射会泄露你的原始源代码。除非你上传到错误跟踪器(Sentry、Bugsnag)并在本地删除,否则请禁用它:

build: {
  sourcemap: false,                                  // 默认 —— 保持这种方式
}

.gitignore 清单

  • .env.local、.env.*.local —— 本地密钥覆盖
  • dist/ —— 构建输出
  • node_modules/.vite —— 预构建缓存(过时的条目会导致幽灵错误)

服务器代理

// vite.config.ts —— server.proxy
server: {
  proxy: {
    '/foo': 'http://localhost:4567',                    // 字符串简写

    '/api': {
      target: 'http://localhost:8080',
      changeOrigin: true,                               // 虚拟主机后端需要此项
      rewrite: (path) => path.replace(/^\/api/, ''),
    },
  },
}

要启用 WebSocket 代理,请将 ws: true 添加到路由配置中。

构建优化

手动代码分割

// vite.config.ts —— build.rolldownOptions
build: {
  rolldownOptions: {
    output: {
      // 对象形式:分组特定包
      manualChunks: {
        'react-vendor': ['react', 'react-dom'],
        'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-popover'],
      },
    },
  },
}
// 函数形式:按启发式规则分割
manualChunks(id) {
  if (id.includes('node_modules/react')) return 'react-vendor'
  if (id.includes('node_modules')) return 'vendor'
}

性能

避免桶文件

桶文件(从目录中重新导出所有内容的 index.ts)会强制 Vite 加载每个重新导出的文件,即使你只导入单个符号。这是官方文档指出的头号开发服务器减速原因。

// 错误 —— 导入一个工具函数会强制 Vite 加载整个桶文件
import { slash } from '@/utils'

// 正确 —— 直接导入,只加载一个文件
import { slash } from '@/utils/slash'

使用显式导入扩展名

每个隐式扩展名会通过 resolve.extensions 强制进行多达 6 个文件系统检查。在大型代码库中,这会累积起来。

// 错误
import Component from './Component'

// 正确
import Component from './Component.tsx'

将 tsconfig.json 中的 allowImportingTsExtensions 和 resolve.extensions 限制为你实际使用的扩展名。

预热热路径路由

server.warmup.clientFiles 在浏览器请求之前预先转换已知的热点入口 —— 消除了大型应用中的冷加载请求瀑布。

// vite.config.ts
server: {
  warmup: {
    clientFiles: ['./src/main.tsx', './src/routes/**/*.tsx'],
  },
}

分析慢速开发服务器

当 vite dev 感觉缓慢时,从 vite --profile 开始,与应用程序交互,然后按 p+enter 保存 .cpuprofile。在 Speedscope 中加载它,找出哪些插件消耗了时间 —— 通常是社区插件中的 buildStart、config 或 configResolved 钩子。

库模式

发布 npm 包时,使用 build.lib。两个常见陷阱比配置细节更重要:

  1. 不会生成类型声明 —— 添加 vite-plugin-dts 或单独运行 tsc --emitDeclarationOnly。
  2. 对等依赖必须外部化 —— 未列出的对等依赖会被打包到你的库中,导致消费者出现重复运行时错误。
// vite.config.ts
build: {
  lib: {
    entry: 'src/index.ts',
    formats: ['es', 'cjs'],
    fileName: (format) => `my-lib.${format}.js`,
  },
  rolldownOptions: {
    external: ['react', 'react-dom', 'react/jsx-runtime'],  // 每个对等依赖
  },
}

SSR 外部化

裸 createServer({ middlewareMode: true }) 设置属于框架作者的领域。大多数应用应使用 Nuxt、Remix、SvelteKit、Astro 或 TanStack Start。作为框架用户,你需要调整的是当依赖在 SSR 中损坏时的外部化配置:

// vite.config.ts —— ssr 选项
ssr: {
  external: ['node-native-package'],           // 在 SSR 打包中保持为 require()
  noExternal: ['esm-only-package'],            // 强制打包到 SSR 输出中(修复大多数 SSR 错误)
  target: 'node',                              // 'node' 或 'webworker'
}

依赖预构建

Vite 预构建依赖以将 CJS/UMD 转换为 ESM 并减少请求数量。

// vite.config.ts —— optimizeDeps
optimizeDeps: {
  include: [
    'lodash-es',                              // 强制预构建已知的重量级依赖
    'cjs-package',                            // 导致互操作问题的 CJS 依赖
    'deep-lib/components/**',                 // 深度导入的通配符模式
  ],
  exclude: ['local-esm-package'],             // 如果排除,则必须是有效的 ESM
  force: true,                                // 忽略缓存,重新优化(临时调试)
}

常见陷阱

开发与构建不一致

开发使用 esbuild/Rolldown 进行转换;构建使用 Rolldown 进行打包。CJS 库在这两者之间可能表现不同。在部署前始终验证 vite build && vite preview。

部署后过时的块

新构建产生新的块哈希。有活动会话的用户会请求不再存在的旧文件名。Vite 没有内置的解决方案。缓解措施:

  • 在部署窗口期间保留旧的 dist/assets/ 文件
  • 在路由器中捕获动态导入错误并强制页面重新加载

Docker 和容器

Vite 默认绑定到 localhost,这从容器外部无法访问:

// vite.config.ts —— Docker/容器设置
server: {
  host: true,                                  // 绑定 0.0.0.0
  hmr: { clientPort: 3000 },                   // 如果在反向代理后面
}

单体仓库文件访问

Vite 将文件服务限制在项目根目录。根目录外的包会被阻止:

// vite.config.ts —— 单体仓库文件访问
server: {
  fs: {
    allow: ['..'],                             // 允许父目录(工作区根目录)
  },
}

反模式

// 错误:将 envPrefix 设置为 '' 会向客户端暴露所有环境变量(包括密钥)
envPrefix: ''

// 错误:假设 require() 在 Vite 构建中有效

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能