Skip to content

Monorepo 面试题

本面试题基于《Monorepo 学习文档》编写,按难度分为基础、进阶、高级三个等级,每题均附详细参考答案与评分要点,适用于前端工程化岗位面试与技术评估。


一、基础题

0. 第 1 题基础

第 1 题

请简述 Monorepo 与 Polyrepo 的主要区别,以及各自适合什么场景。

参考答案:

Monorepo:将多个相关项目放在同一个仓库中管理,共享工具链和规范。

优势:

  • 代码共享方便;
  • 原子化提交,保证多项目一致性;
  • 统一 ESLint、Prettier、CI/CD 规范;
  • 跨项目重构成本低;
  • 构建缓存复用。

劣势:

  • 仓库体积大;
  • 权限控制复杂;
  • 构建耦合;
  • 工具链要求高。

Polyrepo:一个项目一个仓库,独立演进。

优势:

  • 隔离性强;
  • 权限简单;
  • 工具简单。

劣势:

  • 代码复用困难;
  • 版本管理复杂;
  • 重复配置;
  • 跨项目重构困难。

适用场景:

  • Monorepo 适合多个项目共享大量代码、需要频繁跨项目协作、希望统一规范的大型团队。
  • Polyrepo 适合项目关联度低、团队独立、权限隔离要求高的场景。

评分维度

  • 能解释两者定义(30%)
  • 能分别说出优劣势(40%)
  • 能给出适用场景(30%)

0. 第 2 题基础

第 2 题

什么是幽灵依赖(Phantom Dependencies)?pnpm 如何避免幽灵依赖?

参考答案:

幽灵依赖是指某个包没有在其 package.json 中声明依赖,却可以使用 node_modules 中其他包安装的依赖。这会导致依赖关系不透明,一旦上层依赖变化,代码可能无法运行。

pnpm 通过严格的依赖隔离机制避免幽灵依赖:

  • 每个包只能访问自己 package.json 中声明的依赖;
  • pnpm 使用软链接和硬链接组织 node_modules,不随意提升依赖;
  • 子包的 node_modules 结构清晰,不会出现未声明却可访问的依赖。

评分维度

  • 能解释幽灵依赖概念(40%)
  • 说明危害(20%)
  • 说明 pnpm 的严格隔离和软链接机制(40%)

0. 第 3 题基础

第 3 题

请解释 workspace:* 协议的作用。

参考答案:

workspace:* 是 pnpm/yarn 等包管理器支持的 workspace 协议,用于引用同一个 Monorepo 中的内部包。

作用:

  • 避免手动维护内部包的版本号;
  • 发布到 npm 时,工具会自动将其替换为具体版本号;
  • 保证开发时使用本地最新代码,而不是从 npm 下载。

评分维度

  • 能说明 workspace:* 引用内部包(40%)
  • 提到发布时自动替换版本号(40%)
  • 说明开发时使用本地代码(20%)

0. 第 4 题基础

第 4 题

Changesets 的工作流程是什么?

参考答案:

Changesets 是现代 Monorepo 常用的版本管理工具,工作流程如下:

  1. 开发者提交代码后,运行 pnpm changeset
  2. 选择变更的包和变更类型(major/minor/patch),生成一个 changeset 文件;
  3. 发布时运行 pnpm changeset version,自动 bump 版本号并生成 changelog;
  4. 最后运行 pnpm changeset publish,将包发布到 npm。

评分维度

  • 能按顺序说出四个步骤(60%)
  • 提到 major/minor/patch 变更类型(20%)
  • 说明版本号自动 bump 和 changelog 生成(20%)

0. 第 5 题基础

第 5 题

在 Monorepo 中,根目录依赖和子包依赖应该如何划分?

参考答案:

  • 根目录依赖:通用的开发工具,如 TypeScript、ESLint、Prettier、Jest、Turborepo。这些工具不随应用发布,只用于开发、构建、测试。
  • 子包依赖:该包运行时真正需要的依赖,如 React、Vue、lodash 等。应该放在对应子包的 dependenciesdevDependencies 中。

划分原则:

  • 能被多个子包共享的开发工具放根目录;
  • 运行时依赖必须声明在子包中;
  • 避免把所有依赖都堆在根目录,导致子包依赖关系不清晰。

评分维度

  • 能区分根目录和子包依赖(50%)
  • 能举例说明(30%)
  • 提到依赖关系清晰化原则(20%)

