掘金文章归档 · 第 18 篇 Vue3 / Vite 系列 1/4 性能优化

Vite 项目性能优化实践:从打包体积到首屏加载

路由懒加载 → manualChunks 分包 → 图片压缩,真实工程里的三件套

原文作者:随意_(掘金) | juejin.cn/post/7616548643940696115 | 发布于 2026-03-13 | 阅读 390 · 约 4 分钟

0默认情况下 Vite 的打包会发生什么

以下内容仅供参考酌情使用。说起 Vite 和性能优化,网上大多都是讲概念(什么是分包、什么是懒加载、什么是 Tree Shaking),但很多文章只讲理论,不讲工程实践

很多人误以为 Vite 会把所有代码打成一个 JS。其实 Vite 的生产构建基于 Rollup,默认会做基础的 chunk splitting(代码拆分),例如 main.js / vendor.js。但默认拆分不会按照业务语义优化,可能出现:

首页代码 + lodash
报表代码 + lodash
编辑器代码 + lodash
⚠️ 同一个依赖可能会被多个 chunk 引用,或者混入业务代码,导致三个问题:① 首屏加载体积过大;② 浏览器缓存利用率低;③ 更新业务代码时 vendor 也失效。所以我们需要做更精细的分包控制。

1第一层优化:路由懒加载(Code Splitting)

最基础也是最重要的一步:按页面加载代码。如果不做懒加载,用户打开首页要下载整个项目所有页面代码;做了懒加载,打开首页只加载首页代码,进入报表页再加载报表代码——首屏体积显著下降。

// React 示例
import { lazy, Suspense } from 'react'

const Home = lazy(() => import('./pages/Home'))
const Report = lazy(() => import('./pages/Report'))
const Editor = lazy(() => import('./pages/Editor'))

function App() {
  return (
    <Suspense fallback={<div>加载中...</div>}>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/report" element={<Report />} />
        <Route path="/editor" element={<Editor />} />
      </Routes>
    </Suspense>
  )
}
📌 核心思想只有一句话:用到哪个页面,再加载哪个页面的代码

2第二层优化:manualChunks 控制第三方分包

懒加载解决的是业务代码拆分,但第三方依赖仍然可能混在业务 chunk 里:

page-home.js
  └ react
  └ lodash

page-report.js
  └ echarts
  └ lodash

如果业务代码更新:page-home hash 改变 → lodash 也被重新下载 → 浏览器缓存失效。

manualChunks 可以手动控制依赖如何分包,把长期不变的依赖拆出来(react-vendor.js / utils.js / echarts.js / editor.js),业务更新时只更新业务 chunk,vendor 继续使用缓存。

对象写法

rollupOptions: {
  output: {
    manualChunks: {
      'react-vendor': [
        'react',
        'react-dom',
        'react-router-dom',
        'zustand'
      ],

      'arco-design': ['@arco-design/web-react'],

      echarts: ['@ceai-front/echarts'],

      wangeditor: [
        '@wangeditor-next/editor',
        '@wangeditor-next/editor-for-react'
      ],

      utils: [
        'lodash',
        'lodash-es',
        'dayjs',
        'axios',
        'classnames'
      ]
    }
  }
}

更稳定的写法(推荐):函数写法

manualChunks(id) {
  if (id.includes('node_modules')) {

    if (id.includes('react')) {
      return 'react-vendor'
    }

    if (id.includes('arco')) {
      return 'arco'
    }

    if (id.includes('echarts')) {
      return 'echarts'
    }
  }
}
✅ 原因是:Rollup 解析模块时使用的是文件路径(如 node_modules/react/index.js),函数写法在复杂依赖场景中更稳定。

3第三层优化:图片体积优化(vite-plugin-imagemin)

在很多项目里,图片往往才是体积最大的资源:banner.jpg 2MB、icon.png 800KB、background 3MB……一旦页面加载多张图片,性能会明显下降。

安装

pnpm add vite-plugin-imagemin -D

配置

import viteImagemin from 'vite-plugin-imagemin'

plugins: [
  viteImagemin({
    gifsicle: { optimizationLevel: 3 },
    optipng: { optimizationLevel: 7 },
    mozjpeg: { quality: 80 },
    pngquant: { quality: [0.7, 0.8] },
    svgo: {
      plugins: [{ name: 'removeViewBox' }]
    }
  })
]
格式通常可减少
PNG20% ~ 40%
JPG10% ~ 30%
SVG50%+
📌 而肉眼几乎看不出差异。

4assetsInlineLimit & 完整配置示例

一个容易忽略的小优化:

assetsInlineLimit: 4096

意思是:小于 4KB 的资源会被转换为 Base64 并直接内联到 JS 中,减少 HTTP 请求数量。但不宜设置过大,否则 JS 体积会膨胀。

完整的 Vite 优化配置示例

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import viteImagemin from 'vite-plugin-imagemin'

export default defineConfig({

  plugins: [
    react(),

    viteImagemin({
      gifsicle: { optimizationLevel: 3 },
      optipng: { optimizationLevel: 7 },
      mozjpeg: { quality: 80 },
      pngquant: { quality: [0.7, 0.8] },
      svgo: { plugins: [{ name: 'removeViewBox' }] }
    })
  ],

  build: {

    target: 'esnext',

    minify: 'esbuild',

    cssCodeSplit: true,

    sourcemap: false,

    chunkSizeWarningLimit: 2000,

    assetsInlineLimit: 4096,

    rollupOptions: {
      output: {

        manualChunks: {
          'react-vendor': [
            'react',
            'react-dom',
            'react-router-dom',
            'zustand'
          ],

          'arco-design': ['@arco-design/web-react'],

          echarts: ['@ceai-front/echarts'],

          pdfjs: ['pdfjs-dist'],

          utils: [
            'lodash',
            'lodash-es',
            'dayjs',
            'axios',
            'classnames'
          ]
        },

        assetFileNames: 'assets/[name].[hash][extname]',
        chunkFileNames: 'js/[name].[hash].js',
        entryFileNames: 'js/[name].[hash].js'
      }
    }
  }
})

5性能优化三件套 & 术语表

优化手段解决的问题口诀
1️⃣ 路由懒加载控制什么时候加载代码 → 首屏体积大幅下降懒加载 = 控制加载时机
2️⃣ manualChunks 分包把长期不变的依赖单独打包 → 浏览器缓存最大化分包 = 控制缓存策略
3️⃣ 图片压缩减少最大体积资源 → 页面加载速度明显提升图片压缩 = 减少资源体积
✅ 一套下来,项目通常会有明显变化:首屏体积下降、JS chunk 更清晰、浏览器缓存利用率更高、页面加载更快。

术语表

术语定义
Code Splitting代码拆分,按需加载不同 chunk,避免首屏加载全部代码
manualChunksRollup 手动分包配置,控制第三方依赖的 chunk 归属
Tree Shaking构建时移除未使用代码(死代码消除)
assetsInlineLimit小于该字节数的静态资源转 Base64 内联,减少请求数
vite-plugin-imageminVite 图片压缩插件,自动优化 PNG/JPG/SVG 等格式
chunkSizeWarningLimitchunk 体积告警阈值,超过会输出构建警告