跳到主要内容

生产构建

构建命令

使用 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 的生产构建:

  1. 构建命令vite build 及其选项
  2. 浏览器兼容性:目标配置和旧浏览器支持
  3. 公共基础路径base 配置和动态路径
  4. 构建配置:输出目录、资源处理、代码压缩
  5. 代码分割:动态导入和手动分割
  6. 多页面应用:配置多个入口点
  7. 库模式:构建可发布的库
  8. 构建优化:CSS、资源、tree shaking
  9. 构建分析:分析包大小和性能

掌握这些构建知识,可以帮助你优化生产环境的性能和输出质量。