重要提示:本文档涵盖 Yarn 1(经典版)。
有关 Yarn 2+ 文档和迁移指南,请参阅yarnpkgpkg.com。

借助 Focused Workspaces 轻松过渡到单一代码库

2018 年 5 月 18 日发布,作者 Bryan Wain

之前,我们曾撰写有关单一代码库以及 Yarn Workspaces 如何简化使用它们的文章。遗憾的是,转移到单一代码库并不总是很容易的选择。如果没有合适的工具,单一代码库通常会损害开发者体验,而不是帮助开发者。

单一代码库存在的问题

项目通常转移到单一代码库的主要原因之一是,它能让你在一个拉取请求中进行更改,从而更容易对多个软件包进行更改。Yarn Workspaces 改进此工作流的方法之一是,在 node_modules 文件夹中自动对相邻软件包依赖项创建符号链接,让你在处理其他软件包时能够立即看到对其中一个软件包的更改效果。

遗憾的是,虽然始终对相邻软件包创建符号链接可以简化跨软件包开发,但当你只想处理单个软件包时,它会带来很大的劣势。如果软件包 A 依赖于软件包 BC,你只需更改软件包 A 就需要构建所有三个软件包。在包含许多软件包的单一代码库中,与多代码库设置相比,这可能是一个非常缓慢的过程,因为你只需在安装时获取 BC 的预构建版本。

单一代码库和多代码库开发的这些相对优势通常会给开发者带来艰难的选择。使用单一代码库优化跨软件包开发,或者使用多个代码库优化单个软件包开发。我们认为你无需做出此项选择,而我们对 Focused Workspaces 的目标是帮助将 Yarn Workspaces 转变为一款能够让你充分享受单一代码库的全部优势,而不必放弃多个代码库优势的工具。

推出 Focused Workspaces

yarn install --focus1.7.0 中提供的一项新安装选项,可浅层安装 workspace 的相邻依赖项,将其装入其 node_modules 文件夹。浅层安装可以用一个示例最好解释。

假设你有一个包含软件包 AB 的单一代码库,A 依赖于 BB 依赖于 External,而后者不属于该单一代码库。正常安装可能产生这样的结果。

| my_project/
|      package.json
|      node_modules/
|          A/ (symlink to packages/A)
|          B/ (symlink to packages/B)
|          External/
|      packages/
|          A/
|              node_modules/ (empty)
|          B/
|              node_modules/ (empty)

此处的问题是,如果你想运行 A,你还需要构建 B。如果你尚未对 B 进行任何更改,这很可能比从注册表中安装 B 要慢。

如果你转到 packages/A 并运行 yarn install --focus,结果将如下所示

| my_project/
|      package.json
|      node_modules/
|          A/ (symlink to packages/A)
|          B/ (symlink to packages/B)
|          External/
|      packages/
|          A/
|              node_modules/
|                  B/ (not a symlink. Pulled from registry. No need to build.)
|          B/
|              node_modules/ (empty)

此设置让你无需重建 B 即可运行 A。由于 node 模块解析的工作方式,在构建 A 时,它会在 packages/A/node_modules/B 中找到 B,并避免使用根目录处的符号链接,该符号链接指向 B 的未构建版本。

使用 --focus 时,Yarn 始终会执行最小安装。请注意,External 不会在 A 下重新安装。这没有必要,因为当 A 尝试解析 External 时,它将已指向提升的版本。

处理版本冲突

让我们看一个稍微复杂的示例。现在想象 AB 都依赖于 External,但 A 依赖于 [email protected],而 B 依赖于 [email protected]。由于版本不兼容,AB 不再可以共享 External 的副本。

常规安装将生成此结构

| my_project/
|      package.json
|      node_modules/
|          A/ (symlink to packages/A)
|          B/ (symlink to packages/B)
|          External/ (v2)
|      packages/
|          A/
|              node_modules/
|                  External (v1)
|          B/
|              node_modules/ (empty)

而聚焦安装将生成此结构

| my_project/
|      package.json
|      node_modules/
|          A/ (symlink to packages/A)
|          B/ (symlink to packages/B)
|          External/ (v2)
|      packages/
|          A/
|              node_modules/
|                  External (v1)
|                  B/
|                      node_modules/
|                          External/ (v2)
|          B/
|              node_modules/ (empty)

Yarn 不仅需要在 A 下安装 B,还需要在 B 的嵌套副本下安装 External,以确保 B 使用 External 的 v2,而 A 仍然使用 v1。

取消聚焦

如果您想从聚焦安装中删除浅层安装,只需在不使用 --focus 的情况下重新运行 yarn install。所有 node_modules 将恢复到您聚焦之前它们所处的状态。`升级`、`添加` 和 `删除` 也将删除所有浅层安装。

您还可以聚焦另一个工作区,而原始工作区将取消聚焦。

默认聚焦

如果您希望工作区在安装时始终使用 --focus,则可以使用 CLI 参数 功能 .yarnrc 文件。

--install.focus true

如果您将它添加到 packages/A/.yarnrc,则从 A 运行安装时,您将始终执行聚焦安装,但不会从任何其他包或根目录执行聚焦安装。

如果您改为将其添加到 packages/.yarnrc,您将从 packages/ 下的所有包执行聚焦安装。

接下来呢?

我们希望聚焦工作区能够让您更轻松地迁移至单一存储库。这只是第一次迭代,未来可能会进行进一步的改进。如果您注意到了任何错误之处,或者有任何关于如何改进您对工作区的体验的建议,请告知我们。

参考

  • 原始提案:RFC
  • 实施公关:#5663