生产构建
执行构建
bash
## 构建
pnpm build
## 不使用缓存构建
pnpm build:no-cache构建成功后终端输出类似:
bash
Building [████████████████████████████████████████] 100% | Time: 24.3s
Build successful. Please see dist directory构建产物
静态文件输出目录:
bash
dist/
├── favicon.ico # 站点图标
├── index.html # 入口 HTML(含 .br/.gz 预压缩副本)
├── logo.png # Logo 图片
├── stats.html # 打包体积分析报表
├── assets/js/ # JS 资源(业务 chunk + 第三方依赖 + i18n,含 .br/.gz 压缩副本)
├── css/ # 样式资源(入口、组件库、页面级样式)
├── png/ # PNG 图片(404、大图等)
├── jpg/ # JPG 背景图
├── gif/ # GIF 动图(401 页)
├── woff/ / woff2/ / ttf/ # iconfont 字体文件
└── ...WARNING
dist/ 目录为构建生成物,不要手动编辑;应修改源文件后重新 build。
本地预览
bash
pnpm preview默认访问:
bash
http://localhost:4000/用于在部署前验证样式、路由与组件示例是否正常。
流程说明
项目基于 Vite 6 + Rollup 的标准 SPA 构建流程,产出静态资源:
- 依赖预构建(optimizeDeps):Vite 将 vue/vue-router/element-plus 等 include 列表里的依赖用 esbuild 预打成 ESM,加速后续构建。
- 编译转换:@vitejs/plugin-vue(SFC)+ @vitejs/plugin-vue-jsx(TSX)+ unocss + vue-i18n 等插件链式处理源码。
- 打包分块(Rollup):按 manualChunks 策略将业务代码与第三方依赖拆分为独立 chunk,业务按路由懒加载自动分块。
- 资源处理:CSS 按页面拆分、SCSS 变量全局注入、小体积资源(<5KB)内联为 base64。
- 压缩输出:esbuild 压缩 JS,可选 terser 二次压缩;同时对 >10KB 的文件预生成 .gz 和 .br 压缩副本。
- 产物生成:输出到 dist/,含 index.html、hash 命名的 JS/CSS、图片字体、stats.html 体积分析报表。
优化配置
1. JS 分包策略
按依赖类型分层拆 chunk,避免单文件过大、提升缓存命中率:
| chunk 名 | 包含 |
|---|---|
vue | vue / @vue / vue-router / pinia / vue-i18n / vue-types / @vueuse |
elementPlus | element-plus / @element-plus |
echarts | echarts / echarts-wordcloud / zrender |
guavaUI | guava-ui |
独立分包 | axios / crypto-js / cropperjs / pinyin-pro / qrcode / @cropper/* |
vendor | 其他未命中、体积 <80KB 的第三方包 |
自动分包 | node_modules 中 ≥80KB 且不在上述规则的包,按包名单独成 chunk |
实际产物体积:
| chunk | 大小 |
|---|---|
| elementPlus-*.js | 936KB |
| echarts-*.js | 800KB |
| guavaUI-*.js | 268KB |
| pinyin-pro-*.js | 296KB |
| vue-*.js | 196KB |
| vendor-*.js | 96KB |
2. Element Plus 按需样式
通过 vite-plugin-style-import + 自定义 resolveElementPlusStyle,仅在用到组件时加载对应 CSS。同时 src/styles/element-plus-preload.ts 显式补充 guava-ui 内部使用但按需插件无法注入的 ~50 个组件样式。
对比全量引入 element-plus/dist/index.css(约350KB),实际产物:
| 文件 | 大小 |
|---|---|
| elementPlus-*.css | 272KB |
| guavaUI-*.css | 96KB |
| index-*.css | 64KB |
| 各页面 CSS | 4–8KB |
3. 静态资源压缩(gzip + brotli)
ts
compression({ algorithm: 'gzip', threshold: 10240 }); // >10KB 生成 .gz
compression({ algorithm: 'brotliCompress', threshold: 10240 }); // >10KB 生成 .br产物中每个 JS/CSS/HTML 均附带 .gz 与 .br 副本,Nginx 可直接使用 gzip_static / brotli_static 实时返回,无需服务端即时压缩。
4. 环境变量驱动构建行为
| 变量 | 作用 |
|---|---|
VITE_DROP_CONSOLE | true 时移除 console.log |
VITE_DROP_DEBUGGER | true 时移除 debugger |
VITE_USE_ALL_ELEMENT_PLUS_STYLE | false 启用 EP 按需样式,true 引入全量 CSS |
VITE_SOURCEMAP | true 输出 sourcemap |
VITE_BUNDLE_ANALYZER | true 输出 stats.html 体积分析 |
VITE_OUT_DIR | 自定义输出目录,默认 dist |
5. 其他优化
- SCSS 全局变量自动注入:
additionalData: @use "@/styles/styles.variables.scss",所有 SFC 无需手动 import。 - 小资源内联:
assetsInlineLimit: 5120,<5KB 资源转 base64 减少请求。 - 构建目标:
target: 'es2015'+cssTarget: ['chrome31'],兼容老浏览器(@vitejs/plugin-legacy已注释,可按需开启)。 - 告警阈值:
chunkSizeWarningLimit: 2048(2MB),避免无意义的大包警告刷屏。 - 最小 chunk:
experimentalMinChunkSize: 20 * 1024,过小的模块合并以减少碎片请求。 - 可视化分析:
rollup-plugin-visualizer生成dist/stats.html,展示 gzip/brotli 体积。 - SVG 图标:
vite-plugin-svg-icons-ng将src/assets/svgs下的 SVG 注册为 symbol sprite,class 规则gv-icon-[dir]-[name]。 - ESLint 不阻断构建:
failOnError: false,开发期提示但不阻塞产出。 - UnoCSS 扫描组件库:
content.filesystem包含node_modules/guava-ui/**,组件库使用的原子类也能被正确生成。
体积参考
| 资源 | 大小 |
|---|---|
| dist 总计 | 8.3 MB |
| assets/js | 5.5 MB |
| css | 660 KB |
| 业务页面 JS(60+ 个 chunk) | 合计 ~1.2 MB |
| 入口 index.js | ~500KB(路由/布局/首屏) |
失败排查
| 错误 | 可能原因 | 处理 |
|---|---|---|
模块无法解析 @/ 别名 | alias 未生效 / 文件缺失 | 检查 vite.config.ts resolve.alias 与目标文件 |
element-plus 样式丢失 | VITE_USE_ALL_ELEMENT_PLUS_STYLE 与按需引入混用 | 按需模式下检查 element-plus-preload.ts 是否补全 |
| brotli/gzip 未生成 | 文件 <10KB 不压缩属正常 | 调整 threshold 或忽略 |
| UnoCSS 类未生效 | safelist 或扫描路径缺失 | 检查 uno.config.ts content.filesystem 与 safelist |
| hash 频繁全量变更 | 公共 chunk 内容随业务改动 | 确保 vue/guavaUI 等框架 chunk 不被业务代码污染 |
下一步
构建通过后,参见 部署上线 发布到服务器。