Split Chunks
2023-04-21代码拆分是我们优化打包体积的常用做法,目前常用的项目构建工具是 webpack 和 vite(rollup), 我们将对这两种工具的代码拆分的配置做一些介绍。
webpack
敬请期待...
vite(rollup)
测试环境:
- 安装了 ant-design-vue、lodash 包
- 配置了两个懒加载的路由
通常情况下,我们只会拆分业务代码和第三方依赖,其中业务代码中会包含一些动态引入的组件, 这些组件相关的模块默认情况下会被单独拆到一个 chunk。
vite 官方文档提供了拆分 vendor 的方式: vite 产物分块策略
// vite.config.tsimport { splitVendorChunkPlugin } from 'vite'export default defineConfig({ plugins: [splitVendorChunkPlugin()],})
构建结果如下:
但如果我们想自定义拆分 chunk,那上面的操作就不行了,得使用 rollup 的 manualChunks 配置, 它可以将一个或多个模块打包进同一个 chunk 中,它有对象、函数两种配置方式。
对象配置方式
// vite.config.tsimport { splitVendorChunkPlugin } from 'vite'export default defineConfig({ build: { rollupOptions: { output: { manualChunks: { // 将 lodash 这个包及其依赖打进 lodash chunk 里面 'lodash': [ 'lodash' ], // 将 User 和 UserAdd 两个组件及其依赖打进 user chunk 里面 'user': [ './src/pages/User/User.vue', './src/pages/User/UserAdd.vue' ] } } } }})
构建结果如下:
对象方式的手动拆分需要指明哪个或哪些模块要被打包进同一个 chunk, 但是不怎么灵活,如 node_modules 里面的一堆第三方包就不好打包成 chunk(可能可以,但我不知道,好心人提醒下 😁)。
函数配置方式
当该选项值为函数形式时,每个被解析的模块都会经过该函数处理。
// vite.config.tsimport { splitVendorChunkPlugin } from 'vite'export default defineConfig({ build: { rollupOptions: { output: { manualChunks: (id) => { if (id.includes('lodash')) { return 'lodash' } else if (id.includes('node_modules')) { return 'vendor' } else if (id.includes('pages/User')) { return 'user' } } } } }})
构建结果如下:
对象的配置方式就可以打包 vendor 了,单个或多个模块也可以打包进同一个 chunk。它还有更高级的用法,详见文档。
上面两种手动拆分 chunk 都需要注意一个问题,那就是被拆分模块的依赖也会被打包进 chunk 中。如果 User 组件使用了 vue-router, 下面两种写法会将 User 和 vue-router 打包在一起:
manualChunks: { 'user': [ './src/pages/User/User.vue' ]}manualChunks: (id) => { if (id.includes('page/User')) { return 'user' } else if (id.includes('node_modules')) { return 'vendor' }}
但如果是下面这种写法,User 会放进 user chunk 中,而 vue-router 会放进 vendor chunk 中。
manualChunks: (id) => { if (id.includes('node_modules')) { return 'vendor' } else if (id.includes('page/User')) { return 'user' }}
因为每个被解析的模块都会经过该函数处理,按上面的判断逻辑, vue-router 被抢先放进了 vendor chunk 里面,就不会被放进 user chunk 里面了。 可见,具体怎么拆包和 manualChunks 函数的逻辑相关,比较灵活,所以函数是推荐的配置方式。