Skip to content
性能优化

性能优化

本章涵盖 Vite 项目的性能优化策略:开发体验优化和生产构建优化。


开发性能

依赖预构建优化

确保 Vite 预构建了所有需要预构建的依赖:

export default defineConfig({
  optimizeDeps: {
    // 添加动态引入的依赖
    include: [
      'lodash-es',
      'dayjs',
      'echarts',             // 大型库
      'some-deep-import/deep/module',
    ],
    // 排除已经预构建好的或纯 ESM 的库
    exclude: [
      'your-pure-esm-lib',
    ],
  },
})

开发服务器启动时间很大程度上取决于预构建速度。include 列表中的包越多,首次启动越慢,但运行时请求更少。

预热(Warmup)

Vite 5.3+ 支持启动时预热:

export default defineConfig({
  server: {
    warmup: {
      clientFiles: [
        './src/App.vue',
        './src/views/Home.vue',
        './src/views/Dashboard.vue',
      ],
    },
  },
})

预热让频繁访问的大文件在服务器启动时就编译好,而不是等到浏览器首次请求时才编译。

性能提示:预热 3-5 个最常访问的入口文件即可。不要预热所有文件——反而会拖慢启动速度。

排除大文件监听

export default defineConfig({
  server: {
    watch: {
      ignored: [
        '**/node_modules/**',
        '**/dist/**',
        '**/.git/**',
        '**/coverage/**',
      ],
    },
  },
})

HMR 性能诊断

// vite.config.js 中启用 HMR 日志
export default defineConfig({
  server: {
    hmr: {
      // 打印 HMR 更新详情
      // 开发时在控制台看到每个模块的更新耗时
    },
  },
})

// 也可通过插件诊断
import inspect from 'vite-plugin-inspect'

export default defineConfig({
  plugins: [inspect()],  // 访问 localhost:5173/__inspect
})

构建性能

选择合适的压缩器

export default defineConfig(({ mode }) => ({
  build: {
    // 默认 esbuild:速度快,体积合理
    minify: 'esbuild',

    // 生产极致体积优化用 terser
    // minify: 'terser',
    // terserOptions: {
    //   compress: {
    //     drop_console: true,      // 移除 console
    //     drop_debugger: true,     // 移除 debugger
    //     pure_funcs: ['console.log'],  // 移除特定函数调用
    //   },
    // },
  },
}))

CSS 压缩

export default defineConfig({
  build: {
    cssMinify: 'lightningcss',    // 比 esbuild 更快,压缩率更好
    // cssMinify: 'esbuild',       // 默认,也很快
  },
})

安装:npm i -D lightningcss

代码分割策略

export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          // 分包:React/Vue 相关单独打包
          'react-vendor': ['react', 'react-dom'],
          'ui-vendor': ['antd'],
          'utils-vendor': ['lodash', 'dayjs', 'axios'],
        },
      },
    },
  },
})

分包原则

策略 说明 何时使用
按框架 React/Vue 单独 chunk 框架变更频率低,可利用浏览器缓存
按库体积 大库单独 chunk 超过 50KB 的库单独打包
按页面 页面级 lazy import SPA 路由懒加载
按频率 稳定库 vs 频繁变更的库 稳定库长期缓存

性能提示:不要过度拆分!HTTP/1.1 限制同域名约 6 个并发连接。总 chunk 数建议控制在 20-30 个以内。HTTP/2 无此限制,但每个 chunk 仍有下载开销。


产物体积优化

分析构建产物

npm i -D rollup-plugin-visualizer
import { visualizer } from 'rollup-plugin-visualizer'

export default defineConfig({
  plugins: [
    visualizer({
      open: true,
      gzipSize: true,
      brotliSize: true,
      filename: 'dist/stats.html',
    }),
  ],
})

Tree Shaking 前提条件

Tree Shaking 依赖 ES Module 的静态结构。确保:

  1. 使用 ESM 导入:import { foo } from 'pkg'
  2. 库提供 "sideEffects": false 在 package.json 中
  3. 避免副作用导入:不用 import 'pkg/global.css' 式的裸导入(必要的全局样式除外)
// package.json
{
  "sideEffects": [
    "*.css",
    "*.scss"
  ]
}

按需导入大型库

