0%

typescript-how-tsconfig-works-in-framework

这篇文章讨论一下在 Angular/Nx 项目中 tsconfig.json 是如何工作的,本文使用的环境如下:

  • Node: 20.11.0(node -v)
  • NPM: 10.2.4(npm -v)
  • Angular CLI: 17.3.7(ng version)
  • Typescript: 5.4.2(in package.json —by project, or tsc -v —globally)
  • Nx: 15.2.1(nx --version)

1. 什么是 tsconfig.json

tsconfig.json 是 TypeScript 的配置文件,用于配置 TypeScript 编译器的行为。目前很多框架都使用Typescript,自然也就需要配置 tsconfig.json 文件。

2. Angular Single Project

Angular框架原生支持Typescript,所以在Angular项目中,使用Angular CLI创建Angular项目后,项目的文件结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
my-app/
├─ node_modules/
├─ src/
│ ├─ index.html
│ ├─ main.ts
│ ├─ ...
├─ angular.json
├─ package.json
├─ tsconfig.app.json
├─ tsconfig.json
├─ tsconfig.spec.json
├─ ...

与tsconfig相关的文件有如下三个:

  • tsconfig.json
  • tsconfig.app.json
  • tsconfig.spec.json

2.1 tsconfig.json

先看一下 tsconfig.json 文件,这是该项目总的配置文件,用来做一些通用配置,其他tsconfig文件可以继承这个文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./dist/out-tsc",
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"esModuleInterop": true,
"sourceMap": true,
"declaration": false,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": [
"ES2022",
"dom"
]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

2.2 tsconfig.app.json

tsconfig.app.json 文件是 Angular app的编译配置文件,由第一行"extends": "./tsconfig.json"可知,它继承了 tsconfig.json 文件的配置,同时也可以覆盖 tsconfig.json 文件的配置。

  • files:
  • include: "src/**/*.d.ts" 表示包含所有位于src目录下的Typescript类型定义文件(*.d.ts)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": [
"src/main.ts"
],
"include": [
"src/**/*.d.ts"
]
}

2.3 tsconfig.spec.json

tsconfig.spec.json 文件是 Angular app的测试配置文件,由第一行"extends": "./tsconfig.json"可知,它也继承了 tsconfig.json 文件。在include选项中,包含了所有的测试文件(.spec.ts)和类型定义文件(.d.ts)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/spec",
"types": [
"jasmine"
]
},
"include": [
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}

如果你尝试将src/**/*.spec.tsinclude选项中删除,再运行npm run test,将会遇到如下错误。

1
An unhandled exception occurred: error TS18003: No inputs were found in config file '.../my-app/tsconfig.spec.json'. Specified 'include' paths were '["src/**/*.d.ts"]' and 'exclude' paths were '["./out-tsc/spec"]'

由上面的分析可知,Angular项目中的 tsconfig.json 文件是一个全局配置文件,tsconfig.app.json掌管app的编译选项,tsconfig.spec.json负责测试文件的配置,这两者分别继承了 tsconfig.json 文件,同时可以做一些个性化的配置。

那么tsconfig.app.jsontsconfig.spec.json文件是如何被使用的呢?这就需要分析另一个文件:angular.json

2.4 angular.json

可以看到在projects | my-app | architect | build | options中,有一个tsConfig选项,这个选项指定了tsconfig.app.json文件的路径,这就是告诉Angular CLI在编译app时要使用tsconfig.app.json文件。

同时,在projects | my-app | architect | test | options中,有一个tsConfig选项,这个选项指定了tsconfig.spec.json文件的路径,这就是告诉Angular CLI在编译测试文件时要使用tsconfig.spec.json文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-app": {
"projectType": "application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
"tsConfig": "tsconfig.app.json", // 1 <-- here
//...
}
},
// ...
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"polyfills": [
"zone.js",
"zone.js/testing"
],
"tsConfig": "tsconfig.spec.json", // 2 <-- here
// ...
}

总结一下:

  • tsconfig.json 是全局配置文件
  • tsconfig.app.json 是app的编译配置文件,继承了tsconfig.json文件。
  • tsconfig.spec.json 是测试文件的配置文件,继承了tsconfig.json文件。
  • angular.json 文件中的tsConfig选项指定了tsconfig.app.jsontsconfig.spec.json文件的路径

