You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rollup含index.ts时如何生成指定的代码分块目录结构?

问题描述

项目结构

  • src/
    • controllers/
      • controller1.ts
      • controller2.ts
    • utils/
      • misc.ts
      • other-file.ts
    • index.ts
  • node_modules/

期望生成的dist结构

  • dist/
    • controllers/
      • controller1.js
      • controller2.js
      • _app.js(对应utils目录代码)
      • _vendor.js(对应node_modules代码)
    • index.js

当前使用的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相关配置实现目标,无需自定义插件,核心是明确区分入口文件与公共依赖块:

  1. 修正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';
      }
    },
    
  2. 调整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`;
    },
    
  3. 完整调整后的配置

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 10:08:18