Vite 是当前前端工程里最值得掌握的构建工具之一。它的核心思路很直接:开发时利用浏览器原生 ESM 按需加载,借助高性能预构建和插件体系,把“启动慢、热更新慢、构建慢”这些老问题尽量压到最低。

如果你已经熟悉 Webpack,那么理解 Vite 的方式可以简单粗暴一点:它不是在开发阶段先把整个应用打成一个大包再提供给浏览器,而是让浏览器直接加载源码模块,只有确实需要的依赖和资源才会被处理。这样一来,项目越大,体验差异越明显。

Vite 到底解决了什么

传统打包器在开发模式下通常要做两件事:分析依赖图和重新生成 bundle。项目一旦变大,这个过程就会变慢,热更新也会被牵连。Vite 则把开发期和生产期分开处理:开发期更像一个高性能的本地服务器,生产期才交给 Rollup 做最终打包。

它的优势主要体现在几个方面。

  • 启动快:不用先全量打包,直接启动开发服务器。
  • HMR 快:热更新只影响变化的模块,而不是整个应用。
  • 配置相对简单:大多数常见场景开箱即用。
  • 插件生态清晰:开发和构建阶段都能通过插件扩展。

对于 Vue、React、Svelte、Solid 这类现代框架,Vite 基本已经是默认推荐方案。

创建项目

Vite 官方脚手架非常直接,支持多种模板。

bun create vite@latest my-app -- --template vue-ts
bun create vite@latest my-app -- --template react-ts
bun create vite@latest my-app -- --template vanilla-ts

创建后进入目录并启动:

cd my-app
bun install
bun run dev

默认情况下,开发服务器会运行在本地端口上,浏览器访问提示的地址即可。

一个标准的项目结构

Vite 项目一般会有这样的目录:

my-app/
	index.html
	src/
		main.ts
		App.vue
		assets/
	public/
	vite.config.ts
	package.json

其中 index.html 不是传统意义上的“只做壳子”的文件,它本身就是 Vite 的入口之一。Vite 会从这里开始接管页面和模块加载流程。

核心概念

理解 Vite,最重要的是抓住下面几个关键词。

原生 ESM

开发阶段,Vite 直接依赖浏览器对 ESM 的支持。模块通过 import 按需加载,减少了初始启动成本,也让模块边界更清晰。

依赖预构建

第三方依赖通常并不是完全按源码逐个请求的。Vite 会用 esbuild 对依赖做预构建,把一些 CommonJS 或复杂依赖转换成更适合浏览器和开发服务器处理的形式。

按需编译

只有被访问到的文件才会被处理。你改一个组件,热更新时一般只会影响这个组件相关的最小范围。

Rollup 负责生产构建

Vite 的开发体验和生产构建是两套逻辑。开发期追求速度,生产期则交给 Rollup 做代码分割、压缩和最终产物输出。

基础配置

最常见的配置文件是 vite.config.ts

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

export default defineConfig({
	plugins: [vue()],
	resolve: {
		alias: {
			'@': resolve(__dirname, 'src'),
		},
	},
	server: {
		port: 3000,
		open: true,
		proxy: {
			'/api': {
				target: 'http://localhost:8080',
				changeOrigin: true,
			},
		},
	},
	build: {
		outDir: 'dist',
		sourcemap: true,
		rollupOptions: {
			output: {
				manualChunks: {
					vendor: ['vue', 'vue-router'],
				},
			},
		},
	},
});

这里最常用的几个配置项是:

  • plugins:安装框架插件和第三方插件。
  • resolve.alias:配置路径别名,减少相对路径层级。
  • server.proxy:本地开发时转发接口请求,规避跨域问题。
  • build.outDir:控制产物目录。
  • build.rollupOptions:做更细的打包优化。

如果你使用 TypeScript,建议把别名同步到 tsconfig.json,否则编辑器和构建器可能出现路径认知不一致的问题。

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

环境变量

Vite 的环境变量有一个非常明确的约定:只有以 VITE_ 开头的变量,才会暴露到前端代码里。

# .env
VITE_API_URL=http://api.example.com

# .env.production
VITE_API_URL=https://api.example.com

代码中这样读取:

const apiUrl = import.meta.env.VITE_API_URL;

常见的几个环境文件如下:

  • .env:所有环境都生效。
  • .env.development:开发环境生效。
  • .env.production:生产环境生效。
  • .env.local:本地个人配置,通常不建议提交。

注意一点:前端环境变量不是秘密管理系统。不要把真正敏感的信息直接塞进 VITE_ 变量里,因为它最终会被打进客户端代码。

插件系统

Vite 最好用的部分之一就是插件生态。常见插件包括 Vue、React、包体积分析、压缩、SVG 处理等。

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
import compression from 'vite-plugin-compression';

