Monorepo with `rootDirs` produces unwanted sudirectories such as `src` in `outDir`

耗尽温柔 提交于 2020-05-16 13:58:31

问题


I am planning a monorepo typescript porject like below:

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

tsconfig.json is defined like below:

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

When I execute tsc under backend it gives me like below:

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

In the above, dist contains backend and shared BUT each of them contains src under it. I wanted backend and shared under dist contain compiled JS files without src:

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

Is it possible ? And how can I make it ?


回答1:


diagnosis

  • Typescript relies on rootDir (not rootDirs) to decide the directory structure of the output (see this comment from Typescript's bossman).
  • When you set multiple rootDirs, tsc will find the parent directory that is common to all of them and treat that a the rootDir. This is why you're getting the outDir structure that you're getting.


prescription: Structure your monorepo as separate Typescript sub-projects

A Typescript project is defined by a tsconfig file, is self-contained, and is effectively bounded by its rootDir. This is a very good thing, as it lines up with principles of encapsulation.

You can have multiple a projects (e.g. a main and a set of libs) each in their own directory with their own tsconfig, with their own rootDir. Dependencies between them are managed in the tsconfig files using Typescript Project References.

It's unfortunate that the Typescript folks chose the term "projects", as intuitively it refers to the whole shebang, but "modules" and "packages" was already taken. But if you think of them as subprojects and it will make a lot more sense.

But I recommend you structure your repo like so:

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

So that when you compile your code you get:

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

Example tsconfigs

  • src/tsconfig.json

    Even if you have no code at the root, this tsconfig can be where all the common settings go (the others will inherit from it), and it will enable a simple tsc --build src to build the whole project (and with --force to build it from scratch).

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

      shared won't import any of the other projects as it has no references. All it imports are limited to within its directory and dependencies listed in package.json. You could even restrict the the latter, I believe, by giving it its own package.json.

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

      backend can import shared because of the declared reference.

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

      frontend can import shared AND frontend because of the declared references.

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

Example build commands

tsc --build src will build the entire src tree

tsc --build src/backend will build the the backend AND shared (if there have been changes since the last build.



来源:https://stackoverflow.com/questions/60896829/monorepo-with-rootdirs-produces-unwanted-sudirectories-such-as-src-in-outdi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!