vite打包-拆包-合包-异步加载包
打包
什么样的资源会被打包?
从入口文件开始,进行扩散性关联扫描,被引用且被使用过至少 1 次的资源会被打包
什么样的文件会被独立成一个包?
- 默认情况下,被引用了至少两次的文件,会被打成一个独立的包
如: Utils01.ts 被 Main.vue, Other.vue 两个 vue 文件引用,则Utils01.ts会被打成一个独立的包
- 异步组件(含普通异步组件以及异步路由组件)会被打成一个独立包
什么样的资源会被合并打包?
- 默认情况下,只被引用了一次的文件会被合并到调用处打包
如:Utils01.ts 只被 Other.vue 文件引用,则Utils01.ts会被打包到Other.vue中
- 通过动态扫描引入的包会被合并打包.
这里的合并打包有两种情况:
- 动态扫描引入的 vue 文件只在一个 vue 组件中使用,那么动态引入的 vue 文件,会被合并打包到调用处
- 动态扫描引入的 vue 文件在多个 vue 组件中使用,那么动态引入的 vue 文件,会被合并打包到一个单独的 chunk
ts
import { Component as VueComponent } from 'vue'
const compMap = new Map<string, VueComponent>()
const mockFiles = import.meta.glob('./demo/*.vue', {
eager: true,
import: 'default',
})
Object.keys(mockFiles).forEach(key => {
const defaultObj = mockFiles[key]
//@ts-ignore
compMap.set(defaultObj.name, defaultObj)
})
如何手动合并零碎的文件
chunk 碎片 是如何产生的?
除了入口点(静态入口点、动态入口点)单独生成一个 chunk 之外,当一个模块被 2 个或以上的 chunk 引用,这个模块会单独生成一个 chunk。
而模块信息中,有两个字段可以利用,一个是 importers,一个是 dynamicImporters,对应着当前模块被静态引入的模块,以及被动态引入的模块。
当前模块的 importers.length + dynamicImporters.length > 1,就可以认为当前模块会被单独打成一个chunk
如何通过手动分包解决 chunk 碎片 问题?
让多个module拥有相同的chunk名称
如何鉴别哪些需要合包?
碎片化的产物可能需要合包
如何判断合包或拆包之后,是有效优化?
某个界面,在资源请求数量没有明显增多的情况下,总资源量变小了。特别要注意合包之后,不要导致首页资源加载变多
基于 vite3 发现的一些手动合包/拆包的规律
- 如果 chunk 中的有 1 个 module 有在首页使用到,那么该 chunk 必然会在首页加载(这可能导致首页加载了不必要的资源)
- 如果对异步路由组件进行合包,那被合包的 chunk, 必然会在首页加载(这个异步路由对于首页而言,可能也是不必要的资源)
- 如果对异步组件(如:
const HelloWorld = defineAsyncComponent(() => import('./HelloWorld.vue')))进行合包, 则该合包的 chunk 必然会在首页加载(这个异步组件对于首页而言,可能也是不必要的资源) - vite3 默认会根据引用情况对第三方依赖,进行拆包/合包,通常情况比我们自己再进行拆包合包形成的包的大小更合理(更小)
总结:
- 尽量只对自己编写的碎片化的普通 ts/js 文件进行合包(所谓普通 ts/js 如:XxxUtil, XxxApi 之类的)
- 不要对异步路由组件进行合包
- 不要对异步组件合包,除非该 chunk 中所有的异步组件本来就要在首页使用
- 尽量不要手动对第三方依赖进行合包/分包
参考资料
分析 vite2.x/rollup 分包原理,解决 chunk 碎片问题