Reputation: 7039
I have the following directory structure:
.
├── tsconfig.json ("module": "CommonJS")
└── foo/
├── node-file.ts
└── bar/
├── browser-file.ts
└── tsconfig.json ("module": "esnext")
The root tsconfig.json
has module
set to CommonJS
because I want most of my files to compile for Node. But inside bar
, I want the files to compile to JavaScript Modules, so I've set module
to esnext
.
Now when I run tsc
from the root, I expect node-file.ts
to compile to CommonJS
module and browser-file.ts
to compile to a JavaScript Module. But that's not what I'm getting. It seems that tsc
is completely ignoring foo/bar/tsconfig.json
and is only picking up the root tsconfig.json
.
(I also use tsc --watch
while developing, so I'm trying to avoid having to run two different tsc
processes to compile the two different targets. It feels to me that running a single tsc
with nested tsconfig.json
files should give me the desired results.)
Anyone know what it is that I'm doing wrong?
Upvotes: 22
Views: 21449
Reputation: 14148
TypeScript only uses one tsconfig.json
and doesn’t automatically use subdirectories’ tsconfig.json
for the files there. However, you can use project references for this.
Create a directory structure like this:
.
├── tsconfig.json
├── tsconfig.settings.json (optional)
└── foo/
├── node-file.ts
├── tsconfig.json ("module": "commonjs")
└── bar/
├── browser-file.ts
└── tsconfig.json ("module": "esnext")
tsconfig.json
{
"files": [],
"references": [
{"path": "./foo"},
{"path": "./foo/bar"}
]
}
This is the root tsconfig.json
. When you run tsc --build
(see below) in the root directory, TypeScript will build the referenced projects ./foo/tsconfig.json
and ./foo/bar/tsconfig.json
.
The "files": []
is to stop accidental tsc
s without --build
from attempting to compile everything in the root directory, which will error but create multiple .js
files in possibly the incorrect places.
tsconfig.settings.json
(optional)
{
"compilerOptions": {
"strict": true,
"noImplicitReturns": true
}
}
You can put configuration common to foo
and foo/bar
and extend this configuration with extends
to reduce duplication. Note that all relative paths in here will be resolved relative to tsconfig.settings.json
when extended, so something like "outDir": "dist"
may not work as expected.
foo/tsconfig.json
{
"extends": "../tsconfig.settings.json",
"exclude": ["bar/**/*.ts"],
"compilerOptions": {
"module": "commonjs"
}
}
This is the configuration for the CommonJS files. It also extends the common config and excludes the files in foo/bar
.
foo/bar/tsconfig.json
{
"extends": "../../tsconfig.settings.json",
"compilerOptions": {
"module": "esnext"
}
}
This is pretty similar to foo
’s configuration.
To compile foo
and foo/bar
at the same time, use build mode from the root directory:
tsc --build # or tsc -b
# Watch mode:
tsc --build --watch # or tsc -bw
From the handbook:
A long-awaited feature is smart incremental builds for TypeScript projects. In 3.0 you can use the
--build
flag withtsc
. This is effectively a new entry point fortsc
that behaves more like a build orchestrator than a simple compiler.Running
tsc --build
(tsc -b
for short) will do the following:
- Find all referenced projects
- Detect if they are up-to-date
- Build out-of-date projects in the correct order
You can provide
tsc -b
with multiple config file paths (e.g.tsc -b src test
). Just liketsc -p
, specifying the config file name itself is unnecessary if it’s namedtsconfig.json
.
You can also compile individual projects:
tsc -b foo # or cd foo && tsc -b
tsc -b foo/bar # or cd foo/bar && tsc -b
Note that are some build-only flags and you cannot override compiler options with command-line arguments.
Upvotes: 30