Sunday面试指南

Monorepo 是什么?pnpm workspace 如何管理多个项目和公共依赖?

下面是一段教学用的模拟面试。

🧑‍💻 面试官:把三个项目文件夹放进同一个 Git 仓库,就算 Monorepo 了吗?

🙋‍♂️ 我:仓库层面可以这样组织,但还需要管理各项目的依赖、测试和发布关系。

🧑‍💻 面试官:公共组件包和业务应用都在本地,应用一定会用本地这份组件吗?

🙋‍♂️ 我:要看依赖声明与工具配置,workspace 协议可以明确要求本地包。

🧑‍💻 面试官:组件改了,哪些应用要重新构建?所有项目必须一起发布吗?依赖形成环又怎么办?

一个仓库存了哪些项目是一回事;谁依赖谁、谁受改动影响、怎样发布,是另外三件事。

面试速答(60 秒版)

Monorepo 是在一个代码仓库中管理多个项目或包的方式。它方便跨项目修改和共享代码,但不会自动解决版本、权限、构建和发布问题。

pnpm workspace 用工作区配置把这些包组织起来,每个包仍通过自己的 package.json 声明依赖。内部依赖可以使用 workspace 协议,明确要求解析到工作区里的包,避免意外使用注册表版本。

构建时,要根据依赖关系确定顺序,并检查公共包变化会影响哪些应用。工作区依赖、构建任务和发布版本,并不等于同一张关系表。

因此我更关心包边界、依赖声明、循环、CI 验证和发布策略。项目适合协同演进时,Monorepo 有帮助;彼此独立、权限要求很不同,也不必仅为了统一目录而合并。

Monorepo中的包依赖构建与发布并非同一关系

知识点详解:共享代码以后,怎样知道谁受影响?

先搭一个最小工作区

假设咱们维护网站 web、管理后台 admin,以及它们共享的组件包 ui。

repo/
  apps/web/
  apps/admin/
  packages/ui/
  pnpm-workspace.yaml

根目录的工作区配置可以写成:

packages:
  - 'apps/*'
  - 'packages/*'

每个项目仍然有自己的 package.json。目录只是发现包的入口,真实包名、脚本和依赖,来自包自身的声明。

这个例子展示 pnpm 的配置,不是 Python 包管理接口。仓库也可以包含 Python 服务,但它仍需要自己的 Python 依赖与构建配置,不能把 pnpm 安装当成通用语言管理器。

workspace 协议,为什么比“本地有这个包”明确?

假设共享包名为 @demo/ui。应用可以声明:

{
  "dependencies": {
    "@demo/ui": "workspace:*"
  }
}

workspace 协议要求使用对应工作区包。普通版本范围是否链接本地,还受版本和配置影响;没有满足条件的本地包时,可能走注册表解析。

因此,公共包明明在仓库里,不代表任何同名依赖都会自动使用它。发布或打包时,workspace 依赖还需要转换成对外可使用的版本约定,具体行为见 pnpm 工作区文档。

使用了源码,还是使用构建产物?

工作区关联只让包能够按依赖关系被找到。最终加载什么,仍由包的入口、exports、类型声明和业务构建配置决定。

如果 ui 暴露的是 dist 里的文件,应用运行前就需要确保 ui 已经正确构建。链接到本地目录,并不会自动生成 dist。

开发时直接消费源码也是一种选择,但要确认转译、样式和依赖都由谁处理。不要开发环境读源码、发布环境读旧产物,却没有验证二者的一致性。

workspace链接不等于dist存在发布包需要检查exports与构建

三张关系,为什么不能混在一起?

第一张是包依赖:web 和 admin 都依赖 ui。

第二张是任务依赖:构建 web 可能需要先生成 ui 产物,测试任务则可能有不同前置条件。

第三张是发布关系:ui 可以单独版本发布,两个应用也可以独立部署,或者团队选择统一版本。Monorepo 不强制它们永远一起发布。

改动影响分析需要结合这些关系与真实输入。根配置、构建工具、锁文件变化,可能影响很多项目;只按“哪个目录的文件变了”决定测试范围,会漏掉问题。

公共包为什么容易越来越大?

任何共享代码都塞进 ui 或 utils,短期省事,长期会让两个原本独立的应用互相牵制。

应该让包有清楚职责和公开入口。应用专属规则不要因为“以后可能复用”,就立刻放进公共层。跨包修改也应有测试与负责人,不等于谁都能随意改所有项目。

循环依赖尤其要检查。A 依赖 B、B 又依赖 A,会破坏清晰构建顺序,某些脚本无法保证拓扑执行。需要调整边界,而不是简单隐藏工具警告。

怎样验证工作区真的可发布?

从干净环境安装依赖,按任务顺序构建,再验证应用只通过声明的公开入口消费共享包。

如果共享包要对外分发,还要测试真实打包产物。仓库里能引用到某个文件,不代表包发布以后那个文件仍然存在。

缓存则要包含源码、依赖与构建配置等真实输入。缓存命中但输出属于旧配置,比构建慢一点更难排查。

面试官继续追问

Monorepo 必须统一技术栈吗?

不必须。同仓可以有不同语言和工具,但依赖、CI 与部署关系需要明确,不能指望一种包管理器代替所有工具。

所有依赖都提升到根目录,最方便吗?

根工具与包运行依赖需要区分。包应该声明自己真实使用的依赖,避免在仓库里碰巧能用,单独打包就失败。

它一定比多仓库好吗?

跨项目协作频繁时可能更方便;独立权限、生命周期和发布节奏很重要时,多仓也有合理性。拿具体维护压力比较,不按“规模大就要 Monorepo”判断。

面试速记卡

  • Monorepo 管同仓多项目,不强制统一语言与发布。
  • workspace 发现包,每个包仍声明自己的依赖。
  • workspace 协议明确要求使用工作区包。
  • 本地链接不等于构建产物已经生成。
  • 包依赖、任务依赖、发布关系分别梳理。
  • 干净构建与真实打包测试,验证仓库外也能使用。

公司面试真题

这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。

浏览公司面试真题 →
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历