Communitygithub.com

Vite 模式

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

Vite 模式 是什么?

该技能旨在为使用 Vite 8+ 构建工具的项目提供全面的模式和实践指南。内容涵盖配置结构、环境变量、开发服务器代理、库模式、依赖预构建以及常见的生产环境陷阱。它详细介绍了 Vite 在开发模式下通过按需转换实现快速冷启动和精准 HMR 的工作原理,以及使用 Rolldown 或 Rollup 进行生产构建的流程。技能还强调了关键的插件选择(如 `vite-plugin-checker` 用于类型检查)、HMR API 的手动使用场景、环境变量的安全性注意事项(如 `VITE_` 前缀并非安全边界),以及构建优化技巧(如避免桶文件(barrel files)、明确导入扩展名)。此外,还包括了性能分析、库模式下的类型导出和外部化依赖、SSR 配置、Docker 和 Monorepo 环境下的特定配置,以及常见的反模式。该技能支持 Cursor、Claude Code 等 AI 代理工具,为开发者提供即用型代码示例和基准配置。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/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 + Fast RefreshReact 应用的默认选择(比 Babel 变体更快)
@vitejs/plugin-react通过 Babel 实现 React HMR + Fast Refresh仅在需要 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) {
  // 在更新之间持久化状态(必须 MUTATE,绝不能重新赋值 .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 编码和禁用 source map 都无法隐藏它。一个坚定的攻击者可以从已发布的 JavaScript 中提取任何 VITE_ 变量。

规则: 只有公共值(API URL、功能标志、公钥)才能放入 VITE_ 变量中。机密(API 令牌、数据库 URL、私钥)必须通过 API 或无服务器函数驻留在服务器端。

loadEnv('') 陷阱

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

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

生产环境中的 Source Map

生产环境中的 source map 会泄露您的原始源代码。除非您将 source map 上传到错误跟踪器(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/**',                 // 深度导入的 glob 模式
  ],
  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 },                   // 如果在反向代理后面
}

Monorepo 文件访问

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

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

反模式

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

// 错误:假设 require() 在 Vite 中有效(除非明确配置 SSR 外部化)
const fs = require('fs')

// 错误:依赖 CJS 仅在构建时有效;在开发模式下,包被作为 ESM 提供

// 错误:在生产构建中保留 source map,除非上传到错误跟踪器并在本地删除
build: {
  sourcemap: true
}

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/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

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.

相关技能