Rollup含index.ts时如何生成指定的代码分块目录结构?
问题描述
项目结构
- src/
- controllers/
- controller1.ts
- controller2.ts
- utils/
- misc.ts
- other-file.ts
- index.ts
- controllers/
- node_modules/
期望生成的dist结构
- dist/
- controllers/
- controller1.js
- controller2.js
- _app.js(对应utils目录代码)
- _vendor.js(对应node_modules代码)
- index.js
- controllers/
当前使用的rollup.mjs配置
export default { input: [ 'src/index.ts', ...glob.sync('src/controllers/**/*.ts', { ignore: ['src/**/*.test.ts'] }), ], output: { dir: 'dist', format: 'cjs', chunkFileNames: '[name].js', entryFileNames: (chunkInfo) => { const { dir, name } = parse(relative('src', chunkInfo.facadeModuleId)); if (dir.startsWith('controllers')) { return `${dir}/${name}.js`; } return 'controllers/_app.js'; }, manualChunks: (id) => { if (id.includes('node_modules')) { return 'controllers/_vendor'; } return 'controllers/_app'; }, }, perf: true, plugins: [ del({ targets: 'dist/*' }), preserveShebangs(), commonjs(), nodeResolve({ preferBuiltins: true }), json({ compact: true }), typescript({ tsconfig: './tsconfig.build.json' }), ], };
遇到的问题
当输入中不包含index.ts时,Rollup可以分别生成controllers、utils和node_modules的独立分块文件;但加入index.ts后,utils目录的内容会被合并到index.js中,无法生成独立的_app.js分块。需要实现目标dist结构,求解决思路及配置调整方案。
解决思路及配置调整
可以通过调整Rollup的manualChunks逻辑和output相关配置实现目标,无需自定义插件,核心是明确区分入口文件与公共依赖块:
修正
manualChunks分块规则
当前规则会把所有非node_modules代码都归入controllers/_app,但入口文件(index.ts和控制器文件)不应被分到公共块。修改规则,仅将utils目录代码和非入口、非node_modules的公共代码分到_app块:manualChunks: (id, { getModuleInfo }) => { // 处理node_modules依赖 if (id.includes('node_modules')) { return 'controllers/_vendor'; } // 排除入口模块本身 const moduleInfo = getModuleInfo(id); if (moduleInfo?.isEntry) { return; } // 归集utils目录代码到_app块 if (id.includes('src/utils')) { return 'controllers/_app'; } },调整
entryFileNames输出路径
当前逻辑会把index.ts输出到controllers/_app.js,不符合期望。修改后让index.ts单独输出到dist根目录,控制器文件保持原结构:entryFileNames: (chunkInfo) => { const { dir, name } = parse(relative('src', chunkInfo.facadeModuleId)); if (dir.startsWith('controllers')) { return `${dir}/${name}.js`; } // index.ts直接输出到dist根目录 return `${name}.js`; },完整调整后的配置
import { parse, relative } from 'path'; import glob from 'glob'; import del from 'rollup-plugin-delete'; import preserveShebangs from 'rollup-plugin-preserve-shebangs'; import commonjs from '@rollup/plugin-commonjs'; import nodeResolve from '@rollup/plugin-node-resolve'; import json from '@rollup/plugin-json'; import typescript from '@rollup/plugin-typescript'; export default { input: [ 'src/index.ts', ...glob.sync('src/controllers/**/*.ts', { ignore: ['src/**/*.test.ts'] }), ], output: { dir: 'dist', format: 'cjs', chunkFileNames: '[name].js', entryFileNames: (chunkInfo) => { const { dir, name } = parse(relative('src', chunkInfo.facadeModuleId)); if (dir.startsWith('controllers')) { return `${dir}/${name}.js`; } return `${name}.js`; }, manualChunks: (id, { getModuleInfo }) => { if (id.includes('node_modules')) { return 'controllers/_vendor'; } const moduleInfo = getModuleInfo(id); if (moduleInfo?.isEntry) { return; } if (id.includes('src/utils')) { return 'controllers/_app'; } }, }, perf: true, plugins: [ del({ targets: 'dist/*' }), preserveShebangs(), commonjs(), nodeResolve({ preferBuiltins: true }), json({ compact: true }), typescript({ tsconfig: './tsconfig.build.json' }), ], };
原理说明
- 通过
manualChunks排除入口模块,仅将utils和node_modules代码归入对应公共块,避免入口被合并到公共块中。 - 调整
entryFileNames保证index.ts输出到dist根目录,控制器文件维持原目录结构。 - 借助Rollup的代码拆分机制,即使只有
index.ts依赖utils,manualChunks也会强制将utils代码分到独立的_app.js,不会内联到index.js。
内容的提问来源于stack exchange,提问作者Black Moon
相关产品推荐
相关产品推荐

