Skip to content

Vite相关性能优化

分包策略

在生产环境下 Vite 完全利用 Rollup 进行构建,因此拆包也是基于 Rollup 来完成的

Vite 默认拆包策略

只不过Rollup专注于JS库的打包,对应用构建的能力还有待提升,Vite 正好是补足了 Rollup 应用构建的能力,在拆包能力这一块的扩展就是很好的体现

项目的基本结构:

text
.
├── public
│   ├── vite.svg
├── src
│   ├── routes
│   │			└── index.ts		//路由配置
│   ├── views
│   │			├── AboutView.vue 	// 懒加载路由页面
│   │			├── HomeView.vue	// 直接加载路由页面
│   │			├── PhotoView.vue   // 懒加载路由页面
│   │			├── StudentView.vue // 懒加载路由页面
│   │			└── UserView.vue	// 懒加载路由页面
│   ├── App.vue
│   └── main.ts
└── index.html

打包之后的产物:

text
.
├── assets
│   ├── AboutView-355cc1df.js   // Async Chunk
│   ├── AboutView-786d9592.css 	// Async Chunk (CSS)
│   ├── index-c0c63fdb.js      	// Initial Chunk
│   ├── index-d1e7a483.css     	// Initial Chunk (CSS)
│   ├── StudentView-85c73246.js // Async Chunk
│   └── UserView-18eefd25.js	// Async Chunk
├── index.html                 	// 入口 HTML
└── vite.svg                    // 静态资源

这是没有任何配置的vite打包之后的产物,自动对懒加载的路由和与其对应的css进行的处理

自定义拆包策略

针对更细粒度的拆包,Vite还是基于的Rollup处理。

manualChunks 主要有两种配置的形式,可以配置为一个对象或者一个函数。

对象方式

js
build: {
  ...
  rollupOptions: {
    output: {
      ...
      manualChunks:{
        'vue-vendor': ['vue', 'vue-router']
      }
    }
	}
}

在对象格式的配置中,key代表 chunk 的名称,value为一个字符串数组,每一项为第三方包的包名

text
vite v4.4.9 building for production...
✓ 34 modules transformed.
dist/index.html                        0.54 kB │ gzip:  0.33 kB
dist/assets/AboutView-786d9592.css     0.04 kB │ gzip:  0.06 kB
dist/assets/index-d1e7a483.css         0.27 kB │ gzip:  0.17 kB
dist/assets/UserView-9010cdee.js       0.55 kB │ gzip:  0.35 kB
dist/assets/StudentView-eff7d69a.js    0.55 kB │ gzip:  0.35 kB
dist/assets/AboutView-74a57329.js      0.78 kB │ gzip:  0.43 kB
dist/assets/index-4fb9786f.js          5.87 kB │ gzip:  2.06 kB
dist/assets/vue-vendor-99c39a4b.js   210.95 kB │ gzip: 49.67 kB
✓ built in 553ms

可以看到之前很大的index.js文件被拆分了出来。

函数方式

typescript
manualChunks(id) {
  if (id.includes('node_modules/vue')) {
    return 'vue';
  }
  if (id.includes('element-plus')) {
    return 'element-plus';
  }
  if (id.includes('lodash-es')) {
    return 'lodash';
  }
}

不过需要注意的是,这种方式在Vite4并不安全,因为如element-plusvue-demi也依赖了Vue,这里单独拆分Vue的话,导致循环依赖的错误问题

一般情况下,建议还是使用对象方式

treeshaking

这个没什么可多说的,不需要额外进行配置。

但有一个条件,必须是 ES6 module 模块才行,而且我们自己在引入的时候,注意只需要引入具体的函数(对象),不要直接导入全对象

代码压缩

Vite默认使用esbuild进行代码压缩,速度快,如果要追求压缩效果。

typescript
minify:esbuild

也可以使用terserVite也默认集成了terser,只是需要手动导入terser插件

typescript
minify: 'terser',
terserOptions: {
  compress: {
      drop_console: true,
      drop_debugger: true,
  }
},

GZIP压缩

gzip 是一种使用非常普遍的压缩格式。使用 gzip 压缩可以大幅减小代码体积,提升网络性能。当然gzip只是其中一种,brotliCompress也是一样,一般简称br