export default defineConfig({
	plugins: [
		vue(),
		visualizer(),
		compression(),
	],
});

如果是 Vue 项目,最常见的是 @vitejs/plugin-vue。如果是 React 项目,通常使用 @vitejs/plugin-react。生产环境如果需要做 gzip 或 brotli 压缩,也可以靠插件完成。

常用开发能力

代理接口

本地前端开发时,接口地址通常和后端不在一个源上。与其在代码里写一堆跨域处理,不如直接交给代理。

server: {
	proxy: {
		'/api': {
			target: 'http://localhost:8080',
			changeOrigin: true,
			rewrite: (path) => path.replace(/^\/api/, ''),
		},
	},
}

这种做法适合本地联调,生产环境仍然应该由真实网关或反向代理处理。

静态资源

放在 src 里的资源可以被构建器追踪和处理,放在 public 里的资源则会被原样拷贝。

import logoUrl from './assets/logo.svg';

对于需要参与打包处理、哈希命名和引用分析的资源,优先放在源码目录里。对于完全静态、不需要处理的文件,再考虑 public

导入 CSS

Vite 对 CSS 的支持是开箱即用的,样式文件可以像模块一样直接导入。

import './style.css';

如果是预处理器,比如 Sass,也可以直接在配置里统一注入变量或混入。

css: {
	preprocessorOptions: {
		scss: {
			additionalData: '@use "./src/styles/vars.scss" as *;'
		},
	},
}

生产构建

开发好用只是第一步,生产构建才决定你能不能放心上线。

bun run build
bun run preview

build 会生成最终产物,preview 则用于本地预览构建结果。后者非常适合上线前做最后确认,因为它更接近真实部署环境。

构建优化建议

如果项目体积开始变大,可以考虑下面这些手段。

  • manualChunks 拆分第三方包。
  • 用动态导入拆分路由和大组件。
  • 减少一次性引入的大型工具库。
  • 开启构建分析,找出真正的体积大头。
const UserPage = () => import('./pages/UserPage.vue');

路由级懒加载通常是最划算的优化之一。

常见工程化组合

Vite 往往不是单独使用的,它通常和下面这些工具搭配。

ESLint + Prettier

用于保持代码风格一致、提前发现错误。

Vitest

Vite 生态下的测试工具,配置和运行体验都比较顺手。

Tailwind CSS

适合快速搭建界面,尤其是组件化风格比较强的项目。

Storybook

适合做组件开发和视觉回归。

如果你的项目是 Vue 3 + TypeScript,那么一个比较稳妥的组合通常是:Vite + Vue Router + Pinia + Vitest + ESLint。

常见坑

1. 忘记加 VITE_ 前缀

前端代码里读取不到没有前缀的环境变量,这是最常见的问题之一。

2. 把敏感信息放进前端环境变量

只要进了前端包,就等于公开了。不要把密钥、私服密码、真实 token 直接放进去。

3. 别名只配了一边

如果只配了 Vite 的别名,TypeScript 和编辑器可能还是会报路径找不到。构建配置和类型配置要保持同步。

4. 误把 public 当源码目录

public 里的文件不会像源码那样参与模块解析,引用方式也不同。它更像纯静态资源仓库。

5. 插件装太多

Vite 插件体验很好,但并不意味着越多越好。插件过多会增加维护成本,也可能拖慢启动和构建。

什么时候不该用 Vite

大多数现代前端项目都适合 Vite,但也有少数情况需要谨慎。

  • 你依赖非常重的老旧构建链,迁移成本很高。
  • 你的项目有特别复杂的自定义编译流程,现有方案已经高度定制。
  • 你不是在做浏览器前端,而是在做别的类型的打包任务。

对绝大多数 SPA、组件库、后台管理系统、内容站点来说,Vite 都是一个很稳的默认选择。

一个推荐的起步模板

如果你想快速开工,可以把项目起步标准定成下面这样:

bun create vite@latest my-app -- --template vue-ts
cd my-app
bun install
bun add vue-router pinia
bun add -D vitest eslint prettier @vitejs/plugin-vue
bun run dev

然后再补齐这些基础能力:

  • 路由按需加载。
  • 统一的 API 封装。
  • 环境变量分层。
  • 构建产物分析。
  • 测试和 lint 接入 CI。

总结

Vite 的本质不是“另一个打包器”,而是一种更适合现代前端开发的工程组织方式。它把开发期的低延迟体验、生产期的稳定打包、插件扩展能力和框架生态结合得比较好,所以才会成为今天很多项目的默认选项。

如果你刚开始接触 Vite,先把这几件事吃透就够了:原生 ESM、环境变量规则、插件机制、代理配置、生产构建。掌握这些之后,再去看更进阶的内容,比如 SSR、库模式打包、Monorepo 集成,就会顺很多。