上图:
angular-single-project-tsconfig

3. Angular Multi Project

关于如何创建Angular多项目应用,可以参考这篇

多项目应用的文件结构如下,projects目录负责存放所有的子项目,这里有两个子项目:mfe1和shell。
每个子项目分别有自己的tsconfig.app.jsontsconfig.spec.json文件,这两个文件分别继承了全局的tsconfig.json文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my-app/
├─ node_modules/
├─ projects/
│ ├─ mfe1/
│ │ ├─ ...
│ │ ├─ tsconfig.app.json
│ │ ├─ tsconfig.spec.json
│ ├─ shell/
│ │ ├─ ...
│ │ ├─ tsconfig.app.json
│ │ ├─ tsconfig.spec.json
├─ ...
├─ angular.json
├─ package.json
├─ tsconfig.json

angular.json文件中的tsConfig选项指定了每个子项目的tsconfig.app.jsontsconfig.spec.json文件的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"shell": { // project shell <-- here
"projectType": "application",
// ...
"architect": {
"build": {
"builder": "ngx-build-plus:browser",
"options": {
// ...
"tsConfig": "projects/shell/tsconfig.app.json", // 1 <-- here
},
},
// ...
"test": {
// ...
"tsConfig": "projects/shell/tsconfig.spec.json", // 2 <-- here
}
}
},
"mfe1": { // project mfe1 <-- here
"projectType": "application",
// ...
"architect": {
"build": {
"builder": "ngx-build-plus:browser",
"options": {
// ...
"tsConfig": "projects/mfe1/tsconfig.app.json", // 3 <-- here
},
},
// ...
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
// ...
"tsConfig": "projects/mfe1/tsconfig.spec.json", // 4 <-- here
}
}
}
}
}
}

总结一下:
多项目Angular应用的tsconfig文件使用情况

  • tsconfig.json 是全局配置文件,位于workspace根目录下
  • 每个子项目有自己的tsconfig.app.jsontsconfig.spec.json文件,分别继承了全局的tsconfig.json文件
  • angular.json 文件中的tsConfig选项指定了每个子项目的tsconfig.app.jsontsconfig.spec.json文件的路径

上图:
angular-multiple-projects-tsconfig

4. Nx Mono Repo

使用Nx创建的Mono Repo项目,Nx会自动创建一个tsconfig.base.json文件,这个文件是全局的配置文件,所有的子项目都会继承这个文件。并且没有angular.json文件,每个子项目有自己的project.json文件,负责引用子项目中的tsconfig文件。

假设我们的mono repo包含一个app,名为todo, 一个library, 名为data-access,则文件结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Nx mono repo/
├─ apps/
│ ├─ todo/
│ │ ├─ ...
│ │ ├─ project.json
│ │ ├─ tsconfig.app.json
│ │ ├─ tsconfig.json
│ │ ├─ tsconfig.spec.json
├─ libs/
│ ├─ data-access/
│ │ ├─ ...
│ │ ├─ project.json
│ │ ├─ tsconfig.json
│ │ ├─ tsconfig.lib.json
│ │ ├─ tsconfig.spec.json
├─ node_modules/
├─ package.json
├─ tsconfig.base.json
├─ ...

总结一下:

  • tsconfig.base.json 是全局配置文件,位于workspace根目录下
  • app项目有自己的tsconfig.app.jsontsconfig.spec.json文件以及tsconfig.json,继承关系如下:
    • tsconfig.app.json继承tsconfig.json
    • tsconfig.spec.json继承tsconfig.json
    • tsconfig.json继承tsconfig.base.json
  • library项目有自己的tsconfig.lib.jsontsconfig.spec.json文件以及tsconfig.json,继承关系如下:
    • tsconfig.lib.json继承tsconfig.json
    • tsconfig.spec.json继承tsconfig.json
    • tsconfig.json继承tsconfig.base.json
  • 每个子项目的project.json文件负责引用子项目中的tsconfig文件

一图胜千言
nx-mono-repo-tsconfig