0. 第 6 题基础

第 6 题

请对比 pnpm workspace、Turborepo、Nx、Rush 的适用规模。

参考答案:

方案 复杂度 构建缓存 任务编排 依赖管理 适用规模
pnpm workspace 中小型
Turborepo 依赖包管理器 中大型
Nx 大型
Rush 很强 超大型

评分维度

  • 能说出四种方案(40%)
  • 能按规模给出建议(40%)
  • 能说明 Turborepo/Nx 需配合包管理器(20%)

0. 第 7 题基础

第 7 题

为什么在大型 Monorepo 中需要使用 Affected Commands?

参考答案:

Affected Commands 只构建和测试受代码改动影响的项目,而不是每次改动都全量构建所有子包。

原因:

  • 大型 Monorepo 子包数量多,全量构建非常耗时;
  • 很多改动只影响少量子包,无需重建全部;
  • 可以显著缩短 CI 反馈时间,提高开发效率。

常见命令:

  • Turborepo:npx turbo run build --filter=[HEAD^1]--filter=...origin/main
  • Nx:nx affected:build --base=main --head=HEAD

注意事项:

  • 依赖图必须准确,否则可能漏构建或过度构建。
  • 合并到主分支前,通常基于 origin/main 计算 affected。
  • 远程缓存可以进一步加速 affected 构建。

评分维度

  • 能解释 Affected Commands 含义(25%)
  • 说明大型仓库全量构建慢的问题(25%)
  • 能举例命令并说明 base/head(25%)
  • 提到 CI 时间优化和依赖图准确性(25%)

二、进阶题

0. 第 8 题进阶

第 8 题

Turborepo 的 Pipeline 中,dependsOn: ["^build"]dependsOn: ["build"] 有什么区别?

参考答案:

  • dependsOn: ["^build"]:表示当前包的 build 任务依赖其上游依赖包的 build 任务。^ 表示上游依赖,即先构建被依赖的包。
  • dependsOn: ["build"]:表示当前包的当前任务依赖当前包自己的 build 任务,即先完成本包的构建。

例如:

{
  "pipeline": {
    "build": { "dependsOn": ["^build"] },
    "test": { "dependsOn": ["build"] }
  }
}
  • build 会先构建所有依赖包的 build;
  • test 会在本包 build 完成后执行。

评分维度

  • 能区分 ^ 和未加 ^ 的含义(60%)
  • 能结合 build/test 场景说明(30%)
  • 提到依赖图和任务调度(10%)

0. 第 9 题进阶

第 9 题

如何设计 Monorepo 中的测试策略?

参考答案:

  1. 统一测试框架:在根目录统一安装和配置 Vitest/Jest,子包只写测试用例。
  2. 测试范围控制:使用 --changed 或 affected 命令只运行受改动影响的测试。
  3. 测试分层:单元测试、集成测试、E2E 测试合理分布,形成测试金字塔。
  4. CI 集成:每次提交自动运行测试,失败阻止合并。
  5. 测试环境一致:通过 Docker 或统一的 CI Runner 保证环境一致。

评分维度

  • 能说出统一框架和范围控制(40%)
  • 提到测试分层和 CI 集成(40%)
  • 强调环境一致性(20%)

0. 第 10 题进阶

第 10 题

请说明 Monorepo 迁移前应做哪些评估,以及为什么建议渐进式迁移。

参考答案:

迁移前评估:

  • 当前项目之间的依赖关系;
  • 团队是否接受新的工作方式;
  • 现有工具链是否支持 Monorepo;
  • 迁移成本与收益。

渐进式迁移原因:

  • 一次性迁移风险高,容易破坏现有构建和发布流程;
  • 可以先用最相关、最依赖公共代码的几个项目试点;
  • 便于逐步建立治理规范和工具链;
  • 降低团队学习成本和业务中断风险。

评分维度

  • 能说出至少 3 个评估维度(40%)
  • 说明渐进式迁移的优势(40%)
  • 强调风险和成本(20%)

0. 第 11 题进阶

第 11 题

TypeScript Project References 在 Monorepo 中有什么作用?

参考答案:

TypeScript Project References 用于在 Monorepo 中建立包之间的编译依赖关系。

作用:

  • 明确包的编译依赖顺序;
  • 支持增量编译,只检查变化的文件;
  • 避免每个子包独立全量类型检查,提高性能;
  • 保证 Monorepo 内类型一致性。

