管理依赖项
- 外部依赖项来自npm 注册表,使你能够利用生态系统中的有价值代码,更快地构建应用程序和库。
内部依赖项让你在仓库内共享功能,极大地提高了共享代码的可发现性和可用性。我们将在下一个指南中讨论如何构建内部包。
依赖项安装的最佳实践
在使用依赖项的地方安装它们
在仓库中安装依赖项时,应该直接在使用它的包中安装。包的 package.json
将包含该包需要的每个依赖项。这对外部和内部依赖项都适用。
Good to know:
请注意,你的包管理器可能会选择 使用与包不同的 node_modules 位置。
要在多个包中快速安装依赖项,可以使用你的包管理器:
这种做法有几个好处:
- 提高清晰度:当依赖项列在包的
package.json
中时,更容易理解包依赖于什么。在仓库中工作的开发人员可以一目了然地看到包内使用了哪些依赖项。 - 增强灵活性:在大规模的单体仓库中,期望每个包使用相同版本的外部依赖项可能是不现实的。当有许多团队在同一代码库中工作时,由于大规模运营的现实,会有不同的优先级、时间表和需求。通过在使用它们的包中安装依赖项,你可以让你的
ui
团队更新到最新版本的 TypeScript,而你的web
团队可以优先考虑发布新功能并稍后更新 TypeScript。此外,如果你仍然想保持依赖项版本同步,你也可以这样做。 - 更好的缓存能力:如果你在仓库根目录安装了太多依赖项,每当你添加、更新或删除依赖项时,你都会更改工作区根目录,导致不必要的缓存未命中。
- 修剪未使用的依赖项:对于 Docker 用户,Turborepo 的修剪功能可以从 Docker 映像中删除未使用的依赖项,创建更轻量级的映像。当依赖项安装在它们适用的包中时,Turborepo 可以读取你的锁定文件并删除在你需要的包中未使用的依赖项。
根目录中的依赖项很少
遵循上面的第一个原则在使用依赖项的地方安装它们,你会发现自然而然地在工作区根目录中只有很少的依赖项。
工作区根目录中应该只有用于管理仓库的工具,而构建应用程序和库的依赖项则安装在各自的包中。在根目录安装的依赖项的一些例子有 turbo
、husky
或 lint-staged
。
管理依赖项
Turborepo 不管理依赖项
请注意,Turborepo 不参与管理你的依赖项,而是将这项工作交给你选择的包管理器。
由包管理器处理下载正确的外部依赖项版本、符号链接和解析模块等事务。本页上的建议是在工作区中管理依赖项的最佳实践,而不是由 Turborepo 强制执行的。
包管理器之间的模块解析有所不同
包管理器有不同的模块解析算法,这导致行为上的差异,可能难以预测。
在 Turborepo 文档中,我们根据包管理器的预期行为做出了许多建议。我们对如何处理依赖项的介绍是尽最大努力的,你可能需要根据你的包管理器或仓库的需求来调整文档中描述的行为。
然而,如果你发现文档中存在对所有包管理器或特定包管理器普遍不正确的问题,请通过 GitHub Issue 告诉我们,以便我们改进。
node_modules 位置
根据你选择的包管理器、版本、设置以及依赖项在工作区中的安装位置,你可能会在工作区内的各个位置看到 node_modules
及其中的依赖项。依赖项可能位于根 node_modules
、包的 node_modules
或两者中。
只要你的脚本和任务能够找到它们需要的依赖项,你的包管理器就工作正常。
在代码中引用 `node_modules`
工作区内 node_modules
的具体位置不是包管理器公共 API 的一部分。这意味着直接引用 node_modules
(如 node ./node_modules/a-package/dist/index.js
)可能很脆弱,因为磁盘上依赖项的位置可能随着工作区周围的其他依赖项变化而改变。
相反,尽可能依赖 Node.js 生态系统的约定来访问依赖模块。
保持依赖项使用相同版本
一些单体仓库维护者更喜欢按规则保持所有包中的依赖项使用相同版本。有几种方法可以实现这一点:
使用专门构建的工具
syncpack
、manypkg
和 sherif
等工具可用于此特定目的。
使用你的包管理器
你可以使用你的包管理器在一个命令中更新依赖项版本。
使用 IDE
你的 IDE 的重构工具可以一次性在仓库中的所有 package.json
文件中查找和替换依赖项的版本。尝试在 package.json
文件上使用类似 "next": ".*"
的正则表达式,找到 next
包的所有实例,并将它们替换为你想要的版本。完成后,确保运行包管理器的安装命令来更新你的锁定文件。
下一步
现在你已经知道如何在工作区中有效管理依赖项,让我们创建一个内部包作为单体仓库中的依赖项。