首页 > 解决方案 > 带有 `rootDirs` 的 Monorepo 会在 `outDir` 中生成不需要的子目录,例如 `src`

问题描述

我正在计划一个 monorepo 打字稿项目,如下所示:

/ (root)
+--backend/
|  +-src/
|  \-tsconfig.json
+--shared/
|  \-src/
\--frontend/
   \-src/

tsconfig.json定义如下:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./dist",
    "strict": true,
    "baseUrl": "./src",
    "paths": {
      "shared": [
        "../../shared/src"
      ]
    },
    "rootDirs": [
      "./src",
      "../shared/src"
    ],
    "esModuleInterop": true
  }
}

当我tscbackend它下面执行时,我如下所示:

/ (root)
+-backend/
  +-dist/
  | +-backend/
  | | +-src/
  | \-shared/
  |   \-src/
  +-src/
  \-tsconfig.json

在上面,dist包含backendshared但它们中的每一个都包含src在它下面。我想要backendshareddist包含编译的 JS 文件时没有src

/ (root)
+-backend/
  +-dist/
  | +-backend/
  | \-shared/
  +-src/
  \-tsconfig.json

可能吗 ?我怎样才能做到?

标签: typescriptdependenciestsconfigmonorepo

解决方案


诊断

  • Typescript 依赖rootDir(not rootDirs) 来决定输出的目录结构(请参阅Typescript 的 bossman 的此评论)。
  • 当你设置多个rootDirs时,tsc会找到所有的共同的父目录,并将视为rootDir. 这就是为什么你得到你得到的outDir结构。

处方:将你的 monorepo 构建为单独的 Typescript 子项目

Typescript项目tsconfig文件定义,是自包含的,并且有效地受其rootDir. 这是一件非常好的事情,因为它符合封装的原则

您可以在自己的目录中拥有多个项目(例如一个主项目和一组库),每个项目都有自己的 tsconfig 和自己的rootDir. 它们之间的依赖关系在 tsconfig 文件中使用 Typescript Project References进行管理。

不幸的是,Typescript 的人选择了“项目”这个词,因为直观上它指的是整个 shebang,但是“模块”和“包”已经被使用了。但是,如果您将它们视为子项目,那将更有意义。

但我建议您像这样构建您的仓库:

.
├── dist
└── src
    ├── tsconfig.json
    ├── shared
    │   ├── index.ts
    │   └── tsconfig.json
    ├── backend
    │   ├── index.ts
    │   └── tsconfig.json
    └── frontend
        ├── index.ts
        └── tsconfig.json 

因此,当您编译代码时,您会得到:

.
├── dist
│   ├── shared
│   ├── backend
│   └── frontend
└── src

示例 tsconfig

  • src/tsconfig.json

    即使您在根目录下没有代码,此 tsconfig 也可以是所有常用设置所在的位置(其他设置将从它继承),并且可以轻松tsc --build src构建整个项目(并--force从头开始构建它)。

      {
        "compilerOptions": {
          "rootDir": ".",
          "outDir": "../dist/",
        },
        "files": [],
        "references": [
          { "path": "./shared" },
          { "path": "./backend" },
          { "path": "./frontend" }
        ]
      }
    
    • src/shared/tsconfig.json

      shared不会导入任何其他项目,因为它没有引用。它导入的所有内容都仅限于其目录和package.json. 我相信,你甚至可以通过赋予它自己的package.json.

        {
          "compilerOptions": {
            "rootDir": ".",
            "outDir": "../../dist/shared",
            "composite": true
          }
        }
      
    • src/backend/tsconfig.json

      由于声明的引用,后端可以导入共享。

        {
          "compilerOptions": {
            "rootDir": ".",
            "outDir": "../../dist/backend",
            "composite": true
          },
          "references": [
            { "path": "../shared" }
          ]
        }
      
    • src/frontend/tsconfig.json

      由于声明的引用,前端可以导入共享AND后端。

        {
          "compilerOptions": {
            "rootDir": ".",
            "outDir": "../../dist/frontend",
            "composite": true
          },
          "references": [
            { "path": "../shared" },
            { "path": "../backend" }
          ]
        }
      

示例构建命令

tsc --build src将构建整个 src 树

tsc --build src/backend将构建后端并共享(如果自上次构建以来发生了更改。


推荐阅读