启用方式:

  • 被引用包设置 compilerOptions.composite: true
  • 引用包通过 references 声明依赖。

评分维度

  • 能解释 Project References 作用(40%)
  • 提到增量编译和类型一致性(30%)
  • 能说出 compositereferences 配置(30%)

0. 第 12 题进阶

第 12 题

Monorepo 中如何治理代码共享,避免循环依赖?

参考答案:

代码共享正确姿势:

  • 把公共逻辑拆成独立的子包,如 packages/utilspackages/ui
  • 明确包的职责边界,一个包只做一件事;
  • 使用 workspace 协议引用内部包;
  • 使用 TypeScript Project References 管理编译依赖。

避免循环依赖:

  • 定期审查依赖关系图;
  • 出现循环依赖时,把公共部分抽成第三个包;
  • 使用依赖注入或事件机制解耦;
  • 借助工具(如 Madge)检测循环依赖。

评分维度

  • 能说明公共包拆分和职责边界(40%)
  • 能给出循环依赖解决方案(40%)
  • 提到工具检测和 workspace 协议(20%)

0. 第 13 题进阶

第 13 题

请描述 Monorepo 中的 CI/CD 最佳实践。

参考答案:

  1. 只构建受影响项目:使用 Affected Commands 减少 CI 时间。
  2. 缓存依赖和构建产物:利用 Turborepo/Nx 的远程缓存。
  3. 统一代码规范:根目录配置 ESLint、Prettier,CI 中自动检查。
  4. 自动化版本发布:使用 Changesets 管理版本和 changelog。
  5. 分支保护和 CODEOWNERS:设置 main 分支保护和目录负责人。
  6. 并行测试:单元测试、集成测试、E2E 测试并行执行。

评分维度

  • 能说出至少 4 条最佳实践(60%)
  • 能结合 Monorepo 特点说明原因(40%)

0. 第 14 题进阶

第 14 题

什么是固定版本(Fixed)和独立版本(Independent)?

参考答案:

  • 固定版本(Fixed/Locked):所有子包统一版本号。每次发布时,所有包的版本一起升级。例如 Babel 的 7.x.x

    • 优点:版本管理简单,发布节奏统一。
    • 缺点:即使某个包没有变更,也要跟着升级版本。
  • 独立版本(Independent):每个子包单独发版,根据各自的变更决定版本号。例如 Lerna 的 independent 模式。

    • 优点:各包独立演进,版本语义清晰。
    • 缺点:版本管理复杂,需要工具(如 Changesets)辅助。

评分维度

  • 能解释固定版本和独立版本(50%)
  • 能分别说明优缺点(40%)
  • 能举例说明(10%)

三、高级题

0. 第 15 题深入

第 15 题

请设计一个中大型 Monorepo 的完整技术方案,包括依赖管理、任务调度、版本发布、测试和 CI/CD。

参考答案:

  1. 依赖管理

    • 使用 pnpm workspace;
    • 通用开发依赖放根目录,运行时依赖放子包;
    • 使用 workspace:* 引用内部包;
    • 统一常用依赖版本,避免版本碎片化。
  2. 任务调度

    • 使用 Turborepo 配置 pipeline;
    • 定义 build/test/lint 任务依赖;
    • 启用本地和远程构建缓存。
  3. 版本发布

    • 使用 Changesets 管理变更;
    • 结合 GitHub Actions 自动生成 Release PR;
    • 自动 bump 版本、生成 changelog、发布到 npm。
  4. 测试

    • 根目录统一配置 Vitest;
    • 单元测试、集成测试、E2E 测试分层;
    • CI 中只运行 affected 测试。
  5. CI/CD

    • PR 时运行 lint、type-check、test、build;
    • 合并到 main 后触发发布流程;
    • 使用 CODEOWNERS 和分支保护保证代码质量。

评分维度

  • 五个方面均有涉及(60%)
  • 每个方面给出具体工具或命令(30%)
  • 方案整体连贯、可落地(10%)

0. 第 16 题深入

第 16 题

如何排查 Monorepo 中某个子包构建失败的问题?

参考答案:

