生产构建
构建命令
使用 vite build 命令进行生产构建:
# 基本构建
npm run build
# 指定模式
vite build --mode production
# 指定输出目录
vite build --outDir dist
# 生成 source map
vite build --sourcemap
# 监听文件变化(用于开发)
vite build --watch
浏览器兼容性
默认目标
Vite 默认针对 Baseline Widely Available 浏览器:
- Chrome >= 111
- Edge >= 111
- Firefox >= 114
- Safari >= 16.4
自定义目标
通过 build.target 配置指定目标浏览器:
// vite.config.js
export default defineConfig({
build: {
target: 'es2015', // 最低支持 es2015
// 其他选项: 'es2016', 'es2017', 'es2018', 'es2019', 'es2020', 'esnext'
},
})
最低浏览器支持
即使设置更低的目标,Vite 仍需要以下最低浏览器支持(原生 ESM 和 import.meta):
- Chrome >= 64
- Firefox >= 67
- Safari >= 11.1
- Edge >= 79
旧浏览器支持
使用 @vitejs/plugin-legacy 插件支持旧浏览器:
npm install -D @vitejs/plugin-legacy
// vite.config.js
import { defineConfig } from 'vite'
import legacy from '@vitejs/plugin-legacy'
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
}),
],
})
公共基础路径
配置 base
如果项目部署在嵌套路径,需要配置 base:
// vite.config.js
export default defineConfig({
base: '/my-app/', // 项目部署在 /my-app/ 路径下
})
动态基础路径
如果不知道确切的基础路径,可以使用相对路径:
export default defineConfig({
base: './', // 相对路径
})
运行时获取
使用 import.meta.env.BASE_URL 在代码中获取基础路径:
// 构建时会静态替换
const baseUrl = import.meta.env.BASE_URL // "/my-app/"
// 动态拼接 URL
const imageUrl = `${import.meta.env.BASE_URL}images/logo.png`
构建配置
输出配置
export default defineConfig({
build: {
// 输出目录(默认:dist)
outDir: 'dist',
// 静态资源目录(相对于 outDir)
assetsDir: 'assets',
// 构建前是否清空输出目录
emptyOutDir: true,
// 是否生成 source map
sourcemap: false,
// 目标浏览器版本
target: 'es2015',
// 代码压缩工具
minify: 'esbuild', // 'esbuild' | 'terser' | false
// CSS 代码分割
cssCodeSplit: true,
// 小于此值的资源内联为 base64(默认:4096 bytes)
assetsInlineLimit: 4096,
// chunk 大小警告阈值(KB)
chunkSizeWarningLimit: 500,
// 是否写入 manifest.json
manifest: false,
// 是否生成 SSR manifest
ssrManifest: false,
// 报告压缩后的大小
reportCompressedSize: true,
// 触发警告的 chunk 大小(KB)
chunkSizeWarningLimit: 500,
},
})
Rollup 选项
Vite 使用 Rolldown 进行生产构建,可以通过 build.rollupOptions 配置:
export default defineConfig({
build: {
rollupOptions: {
// 入口点(多页面应用)
input: {
main: resolve(__dirname, 'index.html'),
admin: resolve(__dirname, 'admin/index.html'),
},
// 输出配置
output: {
// 入口文件命名
entryFileNames: 'js/[name]-[hash].js',
// chunk 文件命名
chunkFileNames: 'js/[name]-[hash].js',
// 资源文件命名
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.')
const ext = info[info.length - 1]
if (/\.(png|jpe?g|gif|svg|webp|ico)$/i.test(assetInfo.name)) {
return 'img/[name]-[hash][extname]'
}
if (/\.(woff2?|eot|ttf|otf)$/i.test(assetInfo.name)) {
return 'fonts/[name]-[hash][extname]'
}
if (ext === 'css') {
return 'css/[name]-[hash][extname]'
}
return 'assets/[name]-[hash][extname]'
},
// 手动代码分割
manualChunks: {
// 将 vue 相关库打包在一起
'vue-vendor': ['vue', 'vue-router', 'pinia'],
// 将 UI 库打包在一起
'ui-vendor': ['element-plus'],
},
},
// 外部依赖(不打包进 bundle)
external: ['jquery'],
// 全局变量映射(用于 UMD/IIFE)
globals: {
jquery: '$',
},
},
},
})
代码分割
动态导入
Vite 自动处理动态导入的代码分割:
// 路由懒加载
const routes = [
{
path: '/user',
component: () => import('./views/User.vue'),
},
{
path: '/admin',
component: () => import('./views/Admin.vue'),
},
]
// 组件懒加载
const AsyncModal = defineAsyncComponent(() =>
import('./components/Modal.vue')
)
// 条件加载
if (condition) {
const module = await import('./heavy-module.js')
module.doSomething()
}
手动代码分割
通过 manualChunks 控制代码分割:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
// 将 node_modules 中的依赖单独打包
if (id.includes('node_modules')) {
// 按包名分组
const match = id.match(/node_modules\/(?:@([^/]+)\/([^/]+)|([^/]+))/)
const scope = match?.[1]
const name = match?.[2] || match?.[3]
return `vendor/${scope ? `${scope}-` : ''}${name}`
}
// 将特定目录的代码打包在一起
if (id.includes('/src/views/')) {
return 'views'
}
},
},
},
},
})
多页面应用(MPA)
Vite 支持多页面应用配置:
// vite.config.js
import { resolve } from 'path'
export default defineConfig({
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
about: resolve(__dirname, 'about/index.html'),
contact: resolve(__dirname, 'contact/index.html'),
},
},
},
})
项目结构:
project/
├── index.html # 主页面
├── about/
│ └── index.html # 关于页面
├── contact/
│ └── index.html # 联系页面
└── src/
└── ...
库模式
构建面向浏览器的库时使用库模式:
// vite.config.js
import { resolve } from 'path'
export default defineConfig({
build: {
lib: {
// 入口文件
entry: resolve(__dirname, 'lib/main.js'),
// 库的名称(用于 UMD/IIFE)
name: 'MyLib',
// 输出文件名(扩展名会自动添加)
fileName: 'my-lib',
// 输出格式
formats: ['es', 'umd'], // 默认:['es', 'umd']
},
rollupOptions: {
// 确保外部化不想打包进库的依赖
external: ['vue'],
output: {
// 为 UMD 构建提供全局变量
globals: {
vue: 'Vue',
},
},
},
},
})
库模式 package.json
{
"name": "my-lib",
"type": "module",
"files": ["dist"],
"main": "./dist/my-lib.umd.cjs",
"module": "./dist/my-lib.js",
"exports": {
".": {
"import": "./dist/my-lib.js",
"require": "./dist/my-lib.umd.cjs"
},
"./style.css": "./dist/my-lib.css"
}
}
多入口库
export default defineConfig({
build: {
lib: {
entry: {
'my-lib': resolve(__dirname, 'lib/main.js'),
'my-lib-utils': resolve(__dirname, 'lib/utils.js'),
},
name: 'MyLib',
},
},
})
构建优化
CSS 优化
export default defineConfig({
build: {
// CSS 代码分割(默认:true)
cssCodeSplit: true,
// CSS 目标浏览器(默认与 build.target 相同)
cssTarget: 'chrome61',
},
css: {
// 使用 Lightning CSS(实验性)
transformer: 'lightningcss',
lightningcss: {
targets: {
chrome: 80,
},
},
},
})
资源优化
export default defineConfig({
build: {
// 小于 4KB 的资源内联为 base64
assetsInlineLimit: 4096,
// 触发警告的 chunk 大小
chunkSizeWarningLimit: 500,
// 启用/禁用压缩大小报告
reportCompressedSize: false,
},
})
Tree Shaking
Vite 自动进行 tree shaking,但可以通过注释控制:
// 保留副作用(不 tree-shaking)
/* @__PURE__ */ console.log('side effect')
// 标记为无副作用(可以 tree-shaking)
/*#__PURE__*/
export function helper() {
return 'helper'
}
加载错误处理
Vite 在动态导入失败时会触发 vite:preloadError 事件:
window.addEventListener('vite:preloadError', (event) => {
// 新部署后,旧资源可能被删除
// 可以在这里处理,例如刷新页面
window.location.reload()
})
建议为 HTML 文件设置 Cache-Control: no-cache,确保用户获取最新的资源引用。
构建分析
使用 rollup-plugin-visualizer
npm install -D rollup-plugin-visualizer
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true, // 构建后自动打开报告
gzipSize: true,
brotliSize: true,
}),
],
})
预览构建
使用 vite preview 在本地预览生产构建:
# 构建后预览
npm run build
npm run preview
# 指定端口预览
vite preview --port 4173
# 指定主机
vite preview --host
构建性能优化
提高构建速度
export default defineConfig({
build: {
// 禁用 source map 加速构建
sourcemap: false,
// 禁用压缩大小报告
reportCompressedSize: false,
// 使用 esbuild 压缩(比 terser 快)
minify: 'esbuild',
},
})
减少构建输出
export default defineConfig({
build: {
// 提高内联限制,减少 HTTP 请求
assetsInlineLimit: 8192,
rollupOptions: {
output: {
// 控制代码分割粒度
manualChunks: (id) => {
// 将大型依赖单独打包
if (id.includes('node_modules/large-lib')) {
return 'large-lib'
}
},
},
},
},
})
小结
本章我们学习了 Vite 的生产构建:
- 构建命令:
vite build及其选项 - 浏览器兼容性:目标配置和旧浏览器支持
- 公共基础路径:
base配置和动态路径 - 构建配置:输出目录、资源处理、代码压缩
- 代码分割:动态导入和手动分割
- 多页面应用:配置多个入口点
- 库模式:构建可发布的库
- 构建优化:CSS、资源、tree shaking
- 构建分析:分析包大小和性能
掌握这些构建知识,可以帮助你优化生产环境的性能和输出质量。