介绍
在我们项目开发完成后,需要进行项目的打包优化,本文讲解如何在Vite中进行分包,提升项目的性能。 分包策略涉及的优化点有如下几点:首次加载、加载时间、浏览器缓存策略、代码体积。接下来讲一下分包解决的哪些问题,以及使用代码和工程图进行项目分包处理。
分包策略解决的问题
首次加载
在项目中,如果我们的项目中依赖了很多的第三方库或写了很多的代码,在没进行分包处理的情况下,所有代码都是直接打包到一个js文件中的,浏览器在请求到该js文件之后需要一次性加载所有的代码。这样就会在项目很大的情况下,页面加载很久或白屏加载一段时间再展示加载后的内容。这样就会带来很不好的用户体验。
加载时间
和首次加载一样,文件中代码依赖太多,加载时间就会越久。
浏览器缓存策略
在项目中如果a页面中引用了c页面的代码,b页面也引用了c页面的代码。在浏览器中访问a和b页面时,会重复请求c页面的代码。这样就出现了不必要的代码请求和加载。
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代码。 打包结果图如下所示:
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.esorcjs.
[format]:输出选项中定义的渲染格式,例如es或cjs。[hash]: A hash based only on the content of the final generated entry chunk, including transformations inrenderChunkand 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, seeoutput.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文件的文件名