排查步骤:

  1. 查看错误日志:定位具体报错信息和失败任务。
  2. 检查依赖关系:确认该子包依赖的其他包是否已正确构建。
  3. 单独构建:进入该子包目录单独运行 build,排除其他子包干扰。
  4. 检查版本冲突:确认是否存在多个子包依赖同一库的不同版本。
  5. 检查循环依赖:使用工具检测是否存在 A→B→A 的循环依赖。
  6. 清理缓存:清理 node_modules/.cache、Turborepo 缓存等,排除缓存污染。
  7. 审查最近变更:查看 git diff,确认是否有破坏性的配置或代码变更。

评分维度

  • 能给出系统化的排查步骤(60%)
  • 提到依赖、缓存、循环依赖等关键点(30%)
  • 强调日志分析和单独构建(10%)

0. 第 17 题深入

第 17 题

Monorepo 中根目录统一依赖版本有哪些好处?可能带来什么风险?

参考答案:

好处:

  • 避免不同子包依赖同一库的不同版本,减少运行时冲突;
  • 减少打包冗余,避免同一依赖被多次打包;
  • 统一升级,降低维护成本;
  • 保持技术栈一致性。

风险:

  • 某些子包可能需要特定版本,统一版本会导致兼容性问题;
  • 升级时需要全量验证所有子包;
  • 过度统一可能降低子包的灵活性。

平衡做法:

  • 对核心依赖(如 React、TypeScript)统一版本;
  • 对特殊依赖允许子包单独声明。

评分维度

  • 能说出至少 3 个好处(40%)
  • 能说出至少 2 个风险(30%)
  • 提出平衡策略(30%)

0. 第 18 题深入

第 18 题

请解释远程缓存(Remote Caching)在 Monorepo 中的价值,以及可能的安全风险。

参考答案:

价值:

  • 团队成员可以共享构建结果,避免重复构建;
  • CI 中可以直接复用缓存,大幅缩短流水线时间;
  • 大型 Monorepo 中效果尤为明显。

安全风险:

  • 缓存被篡改可能导致构建产物不一致;
  • 敏感信息可能意外被打包进缓存;
  • 需要控制缓存读写权限,防止未授权访问。

应对措施:

  • 使用可信的远程缓存服务;
  • 对缓存进行签名和校验;
  • 限制缓存访问权限;
  • 避免在缓存中包含密钥等敏感信息。

评分维度

  • 能说明远程缓存价值(40%)
  • 能指出缓存篡改、敏感信息泄露等风险(30%)
  • 能给出应对措施(30%)

0. 第 19 题深入

第 19 题

在 Monorepo 中,如何处理一个公共 API 的破坏性变更?

参考答案:

处理流程:

  1. 评估影响范围:通过依赖图找出所有使用该 API 的子包。
  2. 制定迁移计划
    • 如果影响大,考虑先新增 API,保留旧 API 作为兼容层;
    • 逐步推动各子包迁移。
  3. 原子化提交:在一次提交中同时修改公共包和所有依赖子包,保证仓库始终处于可构建状态。
  4. Changeset 标记:用 major 标记该公共包的破坏性变更。
  5. 文档和沟通:更新 README 和迁移文档,通知相关团队。
  6. 分阶段发布:必要时通过预发布版本验证。

评分维度

  • 能评估影响并制定迁移计划(40%)
  • 提到原子化提交和兼容层(30%)
  • 说明 Changeset 标记和文档沟通(30%)

0. 第 20 题深入

第 20 题

请从工程化角度总结 Monorepo 成功的关键因素。

参考答案:

Monorepo 成功的关键因素:

  1. 清晰的包边界:每个子包职责单一,避免循环依赖。
  2. 统一的工具链:统一的构建、测试、lint、格式化配置。
  3. 自动化任务调度:使用 Turborepo/Nx 管理任务依赖和缓存。
  4. 规范的版本管理:使用 Changesets 管理版本和发布。
  5. 完善的 CI/CD:只构建受影响项目,保证主分支稳定。
  6. 良好的治理机制:CODEOWNERS、分支保护、定期审计。
  7. 团队共识:所有成员理解 Monorepo 的工作方式并遵守规范。

Monorepo 不是简单地把项目放到一个仓库,而是一套需要持续投入和治理的工程化体系。

评分维度

  • 能说出至少 5 个关键因素(60%)
  • 强调治理和团队共识(30%)
  • 总结 Monorepo 是系统工程而非简单合并(10%)

难度分布总结

难度题号数量
基础1-77
进阶8-147
高级15-206
合计20

领域编号:E02 包管理与 Monorepo
最后更新:2026-06-18

基于 MIT 协议发布