vite+vue3+ts前端搭建与配置(4) - 打包优化指南
打包优化指南
本文提供一套完整的 Vite 构建优化实践方案,涵盖:
- 构建体积分析
- 图像资源压缩
- 静态资源 Gzip/Brotli 压缩
- 第三方依赖分包策略
- 实际部署注意事项
适用于中大型 Vue/React 项目,帮助开发者显著减少首屏加载时间,提升 Lighthouse 分数。
1. 打包分析
安装:npm i rollup-plugin-visualizer -D
配置到plugins中:
import { visualizer } from 'rollup-plugin-visualizer';
export const setupVitePlugins = (): PluginOption[] => {
const isProd = process.env.NODE_ENV === "production";
const plugins:PluginOption[] = [ ]
// 打包分析(生产环境可关闭)
if (isProd) {
plugins.push(
// 生成分析报告
visualizer({
open: false, // 构建完成后自动打开报告页面
filename: "stats.html", // 报告文件路径
gzipSize: true, // 显示 gzip 压缩后的体积
brotliSize: true, // 显示 brotli 压缩后的体积
}),
);
}
return plugins
}
构建完成后执行:npx serve -s dist,
然后访问本地服务并手动打开 dist/stats.html,或设置 open: true 自动弹出浏览器窗口。
2. 图像优化
详情见vite-plugin-image-optimizer
根据项目需求选择安装以下工具:
# 支持 PNG/JPG/WebP 等栅格图像压缩
npm i -D vite-plugin-image-optimizer sharp
# 支持 SVG 优化(可选)
npm i -D svgo
说明:
- 使用
SVGO优化SVG资源并传递自定义配置 - 使用
Sharp.js优化栅格资源(png、jpeg、gif、tiff、webp、avif),并可选择为每种扩展类型传递自定义配置。默认无损压缩(如PNG/JPEG质量设为100)
配置:
import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
export const setupVitePlugins = (): PluginOption[] => {
const plugins:PluginOption[] = [
// 图片优化
ViteImageOptimizer({
// 针对不同格式的压缩参数
png: { quality: 80 },
jpeg: { quality: 80 },
jpg: { quality: 80 },
webp: { quality: 80, lossless: false }, // 转换WebP,非无损模式
// 可选:排除node_modules或指定小图
exclude: ['node_modules'], // 避免误处理第三方库中的图片
// // 可选:仅处理特定路径
// include: ['src/assets/**/*.{jpg,jpeg,png,svg,webp}'],
}),
]
return plugins
}
3. 资源压缩
安装vite-plugin-compression2:npm i -D vite-plugin-compression2
配置:
import { compression, defineAlgorithm } from "vite-plugin-compression2";
export const setupVitePlugins = (): PluginOption[] => {
const plugins:PluginOption[] = [
compression({
// 同时生成 gzip 和 brotli 文件
algorithms: [
'gzip',
'brotliCompress'
// defineAlgorithm('gzip', { level: 9 }), // 自定义算法与压缩级别
],
// 只压缩大于 1KB 的文件
threshold: 1024,
// 若压缩后更大则跳过
skipIfLargerOrEqual: true,
// 是否原始文件( 设为true时,要求服务端支持)
deleteOriginalAssets: false,
}),
]
return plugins
}
选项
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
include |
string | RegExp | Array<string | RegExp> |
/\.(html|xml|css|json|js|mjs|svg|yaml|yml|toml)$/ |
包含符合任意这些条件的资源文件 |
exclude |
string | RegExp | Array<string | RegExp> |
- |
排除符合任意这些条件的资源文件 conditions. |
threshold |
number |
0 |
仅处理大于此尺寸的资源(单位:字节) |
algorithms |
Algorithms |
['gzip', 'brotliCompress'] |
使用的压缩算法数组或预定义算法结果 |
filename |
string | function |
[path][base].gz or [path][base]. br (若算法为zstandard则生成[path][base].zst) |
生成的目标资源文件名规则 |
deleteOriginalAssets |
boolean |
false |
是否删除原始资源文件 |
skipIfLargerOrEqual |
boolean |
true |
若压缩结果大于或等于原文件时是否跳过压缩 |
logLevel |
string |
info |
控制标准输出的信息级别 |
artifacts |
function |
undefined |
有时需要将某些内容复制到最终输出,此选项可提供帮助 |
**API: defineAlgorithm(algorithm, options?)**定义一种带有选项的压缩算法
参数:
algorithm算法名称('gzip' | 'brotliCompress' | 'deflate' | 'deflateRaw' | 'zstandard' | 'gz' | 'br' | 'brotli' | 'zstd')或自定义函数options算法的压缩选项
支持的算法:
| 算法 | 文件后缀 | 描述 | 备注 |
|---|---|---|---|
gzip |
.gz |
标准 gzip 压缩,速度和压缩比平衡良好 |
支持Node所有版本 |
brotliCompress |
.br |
Brotli 压缩比比 gzip 更好。 |
支持Node所有版本 |
deflate |
.gz |
Deflate压缩算法 |
支持Node所有版本 |
deflateRaw |
.gz |
原始的无标头压缩 | 支持Node所有版本 |
zstandard |
.zst |
Z标准压缩比,具有出色的速度/传动比平衡性 | 版本 >= 22.15.0 或 >= 23.8.0 |
| 自定义功能 | - | 自己实现的压缩算法 | 支持Node所有版本 |
启用 deleteOriginalAssets 选项删除原始资源文件后,部署时需要确保服务器正确配置以支持压缩文件的访问:
配置服务器识别压缩文件: 服务器需根据客户端请求的 Accept-Encoding 头返回对应的压缩文件(如 .gz 或 .br)。
nginx 配置示例:(关键)
server {
listen 80;
root /usr/share/nginx/html;
location / {
# 开启静态压缩文件支持
gzip_static on; # 自动查找 .gz 文件
brotli_static on; # 自动查找 .br 文件(需安装 ngx_brotli 模块)
# 回退机制:若压缩文件不存在则返回原始文件
try_files $uri $uri/ @fallback;
# 缓存策略
add_header Cache-Control "public, max-age=31536000" always;
add_header Vary Accept-Encoding; # 根据 Accept-Encoding 返回对应版本
}
# fallback 用于 SPA 路由
location @fallback {
rewrite ^.*$ /index.html break;
}
}
✅ 必须确保:
插件生成的 .gz 和 .br 文件与原文件同目录
Nginx 已编译或加载 ngx_brotli 模块(GitHub: google/ngx_brotli)
MIME 类型正确映射(JS/CSS/SVG 等均可被压缩)
4. 第三方依赖分包策略
配置位置
在 vite.config.ts 的 build.rollupOptions.output.manualChunks 中进行拆包。
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
return {
build: {
// 打包前清空 dist 目录
emptyOutDir: true,
// 启用CSS代码分割
cssCodeSplit: true,
// 生成sourcemap(生产环境建议设为false)
sourcemap: false,
// 资源内联阈值(默认4096,可适当调高)
assetsInlineLimit: 8192,
// 指定静态资源目录
assetsDir: "static",
// 启用minify(默认esbuild,可改为terser获得更好压缩率)
minify: "terser",
// 代码压缩配置
terserOptions: {
// 生产环境移除console
compress: {
drop_console: true, // 移除 console
drop_debugger: true, // 移除 debugger
},
format: {
comments: false, // 删除注释
},
},
chunkSizeWarningLimit: 2000, // chunk大小警告限制
rollupOptions: {
onwarn(warning) {
// 忽略某些非致命警告(如 eval 使用)
if (warning.code === 'EVAL') return;
console.warn(`Rollup warning: ${warning.message}`);
},
output: {
// 静态资源命名规范
assetFileNames: "assets/[ext]/[name]-[hash].[ext]",
chunkFileNames: "js/[name]-[hash].js",
entryFileNames: "js/[name]-[hash].js",
// 动态分析自动分包
manualChunks(id) {
if (id.includes("node_modules")) {
const match = /[\\/]node_modules[\\/](@?[^\\/]+(?:[\\/][^\\/]+)?)/.exec(id);
const packageName = match ? match[1] : null;
// 将较大的库单独打包
const largeLibs = ['element-plus', 'echarts', 'lodash', 'moment']
if (packageName && largeLibs.includes(packageName)) {
return packageName
}
// 其他依赖分组打包
return `vendor-${packageName}`;
}
},
},
},
},
}
})
当启用 assetFileNames: "assets/[ext]/[name]-[hash].[ext]" 时,哈希变化会触发缓存更新。
静态资源命名带
[hash]可实现长期缓存(max-age=31536000)💡
manualChunks与dynamic import()(如import('./module'))协同工作,Rollup会优先将异步模块单独打包成chunk,再通过manualChunks对同步依赖进一步拆分。
5. 综合配置与问题分析
集成模板
// vite.config.ts
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
return {
plugins: setupVitePlugins(),
build: {
// 见上文完整 build 配置
}
}
})
/* ------------------- 分割线 -------------------- */
// config/plugins/index.ts
import type { PluginOption } from "vite";
import { visualizer } from "rollup-plugin-visualizer";
import { compression, defineAlgorithm } from "vite-plugin-compression2";
import { ViteImageOptimizer } from "vite-plugin-image-optimizer";
/**
* vite插件
* @returns PluginOption[]
*/
export const setupVitePlugins = (): PluginOption[] => {
const isProd = process.env.NODE_ENV === "production";
const plugins = [
// ...其它插件配置省略
// 文件压缩 https://github.com/nonzzz/vite-plugin-compression
compression({
algorithms: [
'gzip',
defineAlgorithm('brotliCompress')
],
}),
// 图片优化
ViteImageOptimizer({
// 针对不同格式的压缩参数
png: { quality: 80 },
jpeg: { quality: 80 },
jpg: { quality: 80 },
webp: { quality: 80, lossless: false }, // 转换WebP,非无损模式
// 可选:排除node_modules或指定小图
exclude: /node_modules/,
// 可选:仅处理特定路径
// include: /public\/images/,
}),
];
// 打包分析(生产环境可关闭)
if (isProd) {
plugins.push(
// 生成分析报告
visualizer({
open: false, // 构建完成后自动打开报告页面
filename: "stats.html", // 报告文件路径
gzipSize: true, // 显示 gzip 压缩后的体积
brotliSize: true, // 显示 brotli 压缩后的体积
}),
);
}
return plugins;
};
性能收益预估
| 优化项 | 平均体积下降 | 加载时间改善 | 备注 |
|---|---|---|---|
| 打包分析 + 移除无用依赖 | ~10%-20% | ⬆️ 10% | 可视化辅助决策 |
图像压缩(WebP + 质量80) |
~30%-60% | ⬆️ 显著 尤其适合含图站群 | |
Gzip/Brotli 压缩 |
~60%-70% | ⬆️ 显著 | 需服务端支持 |
依赖分包(vendor 拆分) |
~首包减半 | ⬆️ 首次加载更快,利于缓存 |
💡 注:实际效果因项目而异,请结合
visualizer报告持续迭代。
常见陷阱与规避方法
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 页面白屏 / JS 加载失败 | 启用了 deleteOriginalAssets: true 但 Nginx 未开启 gzip_static |
确保服务器配置支持 .gz/.br 文件解析 |
SVG 图标变形或丢失 |
svgo 默认配置过于激进 |
自定义 svgo 配置保留 fill、stroke 属性 |
WebP 不兼容旧浏览器 |
缺少降级机制 | 使用 <picture> 标签提供 JPEG/PNG 回退 |
| 分包过多导致 HTTP 请求增多 | manualChunks 拆得太细 |
控制 vendor 包数量,合并小型库 |
图片优化插件报错(sharp 安装失败) |
Node ABI 不匹配或平台不兼容 | 使用 cross-env SHARP_IGNORE_GLOBAL_LIBVIPS=true npm install sharp 或切换镜像源 |
✅ 总结
- 先分析,再优化:每次上线前运行
visualizer查看bundle构成。 - 渐进式压缩:先启用
Gzip,再逐步加入Brotli和WebP。 - 服务端协同:前端压缩
≠自动生效,必须配置Nginx/Apache/Caddy支持.gz/.br。 - 缓存策略匹配:静态资源加 [hash],设置
Cache-Control: max-age=31536000。 - 监控真实用户体验:使用
Lighthouse、CrUX数据跟踪FCP、LCP指标变化。
更多推荐



所有评论(0)