问题
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
(notrootDirs
) 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 therootDir
. This is why you're getting theoutDir
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 ownpackage.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