// ❌ 全部导入(体积大)
import _ from 'lodash'
_.debounce(fn, 300)

// ✅ 按需导入
import debounce from 'lodash/debounce'
debounce(fn, 300)

// ✅ 或直接使用 lodash-es(天然 Tree Shakable)
import { debounce } from 'lodash-es'
// ❌ Moment.js(不可 Tree Shaking,体积大)
import moment from 'moment'

// ✅ dayjs / date-fns(天然轻量 + Tree Shaking)
import dayjs from 'dayjs'
import { format } from 'date-fns'

减少 Polyfill 体积

export default defineConfig({
  build: {
    target: 'es2020',    // 现代浏览器,减少 transpile 体积
    // target: 'es2015',  // 如需兼容老旧浏览器
  },
})

target: 'modules'(默认)要求浏览器支持原生 ESM(Chrome 87+, Firefox 78+),此设置下几乎不需要额外 Polyfill。

图片优化

npm i -D vite-plugin-imagemin
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({
  plugins: [
    viteImagemin({
      gifsicle: { optimizationLevel: 3 },
      mozjpeg: { quality: 80 },
      pngquant: { quality: [0.7, 0.8] },
      svgo: { plugins: [{ removeViewBox: false }] },
    }),
  ],
})

加载性能

资源预加载 / 预连接

// vite.config.js
export default defineConfig({
  build: {
    modulePreload: {
      polyfill: true,       // 为不支持 modulepreload 的浏览器注入 polyfill
      resolveDependencies: (url, deps, context) => deps,
    },
  },
})

在 HTML 中手动添加:

<!-- 预连接到关键来源 -->
<link rel="preconnect" href="https://api.example.com" />
<link rel="dns-prefetch" href="https://cdn.example.com" />

<!-- 预加载关键资源 -->
<link rel="modulepreload" href="/assets/vendor.hash.js" />

CSS 加载优化

// 关键 CSS 内联
// 对于首屏渲染必需的 CSS,可以通过插件内联到 HTML 中
npm i -D vite-plugin-critical

开启 gzip / brotli

npm i -D vite-plugin-compression
import compression from 'vite-plugin-compression'

export default defineConfig({
  plugins: [
    compression({
      algorithm: 'brotliCompress',  // 比 gzip 小 20% 左右
      ext: '.br',
      threshold: 10240,             // 大于 10KB 才压缩
    }),
    compression({
      algorithm: 'gzip',
      ext: '.gz',
    }),
  ],
})

💡 最佳实践:Vite 构建时不压缩,而是在部署环节由 Nginx / CDN 自动压缩。前提是你的 Nginx/CDN 配置了 gzip/brotli。否则用 vite-plugin-compression 提前生成压缩文件。


打包体积检查清单

检查项 操作
是否未使用按需导入 检查导入语句,用 import { specific } from 'pkg' 替代 import *
是否有未使用的依赖 运行 npx depcheck 或使用 knip
Moment.js 替换为 dayjs 或 date-fns
Lodash 全量导入 改为 lodash-es + Tree Shaking 或 lodash/functionName
大图标库全量导入 使用按需导入 @ant-design/icons/es
CSS-in-JS 运行时体积 考虑零运行时方案(Tailwind / CSS Modules)
target 过低导致过多 polyfill 指定合适的 build.target
重复依赖(不同版本) 运行 npx npm-dedupe
Source Map 开启在生产 确保 build.sourcemap: false(或 'hidden'

开发体验优化

快速重启

# 强制重新进行依赖预构建
vite --force

# 清除缓存后启动
rm -rf node_modules/.vite && vite

减少插件负担

开发时仅加载必要的插件:

export default defineConfig(({ command }) => ({
  plugins: [
    // 核心插件始终加载
    react(),
    // 仅在构建时加载的插件
    ...(command === 'build' ? [visualizer(), compression()] : []),
  ],
}))

浏览器性能

Vite 开发服务器使用 304 协商缓存。如果发现开发时浏览器卡顿,可以打开 DevTools 的 “Disable cache” 确认是否是缓存问题。

性能提示:大型项目(500+ 模块)的开发启动依然很快(< 2s 冷启动)。如果变慢,检查 optimizeDeps.include 是否配置合理,以及是否有大量不必要监听的 node_modules 目录。