加载中...

Vite:性能优化-分包策略

Vite:性能优化-分包策略

介绍

在我们项目开发完成后,需要进行项目的打包优化,本文讲解如何在Vite中进行分包,提升项目的性能。 分包策略涉及的优化点有如下几点:首次加载、加载时间、浏览器缓存策略、代码体积。接下来讲一下分包解决的哪些问题,以及使用代码和工程图进行项目分包处理。

分包策略解决的问题

首次加载

在项目中,如果我们的项目中依赖了很多的第三方库或写了很多的代码,在没进行分包处理的情况下,所有代码都是直接打包到一个js文件中的,浏览器在请求到该js文件之后需要一次性加载所有的代码。这样就会在项目很大的情况下,页面加载很久或白屏加载一段时间再展示加载后的内容。这样就会带来很不好的用户体验。

加载时间

和首次加载一样,文件中代码依赖太多,加载时间就会越久。

浏览器缓存策略

在项目中如果a页面中引用了c页面的代码,b页面也引用了c页面的代码。在浏览器中访问a和b页面时,会重复请求c页面的代码。这样就出现了不必要的代码请求和加载。

New Image

Vite进行分包配置

在Vite中配置项目打包后的分包配置,是通过配置build.rollupOptions.output来实现的。在Vite中配置打包的内容是通过rollup来进行配置的,所以需要去看看rollup的官网文档哦 Configuration Options | Rollup

manualChunks 配置选项 |汇总 --- Configuration Options | Rollup

参数:对象数组 / 函数

