介绍
在我们项目开发完成后,需要进行项目的打包优化,本文讲解如何在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
参数:对象数组 / 函数
{ [chunkAlias: string]: string[] } | ((id: string, {getModuleInfo, getModuleIds}) => string | void)
manualChunks(对象数组形式)
参数:对象数组
manualChunks: {
xxx: ['yyy'],
},
其中xxx就是分包名,数组中的yyy可以是当前项目中的任意文件(相对路径)、第三方库的名称。 对于对象数组这种形式,支持指定key值对应多个内容,打包后的结果就是将数组中的内容全部打包到名称为key.xxxx.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(函数形式)
参数:函数
manualChunks: (id,{getModuleInfo,getModuleIds})=>{
xxxx操作...
return string|void
}
函数参数:
- id 依赖包的绝对地址 (常用)
- getModuleInfo 获取当前id对应的模块信息 (不常用)
- getModuleIds (不常用)
写法如下:
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
是一个用于定义入口文件生成规则的选项。它允许你自定义输出文件的名字模式,特别是当你有多个入口点时非常有用。通过设置这个选项,你可以控制最终打包后的文件名格式,包括添加哈希值、指定目录结构等。
写法如下:
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 就是用来控制这些文件的命名格式。
写法如下:
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]
写法如下:
assetFileNames(assetInfos) {
if (assetInfos.name.endsWith('.css')) {
return `css/[name]-[hash].css`;
}
return `[ext]/[name]-[hash].[ext]`;
},
完整代码
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文件的文件名
推荐
看到了一篇比较好的文章 真就是前端性能优化比较全面的,大家有兴趣可以去看看 各方面都总结了的。 前端性能优化的几个大招(理论+实践,看完就是Leader水平)前言 性能优化,一个掣肘用户体验的关键模块。它没有固定的标 - 掘金 墙裂推荐