构建优化
构建优化是Vue.js应用性能优化的重要环节。通过优化构建配置,可以显著减少应用的最终体积,提高加载速度。本章将介绍Vite构建优化的多种策略和最佳实践。
13.35.1 Vite构建配置优化
基础配置优化
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
// 优化构建配置
build: {
// 产物目录
outDir: 'dist',
// 静态资源目录
assetsDir: 'assets',
// 产物文件名哈希
assetsDir: 'assets/[ext]',
// 入口文件名
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html')
}
},
// 最小化混淆
minify: 'terser',
// 生成sourcemap
sourcemap: process.env.NODE_ENV === 'development',
// 拆分CSS
cssCodeSplit: true,
// 预加载策略
preload: {
include: {
type: 'script'
}
},
// 模块预加载
modulePreload: {
include: {
type: 'script'
}
}
},
// 服务器配置
server: {
port: 3000,
open: true
},
// 解析配置
resolve: {
// 别名配置
alias: {
'@': resolve(__dirname, 'src')
},
// 扩展配置
extensions: ['.vue', '.js', '.ts', '.jsx', '.tsx']
}
})高级构建配置
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { visualizer } from 'rollup-plugin-visualizer'
import { resolve } from 'path'
export default defineConfig({
plugins: [
vue(),
// 构建分析插件
visualizer({
open: true,
gzipSize: true,
brotliSize: true
})
],
build: {
// 产物文件名格式
rollupOptions: {
output: {
// 静态资源文件名格式
assetFileNames: 'assets/[name]-[hash][extname]',
// 入口文件名格式
entryFileNames: 'assets/[name]-[hash].js',
// 代码拆分
manualChunks: {
// 将vue相关依赖打包成一个chunk
vue: ['vue', 'vue-router', 'pinia'],
// 将UI组件库打包成一个chunk
ui: ['element-plus'],
// 将工具库打包成一个chunk
utils: ['axios', '@vueuse/core']
}
}
},
// 产物压缩配置
terserOptions: {
compress: {
// 移除console
drop_console: true,
// 移除debugger
drop_debugger: true,
// 移除无用代码
dead_code: true
},
// 混淆配置
mangle: {
// 保留类名
keep_classnames: true,
// 保留函数名
keep_fnames: false
}
}
}
})13.35.2 依赖优化与分析
依赖分析工具
rollup-plugin-visualizer
npm install rollup-plugin-visualizer --save-dev// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
visualizer({
open: true,
gzipSize: true,
brotliSize: true
})
]
})vite-bundle-analyzer
npm install vite-bundle-analyzer --save-dev// vite.config.js
import { defineConfig } from 'vite'
import { createHtmlPlugin } from 'vite-plugin-html'
export default defineConfig({
plugins: [
createHtmlPlugin({
minify: true
})
]
})依赖优化策略
移除无用依赖:
# 检查未使用的依赖 npm install -g depcheck depcheck使用更小的替代库:
- lodash → lodash-es 或 lodash/core
- moment → dayjs 或 date-fns
- axios → ky 或 fetch API
按需导入:
// 完整导入 import _ from 'lodash' // 按需导入 import { debounce } from 'lodash-es'依赖预构建:
Vite会自动预构建依赖,将CommonJS模块转换为ESM模块,提高加载速度。
构建报告生成
# 生成构建报告
npm run build -- --report// package.json
{
"scripts": {
"build": "vite build",
"build:report": "vite build --report"
}
}13.35.3 压缩与CDN配置
资源压缩
Gzip压缩
// vite.config.js
import { defineConfig } from 'vite'
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({
// 压缩算法
algorithm: 'gzip',
// 压缩阈值
threshold: 10240,
// 压缩后的文件扩展名
ext: '.gz',
// 是否删除原文件
deleteOriginFile: false
})
]
})Brotli压缩
// vite.config.js
import { defineConfig } from 'vite'
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
plugins: [
viteCompression({
algorithm: 'brotliCompress',
threshold: 10240,
ext: '.br',
deleteOriginFile: false
})
]
})CDN配置
使用外部CDN
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
external: ['vue', 'vue-router', 'pinia'],
output: {
globals: {
vue: 'Vue',
'vue-router': 'VueRouter',
pinia: 'Pinia'
}
}
}
}
})<!-- index.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue.js应用</title>
<!-- 引入CDN资源 -->
<script src="https://unpkg.com/vue@3.3.4/dist/vue.global.js"></script>
<script src="https://unpkg.com/vue-router@4.2.4/dist/vue-router.global.js"></script>
<script src="https://unpkg.com/pinia@2.1.6/dist/pinia.global.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>使用 vite-plugin-cdn-import
npm install vite-plugin-cdn-import --save-dev// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import cdn from 'vite-plugin-cdn-import'
export default defineConfig({
plugins: [
vue(),
cdn({
modules: [
{
name: 'vue',
var: 'Vue',
path: 'https://unpkg.com/vue@3.3.4/dist/vue.global.js'
},
{
name: 'vue-router',
var: 'VueRouter',
path: 'https://unpkg.com/vue-router@4.2.4/dist/vue-router.global.js'
},
{
name: 'pinia',
var: 'Pinia',
path: 'https://unpkg.com/pinia@2.1.6/dist/pinia.global.js'
},
{
name: 'element-plus',
var: 'ElementPlus',
path: 'https://unpkg.com/element-plus@2.3.12/dist/index.full.js',
css: 'https://unpkg.com/element-plus@2.3.12/dist/index.css'
}
]
})
]
})13.35.4 PWA与离线能力
PWA配置
npm install vite-plugin-pwa --save-dev// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
vue(),
VitePWA({
// PWA配置
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'apple-touch-icon.png', 'masked-icon.svg'],
manifest: {
name: 'Vue.js应用',
short_name: 'Vue应用',
description: '一个基于Vue.js的PWA应用',
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png'
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable'
}
]
},
// Service Worker配置
workbox: {
// 缓存策略
runtimeCaching: [
{
urlPattern: /^https:\/\/api\.example\.com\//,
handler: 'NetworkFirst',
options: {
cacheName: 'api-cache',
expiration: {
maxEntries: 100,
maxAgeSeconds: 60 * 60 * 24 // 1天
}
}
},
{
urlPattern: /^https:\/\/assets\.example\.com\//,
handler: 'CacheFirst',
options: {
cacheName: 'assets-cache',
expiration: {
maxEntries: 1000,
maxAgeSeconds: 60 * 60 * 24 * 30 // 30天
}
}
}
]
}
})
]
})注册Service Worker
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { registerSW } from 'virtual:pwa-register'
// 注册Service Worker
const updateSW = registerSW({
onNeedRefresh() {
// 提示用户刷新
if (confirm('应用有新版本,是否刷新?')) {
updateSW()
}
},
onOfflineReady() {
// 提示用户应用已可离线使用
console.log('应用已可离线使用')
}
})
const app = createApp(App)
app.mount('#app')PWA最佳实践
图标设计:
- 提供多种尺寸的图标
- 使用SVG格式的maskable图标
- 确保图标清晰可见
缓存策略:
- 静态资源使用CacheFirst策略
- API请求使用NetworkFirst或StaleWhileRevalidate策略
- 设置合理的缓存过期时间
更新策略:
- 使用autoUpdate自动更新
- 提供手动更新选项
- 提示用户有新版本可用
离线体验:
- 提供离线页面
- 处理网络请求失败的情况
- 显示离线状态
构建优化总结
Vite配置优化:
- 合理配置构建选项
- 使用别名简化导入
- 配置代码拆分
依赖优化:
- 移除无用依赖
- 使用更小的替代库
- 按需导入
- 生成构建报告
压缩与CDN:
- 使用Gzip和Brotli压缩
- 配置CDN加速
- 使用外部CDN资源
PWA与离线能力:
- 配置PWA支持
- 注册Service Worker
- 优化离线体验
通过以上优化策略,可以显著提高Vue.js应用的构建效率和最终性能。在实际开发中,应该根据应用的具体情况选择合适的优化方案,并使用构建分析工具进行验证。