在使用 Rollup 进行打包时,
manualChunks
选项可以帮助你手动控制代码拆分(code splitting),这对于优化大文件的加载性能非常有用。通过合理地拆分代码,可以减少初始加载时间,并提高应用的整体性能。
manualChunks
简介
manualChunks
是 Rollup 配置中的一个选项,允许你根据模块路径或其他逻辑将代码拆分为多个 chunk 文件。这比自动拆分提供了更多的控制,特别是在处理大型项目时。
使用 manualChunks
拆分大文件
以下是一个示例配置,展示了如何使用 manualChunks
来拆分大文件:
示例配置
javascript
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
export default {
input: 'src/main.js',
output: {
dir: 'dist',
format: 'es',
entryFileNames: '[name].js',
chunkFileNames: '[name]-[hash].js',
},
plugins: [
resolve(),
commonjs(),
terser(),
],
manualChunks(id) {
// 根据模块路径进行拆分
if (id.includes('node_modules')) {
// 将所有 node_modules 中的依赖打包到 vendor.js 中
return 'vendor';
}
if (id.includes('src/utils')) {
// 将 utils 目录下的模块打包到 utils.js 中
return 'utils';
}
if (id.includes('src/components')) {
// 将 components 目录下的模块打包到 components.js 中
return 'components';
}
// 其他模块保持默认行为
}
};
这样vendor打包的js文件可能会很大,如果你使用了pnpm可能还会把node_modules/.pnpm的文件打包进去,如何避免?
js
export default defineConfig({
...
build: {
rollupOptions: {
output: {
chunkFileNames: "static/js/[name]-[hash].js",
entryFileNames: "static/js/[name]-[hash].js",
assetFileNames: "static/[ext]/[name]-[hash].[ext]",
// manualChunks(id) {
// if (id.includes("node_modules") && !id.includes(".pnpm")) {
// return id
// .toString()
// .split("node_modules/")[1]
// .split("/")[0]
// .toString();
// }
// },
manualChunks: {
'element-plus': ['element-plus'],
echarts: ['echarts'],
}
},
},
},
...
})
关键点解释
input
: 指定入口文件。output
:dir
: 输出目录。format
: 输出格式(如 ES 模块)。entryFileNames
: 入口文件的命名规则。chunkFileNames
: 动态导入或拆分出的 chunk 文件的命名规则。
plugins
: 使用的插件,如@rollup/plugin-node-resolve
、@rollup/plugin-commonjs
和@rollup/plugin-terser
。manualChunks
: 自定义拆分逻辑:- 如果模块路径包含
node_modules
,则将其打包到vendor.js
中。 - 如果模块路径包含
src/utils
,则将其打包到utils.js
中。 - 如果模块路径包含
src/components
,则将其打包到components.js
中。 - 对于其他模块,默认行为是保持不变。
- 如果模块路径包含
进一步优化
1. 动态导入
你可以结合动态导入 (import()
) 来进一步优化代码拆分。例如:
javascript
// 在 main.js 中
const loadComponent = async () => {
const module = await import('./components/MyComponent');
return new module.default();
};
Rollup 会自动识别这种动态导入,并将其拆分为单独的 chunk 文件。
2. 基于大小的拆分
如果你希望根据模块大小进行拆分,可以结合 treeshake
和 output.manualChunks
的逻辑来实现。例如:
javascript
manualChunks(id) {
const sizeThreshold = 50 * 1024; // 50KB
const moduleSize = calculateModuleSize(id); // 假设有一个函数计算模块大小
if (moduleSize > sizeThreshold) {
return 'large-modules';
}
if (id.includes('node_modules')) {
return 'vendor';
}
// 其他逻辑...
}
注意:上述代码中的 calculateModuleSize
是假设的一个函数,实际中你需要实现或找到合适的工具来计算模块大小。
3. 第三方库的拆分
对于第三方库,通常建议将它们打包到一个单独的 chunk 文件中,以避免重复加载。例如:
javascript
manualChunks(id) {
if (id.includes('node_modules')) {
// 将所有 node_modules 中的依赖打包到 vendor.js 中
return 'vendor';
}
// 其他逻辑...
}
总结
通过 manualChunks
,你可以灵活地控制 Rollup 如何拆分你的代码。合理的拆分策略不仅可以提升应用的加载速度,还能改善用户体验。以下是一些最佳实践:
- 按功能模块拆分:将不同功能模块拆分为独立的 chunk 文件。
- 第三方库分离:将第三方库打包到单独的 chunk 文件中,减少重复加载。
- 动态导入:结合动态导入进一步优化代码拆分。