服务器就可以直接帮我们处理,不过需要耗费服务器性能,所以,一般前端也可能直接把打包之后的文件进行压缩处理,直接使用插件即可vite-plugin-compression2

typescript
import { compression } from 'vite-plugin-compression2'
......

plugins: [
  ......
  compression({
    //压缩算法,默认gzip
    algorithm: 'brotliCompress',
    //匹配文件
    include: [/\.(js)$/, /\.(css)$/,],
    //压缩超过此大小的文件,以字节为单位
    // threshold: 10240,
    //是否删除源文件,只保留压缩文件
    // deleteOriginalAssets: true
  }),
  ]

图片压缩

图片压缩肯定可以减少网络传输,不过需要看项目对图片清晰度的需求,一般情况下,如果美工能直接处理最好,或者我们也可以使用外部工具进行处理,甚至是网上就可以直接处理,比如:tinypng

如果前端处理的话,可以使用插件vite-plugin-imagemin

typescript
import viteImagemin from 'vite-plugin-imagemin'
......
plugins: [
  ...... 
  viteImagemin({
     gifsicle: {
       optimizationLevel: 7,
       interlaced: false,
     },
     optipng: {
       optimizationLevel: 7,
     },
     mozjpeg: {
       quality: 20,
     },
     pngquant: {
       quality: [0.8, 0.9],
       speed: 4,
     },
     svgo: {
       plugins: [
         {
           name: 'removeViewBox',
         },
         {
           name: 'removeEmptyAttrs',
           active: false,
         },
       ],
     },
   }),
]

产物构建分析

为了能可视化地感知到产物的体积情况,推荐大家用rollup-plugin-visualizer来进行产物分析

typescript
import { visualizer } from "rollup-plugin-visualizer";
......
plugins: [
  visualizer({
    // 是否打包完成之后直接打开
    open: true,
  }),
],

CDN加速

使用CDN,可以让用户从最近的服务器请求资源,能够大大的提高资源的请求获取的速度。特别是一些第三方资源库,放在CDN上不但可以提高资源请求速度,而且也能大大降低我们打包体积和打包速度。

如果要把项目中的一些第三方资源放入到CDN,但是项目中我们又使用了这些资源,需要在项目中进行处理。一般比较常用的处理方式是直接使用第三方插件。比如:rollup-plugin-external-globals

typescript
import externalGlobals from "rollup-plugin-external-globals";
......
rollupOptions: {
  external:['vue','vue-router','element-plus','vue-echarts','echarts','@vueuse/core'],
  plugins: [
    externalGlobals({
      "vue": "Vue",
      "vue-router": "VueRouter",
      "element-plus": 'ElementPlus',
      "@vueuse/core": "VueUse",
      "echarts": "echarts",
      "vue-echarts": "VueECharts",
    })
  ],
}

打包处理

如果希望设置打包之后的文件位置,可以通过相关rollup设置处理

typescript
build:{
  rollupOptions: {
    output: {
      chunkFileNames: 'assets/[name]-[hash].js',
      entryFileNames: 'assets/[name].[hash].js',
      assetFileNames: 'assets/xxx/[ext]/[name]-[hash].[ext]',
    }
}

自定义插件

Vite 插件扩展了设计出色的 Rollup 接口,整个Rollup插件结构体系比较庞杂,简单来说,分成了buildoutput两大工作流的不同阶段进行分类。这个还需要单独去学习。就Vite来说他有可以和rollup结合的通用钩子,也有自己的独有钩子

Vite独有钩子:

钩子名称释义
config在解析 Vite 配置前调用。钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量,包含正在使用的 mode 和 command。
configResolved在解析 Vite 配置后调用。使用这个钩子读取和存储最终解析的配置。
configureServer是用于配置开发服务器的钩子。
configurePreviewServerconfigureServer 相同但是作为预览服务器。
transformIndexHtml转换 index.html 的专用钩子。钩子接收当前的 HTML 字符串和转换上下文。
handleHotUpdate执行自定义 HMR 更新处理。

苏ICP备2025160170号-1 | 前端进化之路 | Released under the MIT License.