Type:  类型
代码解读
复制代码
{ [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)

manualChunks(对象数组形式)

参数:对象数组

css
代码解读
复制代码
manualChunks: { xxx: [''yyy''], },

其中xxx就是分包名,数组中的yyy可以是当前项目中的任意文件(相对路径)、第三方库的名称。 对于对象数组这种形式,支持指定key值对应多个内容,打包后的结果就是将数组中的内容全部打包到名称为key.xxxx.js中。

写法如下:

vite.config.js文件
代码解读
复制代码
import { defineConfig } from ''vite''; import vue from ''@vitejs/plugin-vue''; import { viteMockServe } from ''vite-plugin-mock''; // https://vite.dev/config/ export default defineConfig({ plugins: [ vue(), viteMockServe({ mockPath: ''mock'', }), ], build: { rollupOptions: { output: { manualChunks: { vue: [''vue'', ''vue-router'', ''pinia''], echarts: [''echarts''], lodash: [''lodash''], a: [''./src/modules/a''], b: [''./src/modules/b''], c: [''./src/modules/c''], App: [''./src/App.vue''], }, entryFileNames: `js/[name]-[hash].js`, chunkFileNames: `js/[name]-[hash].js`, assetFileNames(assetInfos) { if (assetInfos.name.endsWith(''.css'')) { return `css/[name]-[hash].css`; } return `[ext]/[name]-[hash].[ext]`; }, }, }, }, });

上述代码中我们配置的manualChunks最终的打包结果如下:

  • vue.xxxx.js文件:该文件中包含''vue'', ''vue-router'', ''pinia''代码。
  • echarts.xxxx.js文件:包含echarts代码。
  • lodash.xxxx.js文件:包含lodash代码。
  • a.xxxx.js文件:包含./src/modules/a代码。
  • b.xxxx.js文件:包含./src/modules/b代码。
  • c.xxxx.js文件:包含./src/modules/c代码。
  • App.xxxx.js文件:包含./src/App.vue代码。 打包结果图如下所示:

New Image

manualChunks(函数形式)

参数:函数

typescript
代码解读
复制代码
manualChunks: (id,{getModuleInfo,getModuleIds})=>{ xxxx操作... return string|void }

函数参数:

  • id 依赖包的绝对地址 (常用
  • getModuleInfo 获取当前id对应的模块信息 (不常用)
  • getModuleIds (不常用)

写法如下:

javascript
代码解读
复制代码
import { defineConfig } from ''vite''; import vue from ''@vitejs/plugin-vue''; import { viteMockServe } from ''vite-plugin-mock''; // https://vite.dev/config/ export default defineConfig({ plugins: [ vue(), viteMockServe({ mockPath: ''mock'', }), ], build: { rollupOptions: { output: { manualChunks(id, config) { console.log(id); if (id.includes(''node_modules'')) { return id .toString() .split(''node_modules/.pnpm'')[1] .split(''/'')[0] .toString(); } }, entryFileNames: `js/[name]-[hash].js`, chunkFileNames: `js/[name]-[hash].js`, assetFileNames(assetInfos) { if (assetInfos.name.endsWith(''.css'')) { return `css/[name]-[hash].css`; } return `[ext]/[name]-[hash].[ext]`; }, }, }, }, });

entryFileNames 配置选项 |汇总 --- Configuration Options | Rollup

是一个用于定义入口文件生成规则的选项。它允许你自定义输出文件的名字模式,特别是当你有多个入口点时非常有用。通过设置这个选项,你可以控制最终打包后的文件名格式,包括添加哈希值、指定目录结构等。

写法如下:

ini
代码解读
复制代码
entryFileNames: `js/[name]-[hash].js`,

其中name和hash是rollup提供的占位符。其他占位符如下:

  • [format]: The rendering format defined in the output options, e.g. es or cjs.
    [format]:输出选项中定义的渲染格式,例如 es 或 cjs
  • [hash]: A hash based only on the content of the final generated entry chunk, including transformations in renderChunk and any referenced file hashes. You can also set a specific hash length via e.g. [hash:10]. By default, it will create a base-64 hash. If you need a reduced character sets, see output.hashCharacters
    [hash]:仅基于最终生成的入口块内容的哈希,包括 renderChunk 中的转换和任何引用的文件哈希。您还可以通过 [hash:10] 设置特定的哈希长度。默认情况下,它将创建一个 base-64 哈希。如果您需要简化的字符集,请参阅 output.hashCharacters
  • [name]: The file name (without extension) of the entry point, unless the object form of input was used to define a different name.
    [name]:入口点的文件名(不带扩展名),除非使用 input 的对象形式来定义不同的名称。

chunkFileNames 配置选项 |汇总 --- Configuration Options | Rollup

chunkFileNames 选项用于定义非入口(non-entry)chunk文件的命名规则。当你使用代码拆分(例如通过动态导入 import())时,Rollup会为每个拆分出来的chunk生成一个单独的文件chunkFileNames 就是用来控制这些文件的命名格式。 写法如下:

ini
代码解读
复制代码
chunkFileNames: `js/[name]-[hash].js`,

其中name、hash也是占位符。

assetFileNames 配置选项 |汇总 --- Configuration Options | Rollup

output.assetFileNames 选项用于定义非JavaScript资源(如图片、CSS文件等)的命名规则。当你在打包过程中包含这些资源时(例如通过 import ''./path/to/image.png'' 或者通过插件处理的资源),Rollup会根据你设置的 assetFileNames 模板来命名这些资源文件。

参数类型:string | ((assetInfo: PreRenderedAsset) => string)(字符串 | 函数)

默认值:assets/[name]-[hash][extname]

写法如下:

scss
代码解读
复制代码
assetFileNames(assetInfos) { if (assetInfos.name.endsWith(''.css'')) { return `css/[name]-[hash].css`; } return `[ext]/[name]-[hash].[ext]`; },

完整代码

php
代码解读
复制代码
import { defineConfig } from ''vite''; import vue from ''@vitejs/plugin-vue''; import { viteMockServe } from ''vite-plugin-mock''; // https://vite.dev/config/ export default defineConfig({ plugins: [ vue(), viteMockServe({ mockPath: ''mock'', }), ], build: { rollupOptions: { output: { manualChunks: { vue: [''vue'', ''vue-router'', ''pinia''], echarts: [''echarts''], lodash: [''lodash''], a: [''./src/modules/a''], b: [''./src/modules/b''], c: [''./src/modules/c''], App: [''./src/App.vue''], }, // manualChunks(id, config) { // console.log(id); // if (id.includes(''node_modules'')) { // return id // .toString() // .split(''node_modules/.pnpm'')[1] // .split(''/'')[0] // .toString(); // } // }, entryFileNames: `js/[name]-[hash].js`, chunkFileNames: `js/[name]-[hash].js`, assetFileNames(assetInfos) { if (assetInfos.name.endsWith(''.css'')) { return `css/[name]-[hash].css`; } return `[ext]/[name]-[hash].[ext]`; }, }, }, }, });

知识点总结

  • 使用vite进行代码分包处理是通过配置rollup选项。(vite中是output.xxx)
  • manualChunks:用于手动控制代码拆分的方式,提供对象数组/函数的形式。
  • entryFileNames:配置入口文件名
  • chunkFileNames:配置分包的文件名称
  • assetFileNames:处理非js文件的文件名