Vite构建工具完全指南

Vite构建工具完全指南
寒霜Vite构建工具完全指南
Vite是下一代前端构建工具,提供了极快的开发服务器启动速度和热更新。本文将系统性地介绍Vite的配置、打包优化和自动化流程。
1. 基础配置
1.1 环境变量配置
首先创建环境变量文件:
项目根目录/
├── .env # 所有环境共享
├── .env.development # 开发环境
├── .env.production # 生产环境
└── vite.config.js
.env.development
# 开发环境配置
VITE_ENV=development
VITE_BASE_URL=http://localhost:3000
VITE_API_URL=http://dev-api.example.com
.env.production
# 生产环境配置
VITE_ENV=production
VITE_BASE_URL=https://example.com
VITE_API_URL=https://api.example.com
1.2 基础vite.config.js配置
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import chalk from 'chalk'
export default defineConfig(({ command, mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd(), '');
// 打印当前环境信息
console.log(`本次打包的环境是:${chalk.yellow(env.VITE_ENV)}`);
console.log(`本次打包使用的baseURL是:${chalk.bold.yellow(env.VITE_BASE_URL)}`);
return {
// 基础路径
base: './',
// 插件配置
plugins: [vue()],
// CSS配置
css: {
preprocessorOptions: {
less: {
// 引入全局 Less 文件
additionalData: `@import "./src/assets/css/base.less";`
},
scss: {
// 引入全局 SCSS 文件
additionalData: `@import "./src/assets/css/base.scss";`
}
}
},
// 路径别名配置
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'@components': fileURLToPath(new URL('./src/components', import.meta.url)),
'@assets': fileURLToPath(new URL('./src/assets', import.meta.url))
}
},
// 开发服务器配置
server: {
port: 3000,
host: '0.0.0.0',
open: true,
proxy: {
'/api': {
target: env.VITE_API_URL,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
// 构建配置
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: false,
minify: 'terser',
rollupOptions: {
output: {
// 自定义入口文件名
entryFileNames: `assets/[name]_${new Date().getTime()}.js`,
// 自定义块文件名
chunkFileNames: `assets/[name]-[hash]_${new Date().getTime()}.js`,
// 自定义资源文件名
assetFileNames: `assets/[name]-[hash].[ext]`
}
}
}
}
})
2. 高级配置
2.1 按需打包指定目录
在实际项目中,有时需要根据特定条件只打包部分目录。以下示例演示如何根据channelId动态打包指定目录:
项目结构:
src/
├── stores/
│ └── counter.js # 存储channelId
├── views/
│ └── detailPageInfo/
│ ├── 123/ # 渠道123的资源
│ │ ├── styleModel.js
│ │ ├── css/
│ │ └── img/
│ ├── 234/ # 渠道234的资源
│ │ └── ...
│ └── 456/ # 渠道456的资源
│ └── ...
└── main.js
vite.config.js配置:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import chalk from 'chalk'
import topLevelAwait from 'vite-plugin-top-level-await'
import { resolve } from 'path'
import fs from 'fs'
// 从counter.js中读取channelId
const getChannelId = () => {
try {
const counterContent = fs.readFileSync(
resolve(__dirname, 'src/stores/counter.js'),
'utf-8'
)
// 提取未被注释的window.channelId赋值行
const lines = counterContent.split('\n')
let channelId = null
for (const line of lines) {
// 匹配未被注释的window.channelId赋值
if (line.trim().startsWith('window.channelId =')) {
const match = line.match(/window\.channelId\s*=\s*['"]([^'"]+)['"]/)
if (match) {
channelId = match[1]
break
}
}
}
return channelId
} catch (error) {
console.error(chalk.red('读取channelId失败,使用默认值000'), error)
return '857'
}
}
const channelId = getChannelId()
console.log(chalk.green(`当前打包渠道ID: ${channelId}`))
export default defineConfig(({ mode }) => {
return {
base: './',
plugins: [
vue(),
topLevelAwait()
],
css: {
preprocessorOptions: {
less: {
additionalData: `@import "./src/assets/css/base.less";`
}
}
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
build: {
rollupOptions: {
// 排除不需要打包的文件
external: (id) => {
// 排除detailPageInfo下非当前channelId目录的文件
return id.includes('src/views/detailPageInfo/') &&
!id.includes(`src/views/detailPageInfo/${channelId}/`);
},
output: {
entryFileNames: `assets/[name].[hash].js`,
chunkFileNames: `assets/[name].[hash].js`,
assetFileNames: `assets/[name].[hash].[ext]`,
// 将指定目录下的文件打包在一起
manualChunks(id) {
// 处理当前channelId目录下的文件
if (id.includes(`src/views/detailPageInfo/${channelId}`)) {
return channelId;
}
}
}
},
sourcemap: true
},
esbuild: {
sourcemap: true,
sourcesContent: true
}
}
})
2.2 代码分割策略
build: {
rollupOptions: {
output: {
manualChunks: {
// 将node_modules中的包打包到vendor
'vendor': ['vue', 'vue-router', 'pinia'],
// 将UI库单独打包
'ui-library': ['element-plus'],
// 将工具函数单独打包
'utils': ['lodash-es', 'axios']
}
}
}
}
2.3 构建优化配置
build: {
// 代码压缩
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 删除console
drop_debugger: true // 删除debugger
}
},
// chunk大小警告阈值
chunkSizeWarningLimit: 1000,
// 启用源码映射
sourcemap: false,
rollupOptions: {
output: {
// 分包策略
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor'
}
}
}
}
}
3. 打包自动化
3.1 清除缓存命令
在package.json中添加清除命令:
{
"scripts": {
"clean": "rm -rf dist/* || rimraf dist/* || echo 'No files to clean.'"
}
}
3.2 自动压缩打包文件
安装archiver依赖:
npm install archiver --save-dev
创建zip.js文件:
// 引入所需模块
import fs from 'fs';
import archiver from 'archiver';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
// 获取当前文件的目录
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// 创建一个文件以写入压缩包内容
const output = fs.createWriteStream(`${__dirname}/dist.zip`);
// 创建archiver实例,并设置压缩格式和压缩级别
const archive = archiver('zip', {
zlib: { level: 9 } // 压缩级别:0-9,9为最高压缩级别
});
// 监听输出文件流的'close'事件
output.on('close', function() {
console.log(`打包完成,总大小:${archive.pointer()} bytes`);
console.log(`压缩包已生成:${__dirname}/dist.zip`);
});
// 监听archive的错误事件
archive.on('error', function(err) {
throw err;
});
// 监听压缩进度
archive.on('progress', function(progress) {
const percent = progress.entries.processed / progress.entries.total * 100;
console.log(`压缩进度:${percent.toFixed(2)}%`);
});
// 管道输出文件流到archive对象
archive.pipe(output);
// 指定需要压缩的目录
archive.directory('dist/', false);
// 完成文件添加并结束输出流
archive.finalize();
在package.json中添加压缩命令:
{
"scripts": {
"zip": "node zip.js"
}
}
3.3 组合命令
将清除、打包、压缩组合成一个命令:
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:dev": "npm run clean && vite build --mode development && npm run zip",
"build:prod": "npm run clean && vite build --mode production && npm run zip"
}
}
4. 常用插件配置
4.1 自动导入插件
npm install -D unplugin-auto-import unplugin-vue-components
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
export default defineConfig({
plugins: [
vue(),
// 自动导入Vue API
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: 'src/auto-imports.d.ts'
}),
// 自动导入组件
Components({
resolvers: [ElementPlusResolver()],
dts: 'src/components.d.ts'
})
]
})
4.2 SVG图标插件
npm install -D vite-plugin-svg-icons
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default defineConfig({
plugins: [
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
symbolId: 'icon-[dir]-[name]'
})
]
})
4.3 Top-level Await插件
npm install -D vite-plugin-top-level-await
import topLevelAwait from 'vite-plugin-top-level-await'
export default defineConfig({
plugins: [
topLevelAwait({
promiseExportName: '__tla',
promiseRetry: false
})
]
})
5. 性能优化
5.1 开发环境优化
server: {
host: '0.0.0.0',
port: 3000,
open: true,
// 预构建频繁使用的文件
optimizeDeps: {
include: ['vue', 'vue-router', 'axios'],
exclude: []
},
// 文件系统监听
watch: {
usePolling: false, // 启用轮询
interval: 100 // 轮询间隔
}
}
5.2 生产环境优化
build: {
// 减小打包体积
reportCompressedSize: false,
// 设置chunk大小警告限制
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
// 手动分包
manualChunks(id) {
if (id.includes('node_modules')) {
// 将大型库单独打包
if (id.includes('echarts')) {
return 'echarts'
}
if (id.includes('element-plus')) {
return 'element-plus'
}
return 'vendor'
}
}
}
},
// CSS代码分割
cssCodeSplit: true,
// 构建目标
target: 'modules'
}
5.3 CDN加速配置
build: {
rollupOptions: {
external: ['vue', 'vue-router', 'axios', 'element-plus'],
output: {
globals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
'element-plus': 'ElementPlus'
}
}
}
}
在HTML中引入CDN:
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-router@4/dist/vue-router.global.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
6. 环境管理最佳实践
6.1 环境变量类型定义
创建src/env.d.ts文件:
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_ENV: string
readonly VITE_BASE_URL: string
readonly VITE_API_URL: string
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
6.2 在代码中使用环境变量
// 获取环境变量
const env = import.meta.env.VITE_ENV
const apiUrl = import.meta.env.VITE_API_URL
// 根据环境执行不同逻辑
if (import.meta.env.PROD) {
console.log('生产环境')
} else {
console.log('开发环境')
}
7. 总结
Vite的强大之处在于:
- ✅ 快速的冷启动
- ✅ 即时的热模块更新
- ✅ 丰富的插件生态
- ✅ 灵活的配置选项
- ✅ 优秀的构建性能
掌握这些配置技巧,可以让你的项目构建更加高效和灵活。