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

以下内容 仅供参考酌情使用,正好最近优化项目 顺便记录下 后续好翻阅

说起 Vite 和性能优化,网上大多都是讲概念,比如:

  • 什么是分包
  • 什么是懒加载
  • 什么是 Tree Shaking

但很多文章 只讲理论,不讲工程实践

最近正好优化了一个项目的打包体积和首屏加载速度,顺手把 Vite 实战中最常见、最有效的优化方式总结了一下。

本文不讲复杂原理,只讲 真实项目里最有用的优化方法

如果你的项目存在这些问题:

  • 打包后 dist 特别大
  • 首屏加载慢
  • 每次发布用户都要重新下载一堆 JS
  • 图片体积巨大

那么这篇文章基本可以解决 80% 的性能问题


一、默认情况下,Vite 的打包会发生什么?

很多人误以为:

Vite 会把所有代码打成一个 JS。

其实并不是。

Vite 的生产构建基于 Rollup ,默认会做基础的 chunk splitting(代码拆分)

例如:

css 复制代码
main.js
vendor.js

但默认拆分 不会按照业务语义优化,可能会出现:

复制代码
首页代码 + lodash
报表代码 + lodash
编辑器代码 + lodash

也就是说:

同一个依赖可能会被多个 chunk 引用,或者混入业务代码。

这会导致几个问题:

1️⃣ 首屏加载体积过大

2️⃣ 浏览器缓存利用率低

3️⃣ 更新业务代码时 vendor 也失效

所以我们需要做 更精细的分包控制


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

最基础也是最重要的一步:

按页面加载代码。

如果不做懒加载:

复制代码
用户打开首页
↓
下载整个项目所有页面代码

如果做了懒加载:

复制代码
打开首页
↓
只加载首页代码

进入报表页
↓
再加载报表代码

这样 首屏体积会显著下降


React 示例

javascript 复制代码
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>
  )
}

核心思想只有一句话:

用到哪个页面,再加载哪个页面的代码。


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

懒加载解决的是 业务代码拆分

但第三方依赖仍然可能混在业务 chunk 里。

例如:

arduino 复制代码
page-home.js
  └ react
  └ lodash

page-report.js
  └ echarts
  └ lodash

如果业务代码更新:

arduino 复制代码
page-home hash 改变
↓
lodash 也被重新下载

浏览器缓存就失效了。


manualChunks 的作用

manualChunks 可以 手动控制依赖如何分包

把长期不变的依赖拆出来:

复制代码
react-vendor.js
utils.js
echarts.js
editor.js

这样:

复制代码
业务更新
↓
只更新业务 chunk
↓
vendor 继续使用缓存

示例配置

css 复制代码
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'
      ]
    }
  }
}

更稳定的写法(推荐)

在大型项目中,很多团队更推荐使用函数写法:

python 复制代码
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 解析模块时使用的是 文件路径

bash 复制代码
node_modules/react/index.js

函数写法在复杂依赖场景中 更稳定


四、第三层优化:图片体积优化

在很多项目里:

图片往往才是体积最大的资源。

常见情况:

css 复制代码
banner.jpg   2MB
icon.png     800KB
background   3MB

一旦页面加载多张图片,性能会明显下降。


使用 vite-plugin-imagemin

安装:

csharp 复制代码
pnpm add vite-plugin-imagemin -D

配置:

css 复制代码
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' }]
    }
  })
]

通常可以减少:

erlang 复制代码
PNG  20% ~ 40%
JPG  10% ~ 30%
SVG  50%+

而肉眼几乎看不出差异。


五、一个容易忽略的小优化:assetsInlineLimit

yaml 复制代码
assetsInlineLimit: 4096

意思是:

小于 4KB 的资源会被转换为 Base64 并直接内联到 JS 中。

这样可以减少 HTTP 请求数量。

但不宜设置过大,否则 JS 体积会膨胀。


六、完整的 Vite 优化配置示例

php 复制代码
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'
      }
    }
  }
})

七、Vite 项目最实用的性能优化三件套

如果只记住三件事就够了:

1️⃣ 路由懒加载

控制 什么时候加载代码

复制代码
首屏体积大幅下降

2️⃣ manualChunks 分包

长期不变的依赖单独打包

复制代码
浏览器缓存最大化

3️⃣ 图片压缩

减少 最大体积资源

复制代码
页面加载速度明显提升

三者关系(很好记)

复制代码
懒加载 = 控制加载时机
分包 = 控制缓存策略
图片压缩 = 减少资源体积

一套下来,项目通常会有明显变化:

  • 首屏体积下降
  • JS chunk 更清晰
  • 浏览器缓存利用率更高
  • 页面加载更快
相关推荐
酉鬼女又兒2 小时前
HTML零基础快速入门篇(可用于备赛蓝桥杯Web应用开发) 牛客手把手戴刷FED1~8:基本标签,基本标签,媒体标签详解
前端·职场和发展·蓝桥杯·html·web
weixin199701080162 小时前
搜好货商品详情页前端性能优化实战
java·前端·python
SuperEugene2 小时前
NPM Script 实战:常用命令设计与封装|Vue 工程化篇
前端·javascript·vue.js·前端框架·npm
前端进阶之旅2 小时前
React 18 并发特性实战指南:提升大型应用性能的关键技术
前端·react.js·前端框架
恋猫de小郭2 小时前
Android 性能迎来提升:内核引入 AutoFDO 普惠所有 15-16 设备
android·前端·flutter
小霍同学2 小时前
Vue 动态表单(Dynamic Form)
前端·vue.js
Dragon Wu2 小时前
Taro 小程序开发注意事项(不定期记录更新)
前端·javascript·小程序·typescript·taro
wangfpp2 小时前
多端统一你真的会了吗?
前端·javascript·架构
小霍同学2 小时前
Vue 动态组件(Dynamic Components)
前端·vue.js