javascript monorepo 的正确方法是什么

What is a correct approach to a javascript monorepo

我正在尝试找出 javascript monorepo 的正确方法。想象一下包含包/库的 monorepo:

root
  - node_modules
  - packages
      + lib-a
          * node_modules
      + lib-b
          * node_modules

现在假设 lib-alib-b 包都使用 webpack 作为它们的构建工具。

我看到两种方法

  1. 添加 wepback 作为对 root 的依赖。在两个包中包含 "build" 脚本:"build": "webpack -p --config webpack.config.jswebpack.config.js 可以包含根 webpack.config.js。然后我可以使用 lerna 之类的工具从根目录 运行 构建(这意味着 webpack 二进制文件被识别。但是我将无法 运行 在特定包中构建因为 webpack 在那里不可用。我可能会将构建脚本更改为 "build": "../../node_modules/.bin/webpack -p --config webpack.config.js

  2. 始终在每个包中包含 webpack。这意味着 build 脚本将会成功。这也意味着每个包都将具有相同的依赖关系,我应该注意每个包都使用相同的 webpack 版本。

基本上我的意思是应该如何构造 monorepo 中的包?如果发布了任何包,是否总是可以单独 build 该包。

我们现在的配置和你一样:

root
  - node_modules
  - packages
      + lib-a
          * node_modules
      + lib-b
          * node_modules

我们使用lerna来处理我们的项目:https://github.com/lerna/lerna

您只需要在 lerna.json

中指定您的包文件夹
{
  "lerna": "3.16.4",
  "packages": ["packages/*"],
  "version": "0.0.0",
  "npmClient": "yarn",
  "useWorkspaces": true
}

然后在您的 package.json 脚本中,您可以使用以下行:

"build": "lerna run build",

这基本上 运行 所有包中的构建。因此,只要每个包中的构建脚本具有正确的参数和安装的 webpack,它就会自动 运行 webpack 构建。

之后您就可以简单地处理您指定的包中的工作了。

您的方法 #2 是正确的。您单独处理每个包裹,因为它是一个单独的、独立的包裹。

monorepo 的优势不在于通过目录结构共享文件,而在于:

  1. 将所有依赖项引导至具有扁平结构的单个 node_modules,有效地消除重复项。
  2. 通过常规包 import/require() 使您的包对其他包可用,因为它们是外部依赖项。而且,由于指向 node_modules 的符号链接,您的 "dependency" 包始终包含最新内容而无需发布。
  3. 在所有包中强制执行一致的、始终最新的依赖结构。正如你所说 "This also means that each package will have the same dependency".
  4. 使用单个命令对所有包执行不同维护任务(如构建、发布)的自动化工具。

我知道一开始并不容易,但是当你深入研究 Lerna 文档时,它会变得更加清晰。除了 Lerna main page I recommend reading about hoisting, FAQ and individual commands like bootstrap and publish.