Vite 与新一代构建
Vite 由 Vue 作者尤雨溪开发,名字取自法语"快"(Vitesse)。它充分利用浏览器原生 ESM 能力,把"开发体验"做到了极致——冷启动毫秒级、HMR 亚秒级。理解它,就理解了现代前端构建的新范式。
一、核心思想:基于原生 ESM
传统构建工具(Webpack)的开发模式:先打包全部模块再启动服务器,项目越大启动越慢。Vite 反其道而行:
| 维度 | Webpack | Vite |
|---|---|---|
| 开发时 | 先打包成 bundle 再提供 | 不打包,浏览器直接请求源码 |
| 依赖处理 | 全部进依赖图 | 预构建缓存,天然缓存 |
| 模块加载 | 打包产物 | 浏览器原生 ESM import |
| 冷启动 | 随项目增大而变慢 | 基本恒定,秒级 |
<!-- Vite 开发服务器返回的就是原生 ESM,浏览器直接执行 -->
<script type="module" src="/src/main.js"></script>// src/main.js 里的 import 直接请求对应文件
import { createApp } from "vue"; // 请求 /node_modules/.vite/deps/vue.js
import App from "./App.vue"; // 请求 /src/App.vue(按需编译)Vite 开发模式的核心公式:源码按需编译 + 依赖预构建 = 与项目规模基本无关的启动速度。
二、创建项目
npm create vite@latest my-app # 交互式选择模板
npm create vite@latest my-app -- --template vue # 直接指定模板
cd my-app && npm install && npm run dev| 模板 | 说明 |
|---|---|
vanilla | 纯 JavaScript,无框架 |
vue / vue-ts | Vue 3 单文件组件(含 TypeScript 版) |
react / react-ts | React(含 TypeScript 版) |
svelte、solid、lit | 其他框架模板 |
vanilla-ts | 原生 TypeScript |
生成的目录结构:
my-app/
index.html # 真正的入口文件(含 <script type="module">)
vite.config.js # 配置文件
src/ # 源码目录
public/ # 静态资源,原样复制三、开发服务器原理
3.1 esbuild 预构建依赖
启动时,Vite 先用 esbuild(Go 编写的超快转译器)把第三方依赖"预构建":把 CommonJS/UMD 依赖转成 ESM、把分散的依赖合并,并写入 node_modules/.vite 缓存:
依赖(vue、lodash 等几百个文件)
→ esbuild 预构建
→ .vite/deps/vue.js(合并为少量 ESM 文件)
→ 浏览器一次请求即可,且结果带强缓存好处:浏览器请求依赖时不用逐个下载几百个文件;依赖版本不变则预构建结果复用,秒级启动。
3.2 按需编译
源码不预编译,只有当浏览器请求到某个文件时,Vite 才用 esbuild 转译它(剥 TypeScript、转 JSX),这就是"按需编译"。首次访问页面只编译被用到的模块,而不是整个项目。
3.3 HMR 快速更新
Vite 的 HMR 基于原生 ESM:哪个模块变了,就通过 WebSocket 只推送那个模块的更新,浏览器重新请求该模块并执行替换。由于不经过打包器,更新速度与项目规模几乎无关。
// Vite 的 HMR API(框架插件已自动接入)
import.meta.hot?.accept((mod) => {
// 模块更新后的处理
});四、生产构建:Rollup
开发用 esbuild、生产用 Rollup 是 Vite 的设计选择:esbuild 快但产物压缩与代码分割不如 Rollup 精细,Rollup 成熟稳定且对 ESM 与 Tree Shaking 支持极好。
npm run build # rollup 打包到 dist/build 过程
→ Rollup 分析依赖图
→ 代码分割(动态 import 自动拆 chunk)
→ Tree Shaking 摇掉死代码
→ 压缩产物 + 生成 sourcemap// 动态 import 在生产构建中自动拆分为独立 chunk
const Admin = () => import("./views/Admin.vue");// build.rollupOptions 可自定义输出
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: { vue: ["vue", "vue-router", "pinia"] },
},
},
},
});五、配置文件
5.1 基本结构
// vite.config.js
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { fileURLToPath, URL } from "node:url";
export default defineConfig({
plugins: [vue()], // 插件
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)), // 路径别名
},
},
server: {
port: 5173,
proxy: { // 开发代理
"/api": {
target: "http://localhost:8080",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
});5.2 alias 与 proxy
| 配置 | 作用 |
|---|---|
resolve.alias | 路径别名,如 @ 指向 src,避免深层次相对路径 |
server.proxy | 开发环境代理 /api 到后端,解决跨域,无需后端配 CORS |
server.hmr | 自定义 HMR 的 WebSocket 配置(如局域网访问) |
base | 部署到子路径时设置,如 base: "/app/" |
六、环境变量
6.1 import.meta.env
Vite 内置的环境变量统一挂在 import.meta.env 上:
| 变量 | 含义 |
|---|---|
import.meta.env.MODE | 当前模式(development/production) |
import.meta.env.DEV | 是否开发环境 |
import.meta.env.PROD | 是否生产环境 |
import.meta.env.SSR | 是否服务端渲染 |
import.meta.env.BASE_URL | base 配置值 |
6.2 .env 文件
# .env 所有环境共享
VITE_API_BASE=https://api.example.com
# .env.development 开发环境
VITE_DEBUG=true
# .env.production 生产环境
VITE_API_BASE=https://api.prod.example.com// 只有 VITE_ 前缀的变量会暴露给客户端代码
console.log(import.meta.env.VITE_API_BASE);
// 避免把密钥写进 VITE_ 前缀变量(会打进产物)| 文件 | 加载时机 |
|---|---|
.env | 所有模式 |
.env.development | vite(开发模式) |
.env.production | vite build(生产模式) |
.env.local | 本地覆盖,不提交 git |
七、常用插件
| 插件 | 作用 |
|---|---|
@vitejs/plugin-vue | 支持 .vue 单文件组件 |
@vitejs/plugin-react | 支持 React JSX 与 Fast Refresh |
@vitejs/plugin-legacy | 通过 Babel 转译 + polyfill 兼容旧浏览器 |
vite-plugin-svg-icons | SVG 雪碧图 |
vite-plugin-compression | 产物 gzip/brotli 压缩 |
import legacy from "@vitejs/plugin-legacy";
export default defineConfig({
plugins: [
vue(),
legacy({ targets: ["defaults", "ie >= 11"] }), // 需要兼容 IE 时才启用
],
});八、Vite vs Webpack 对比
| 维度 | Webpack | Vite |
|---|---|---|
| 开发原理 | 全量打包 | 原生 ESM + 按需编译 |
| 冷启动 | 慢(随项目增大而变慢) | 快(与项目规模基本无关) |
| HMR 速度 | 中 | 快(模块级精准更新) |
| 转译器 | Babel(JavaScript 转译) | esbuild(依赖)、Rollup(产物) |
| 生产打包 | 自研打包 | Rollup |
| 兼容性 | 支持老浏览器与老语法(可配置) | 现代浏览器为主,老浏览器需 legacy 插件 |
| 配置复杂度 | 较高(loader/plugin 繁多) | 低(约定优于配置) |
| 生态成熟度 | 极高,插件海量 | 快速成长,主流框架全覆盖 |
| 适用场景 | 复杂老项目、强定制构建 | 新项目、追求开发体验、中小型应用 |
怎么选:新项目优先 Vite(Vue 官方脚手架已是 Vite);存量 Webpack 项目若非必要不必强行迁移,两者各有适用边界。
九、构建优化实践
export default defineConfig({
build: {
chunkSizeWarningLimit: 1500, // 调整 chunk 体积告警阈值
sourcemap: false, // 生产默认不产 sourcemap(需排错时再开)
target: "es2019", // 产物目标语法,越低兼容越好、体积越大
rollupOptions: {
output: {
// 大依赖单独拆包,配合浏览器缓存
manualChunks(id) {
if (id.includes("node_modules")) {
if (id.includes("echarts")) return "echarts";
return "vendor";
}
},
},
},
},
});常见优化项:CDN 外置大依赖(build.rollupOptions.external + 手动 <script> 引入)、图片压缩、产物 gzip(Nginx 层即可开启)。使用 npx vite build --report(或 rollup-plugin-visualizer)分析产物组成,定位体积大头后再对症处理。
Vite 重新定义了"构建工具"的体验基准:开发时把工作交给浏览器,构建时把优化交给 Rollup。它是原生 ESM 时代的前端基建方向。