docs(core): typescript batch mode (#18657)

This commit is contained in:
Isaac Mann 2023-08-16 12:28:15 -04:00 committed by GitHub
parent baabbfda91
commit 88900403a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 349 additions and 129 deletions

View File

@ -2053,6 +2053,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"id": "enable-tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Environment Variables",
"path": "/recipes/tips-n-tricks/define-environment-variables",
@ -3101,6 +3109,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"id": "enable-tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Environment Variables",
"path": "/recipes/tips-n-tricks/define-environment-variables",
@ -3232,6 +3248,14 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Enable Typescript Batch Mode",
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"id": "enable-tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Define Environment Variables",
"path": "/recipes/tips-n-tricks/define-environment-variables",
@ -3711,9 +3735,34 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Nx Micro-Frontend Example",
"path": "/showcase/example-repos/mfe",
"id": "mfe",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{
"name": "Benchmarks",
"path": "/showcase/benchmarks",
"id": "benchmarks",
"isExternal": false,
"children": [
{
"name": "Typescript Batch Mode Compilation",
"path": "/showcase/benchmarks/tsc-batch-mode",
"id": "tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Large Repo and Caching",
"path": "/showcase/example-repos/caching",
"path": "/showcase/benchmarks/caching",
"id": "caching",
"isExternal": false,
"children": [],
@ -3721,19 +3770,11 @@
},
{
"name": "Large Repo and DTE",
"path": "/showcase/example-repos/dte",
"path": "/showcase/benchmarks/dte",
"id": "dte",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Nx Micro-Frontend Example",
"path": "/showcase/example-repos/mfe",
"id": "mfe",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
@ -3859,22 +3900,6 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Large Repo and Caching",
"path": "/showcase/example-repos/caching",
"id": "caching",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Large Repo and DTE",
"path": "/showcase/example-repos/dte",
"id": "dte",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Nx Micro-Frontend Example",
"path": "/showcase/example-repos/mfe",
@ -3998,9 +4023,31 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Nx Micro-Frontend Example",
"path": "/showcase/example-repos/mfe",
"id": "mfe",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Benchmarks",
"path": "/showcase/benchmarks",
"id": "benchmarks",
"isExternal": false,
"children": [
{
"name": "Typescript Batch Mode Compilation",
"path": "/showcase/benchmarks/tsc-batch-mode",
"id": "tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Large Repo and Caching",
"path": "/showcase/example-repos/caching",
"path": "/showcase/benchmarks/caching",
"id": "caching",
"isExternal": false,
"children": [],
@ -4008,16 +4055,35 @@
},
{
"name": "Large Repo and DTE",
"path": "/showcase/example-repos/dte",
"path": "/showcase/benchmarks/dte",
"id": "dte",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{
"name": "Typescript Batch Mode Compilation",
"path": "/showcase/benchmarks/tsc-batch-mode",
"id": "tsc-batch-mode",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Nx Micro-Frontend Example",
"path": "/showcase/example-repos/mfe",
"id": "mfe",
"name": "Large Repo and Caching",
"path": "/showcase/benchmarks/caching",
"id": "caching",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Large Repo and DTE",
"path": "/showcase/benchmarks/dte",
"id": "dte",
"isExternal": false,
"children": [],
"disableCollapsible": false

View File

@ -2559,6 +2559,16 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
{
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
"description": "",
"file": "shared/recipes/enable-tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"tags": []
},
{
"id": "define-environment-variables",
"name": "Define Environment Variables",
@ -3867,6 +3877,16 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
{
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
"description": "",
"file": "shared/recipes/enable-tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"tags": []
},
{
"id": "define-environment-variables",
"name": "Define Environment Variables",
@ -4032,6 +4052,16 @@
"path": "/recipes/tips-n-tricks/eslint",
"tags": []
},
"/recipes/tips-n-tricks/enable-tsc-batch-mode": {
"id": "enable-tsc-batch-mode",
"name": "Enable Typescript Batch Mode",
"description": "",
"file": "shared/recipes/enable-tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/recipes/tips-n-tricks/enable-tsc-batch-mode",
"tags": []
},
"/recipes/tips-n-tricks/define-environment-variables": {
"id": "define-environment-variables",
"name": "Define Environment Variables",
@ -4627,26 +4657,6 @@
"path": "/showcase/example-repos/serverless-fastify-planetscale",
"tags": ["database", "node", "serverless"]
},
{
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/caching",
"tags": []
},
{
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/dte",
"tags": []
},
{
"id": "mfe",
"name": "Nx Micro-Frontend Example",
@ -4661,6 +4671,47 @@
"isExternal": false,
"path": "/showcase/example-repos",
"tags": []
},
{
"id": "benchmarks",
"name": "Benchmarks",
"description": "Benchmarks showing how fast Nx is",
"file": "",
"itemList": [
{
"id": "tsc-batch-mode",
"name": "Typescript Batch Mode Compilation",
"description": "",
"file": "shared/examples/tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/tsc-batch-mode",
"tags": []
},
{
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/caching",
"tags": []
},
{
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/dte",
"tags": []
}
],
"isExternal": false,
"path": "/showcase/benchmarks",
"tags": []
}
],
"isExternal": false,
@ -4813,26 +4864,6 @@
"path": "/showcase/example-repos/serverless-fastify-planetscale",
"tags": ["database", "node", "serverless"]
},
{
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/caching",
"tags": []
},
{
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/dte",
"tags": []
},
{
"id": "mfe",
"name": "Nx Micro-Frontend Example",
@ -4988,26 +5019,6 @@
"path": "/showcase/example-repos/serverless-fastify-planetscale",
"tags": ["database", "node", "serverless"]
},
"/showcase/example-repos/caching": {
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/caching",
"tags": []
},
"/showcase/example-repos/dte": {
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/example-repos/dte",
"tags": []
},
"/showcase/example-repos/mfe": {
"id": "mfe",
"name": "Nx Micro-Frontend Example",
@ -5018,6 +5029,77 @@
"path": "/showcase/example-repos/mfe",
"tags": []
},
"/showcase/benchmarks": {
"id": "benchmarks",
"name": "Benchmarks",
"description": "Benchmarks showing how fast Nx is",
"file": "",
"itemList": [
{
"id": "tsc-batch-mode",
"name": "Typescript Batch Mode Compilation",
"description": "",
"file": "shared/examples/tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/tsc-batch-mode",
"tags": []
},
{
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/caching",
"tags": []
},
{
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/dte",
"tags": []
}
],
"isExternal": false,
"path": "/showcase/benchmarks",
"tags": []
},
"/showcase/benchmarks/tsc-batch-mode": {
"id": "tsc-batch-mode",
"name": "Typescript Batch Mode Compilation",
"description": "",
"file": "shared/examples/tsc-batch-mode",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/tsc-batch-mode",
"tags": []
},
"/showcase/benchmarks/caching": {
"id": "caching",
"name": "Large Repo and Caching",
"description": "",
"file": "shared/examples/caching",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/caching",
"tags": []
},
"/showcase/benchmarks/dte": {
"id": "dte",
"name": "Large Repo and DTE",
"description": "",
"file": "shared/examples/dte",
"itemList": [],
"isExternal": false,
"path": "/showcase/benchmarks/dte",
"tags": []
},
"/reference": {
"id": "reference",
"name": "Reference",

View File

@ -834,6 +834,11 @@
"id": "eslint",
"file": "shared/eslint"
},
{
"name": "Enable Typescript Batch Mode",
"id": "enable-tsc-batch-mode",
"file": "shared/recipes/enable-tsc-batch-mode"
},
{
"name": "Define Environment Variables",
"id": "define-environment-variables",
@ -1110,6 +1115,23 @@
"tags": ["database", "node", "serverless"],
"file": "shared/recipes/database/serverless-fastify-planetscale"
},
{
"name": "Nx Micro-Frontend Example",
"id": "mfe",
"file": "shared/examples/nx-examples"
}
]
},
{
"name": "Benchmarks",
"id": "benchmarks",
"description": "Benchmarks showing how fast Nx is",
"itemList": [
{
"name": "Typescript Batch Mode Compilation",
"id": "tsc-batch-mode",
"file": "shared/examples/tsc-batch-mode"
},
{
"name": "Large Repo and Caching",
"id": "caching",
@ -1119,11 +1141,6 @@
"name": "Large Repo and DTE",
"id": "dte",
"file": "shared/examples/dte"
},
{
"name": "Nx Micro-Frontend Example",
"id": "mfe",
"file": "shared/examples/nx-examples"
}
]
}

View File

@ -0,0 +1,33 @@
# TSC Batch Mode
![Side by side demo of normal tsc taking 1m48s and batch mode tsc taking 28s](/shared/images/benchmarks/ts-benchmark.gif)
This repo compares two modes of running the `@nx/js:tsc` executor: the regular one and the batch one. The batch implementation, apart from running multiple tasks in a single process, also creates the required [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html) on the fly to perform incremental builds.
{% github-repository url="https://github.com/nrwl/large-ts-monorepo" /%}
{% callout type="note" title="Potential speed improvement" %}
Depending on the use case, batch mode compilation is from 1.16 to 7.73 times faster. More details on the exact scenarios tested can be found in the [repository `README.md` file](https://github.com/nrwl/large-ts-monorepo).
{% /callout %}
## Why is the batch implementation faster?
The non-batch implementation runs each task in a separate process. Each process creates a new `ts.Program` instance and performs a full build. Creating a full `ts.Program` instance is an expensive operation. Creating processes and `ts.Program` comes with a lot of overhead. Thanks to the project graph, this is already improved by orchestrating tasks and running them in parallel. Still, there's only so much that can be run in parallel and the more deeply nested the dependencies are, the less parallelism we can achieve.
The batch implementation runs multiple tasks in a single process. This reduces the overhead of starting a new process for each task. It also creates the required [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html) (based on the project graph information) on the fly to perform [incremental builds](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript). This is what yields the main performance benefits over the non-batch implementation. In this mode, the TypeScript compiler doesn't create a full `ts.Program` per project. Instead, it acts more like a build orchestrator and runs only out-of-date projects in the correct order.
## Compatible with Nx caching and distributed task execution 🏎️
TSC has powerful capabilities for incremental builds. Nx has powerful capabilities for caching and task distribution. These features compose very nicely. First Nx will retreive whatever it can from its local and remote caches (which includes `.tsbuildinfo` files), and then TSC will compile the remaining libs using the cached `.tsbuildinfo` files. This results in the minimum amount of computation.
Note even though the batch implementation can compile hundreds of libraries in the same process, each compiled library will be cached separately by Nx, which greatly increase computation reuse and the percentage of cache hits.
## Performance and DX balance
In large monorepos, it can be challenging to maintain Project references required for TSC incremental builds. Developers need to manually keep those references up to date, which is error-prone and can lead to broken builds.
The `@nx/js:tsc` batch implementation addresses this by creating the required project references on the fly using the project graph information. Nx already knows how your projects relate, so no need to tell it again. This eliminates the need for developers to manually maintain the project references while still getting the performance benefits of incremental builds. Zero DX cost, huge perf benefits.
## See Also
- [Enable Typescript Batch Mode](/recipes/tips-n-tricks/enable-tsc-batch-mode)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 MiB

View File

@ -66,32 +66,6 @@ The downsides of incremental builds:
If you are only planning to use incremental builds to speed up your CI, then the watch mode concern is irrelevant, and the only thing you need to assess is whether the benefits of skipping the compilation outweigh the costs of initializing the TypeScript compiler several times.
## Using the @nx/js:tsc Batch Implementation
{% callout type="check" title="Available since Nx 16.6.0" %}
The `@nx/js:tsc` batch implementation was introduced in Nx **16.6.0**.
{% /callout %}
If you're using the `@nx/js:tsc` to build your projects, you can opt-in to use its batch implementation. The batch implementation uses the [TypeScript APIs for incremental builds](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript) and batches the execution of the tasks into a single process. This results in a much faster build time when compared to the default implementation (the bigger the task graph to run, the more the performance improvements).
{% callout type="warning" title="Experimental feature" %}
Executing tasks in batch mode is an experimental feature.
{% /callout %}
{% callout type="info" title="Requirements" %}
Building a project with the `@nx/js:tsc` executor in batch mode requires all dependent projects to be buildable and built using the `@nx/js:tsc` executor.
{% /callout %}
To run your builds using the batch implementation, set the `NX_BATCH_MODE` environment variable to `true`:
```shell
NX_BATCH_MODE=true nx build my-project
```
For optimal performance, you could set the `clean` option to `false`. Otherwise, the executor cleans the output folder before running the build, which results in the loss of the [`.tsbuildinfo` file](https://www.typescriptlang.org/tsconfig/#tsBuildInfoFile) and, consequently, the loss of important optimizations performed by TypeScript. This is not a requirement. Even if the `clean` option is not set to `false` there are other important optimizations that are performed by the batch implementation.
You can get a sense of the performance improvements over using the `@nx/js:tsc` default implementation in the following example repository: https://github.com/nrwl/large-ts-monorepo.
## Custom Serve Target with Webpack
If you are implementing a custom serve command, you can use `WebpackNxBuildCoordinationPlugin` provided by `@nx/webpack`. It's a webpack plugin you can use to coordinate the compiling of the libs and the webpack linking.
@ -105,3 +79,8 @@ But there are other ways to make the build process incremental. One of them is u
When using WebPack Module Federation, you split the application into multiple webpack builds. Imagine the application has 3 big sections, and they are built using 3 webpack builds: `W1`, `W2`, and `W3`. Each of them has to build shared code in addition to building the corresponding application section code. So the time it takes to build all of them (`W1` + `W2` + `W3`) will be greater than `W`. However, if you change only Section 1, you will only need to run `W1`. `W2` and `W3` will be retrieved from cache. In addition, `W1`, `W2`, and `W3` can run on separate machines. Because of that, both the CI time and the local serve time can be drastically reduced.
Learn more: [Faster Builds with Module Federation](/concepts/more-concepts/faster-builds-with-module-federation)
## See Also
- [Enable Typescript Batch Mode](/recipes/tips-n-tricks/enable-tsc-batch-mode)
- [Typescript Batch Mode Benchmark](/showcase/benchmarks/tsc-batch-mode)

View File

@ -0,0 +1,40 @@
# Enable Typescript Batch Mode
{% callout type="check" title="Available since Nx 16.6.0" %}
The `@nx/js:tsc` batch implementation was introduced in Nx **16.6.0**.
{% /callout %}
If you're using the `@nx/js:tsc` to build your projects, you can opt-in to use its batch implementation. The batch implementation uses the [TypeScript APIs for incremental builds](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript) and batches the execution of the tasks into a single process. This results in a much faster build time when compared to the default implementation (the bigger the task graph to run, the more the performance improvements).
{% callout type="warning" title="Experimental feature" %}
Executing tasks in batch mode is an experimental feature.
{% /callout %}
{% callout type="info" title="Requirements" %}
Building a project with the `@nx/js:tsc` executor in batch mode requires all dependent projects to be buildable and built using the `@nx/js:tsc` executor.
{% /callout %}
To run your builds using the batch implementation, set the `NX_BATCH_MODE` environment variable to `true`:
```shell
NX_BATCH_MODE=true nx build my-project
```
For optimal performance, you could set the `clean` option to `false`. Otherwise, the executor cleans the output folder before running the build, which results in the loss of the [`.tsbuildinfo` file](https://www.typescriptlang.org/tsconfig/#tsBuildInfoFile) and, consequently, the loss of important optimizations performed by TypeScript. This is not a requirement. Even if the `clean` option is not set to `false` there are other important optimizations that are performed by the batch implementation.
```json {% fileName="libs/ts-lib/project.json" %}
{
"build": {
"executor": "@nx/js:tsc",
"options": {
"outputPath": "dist/libs/ts-lib",
"main": "libs/ts-lib/src/index.ts",
"tsConfig": "libs/ts-lib/tsconfig.lib.json",
"assets": ["libs/ts-lib/*.md"],
"clean": false
}
}
}
```
You can get a sense of the performance improvements over using the `@nx/js:tsc` default implementation in the [tsc batch mode benchmark](/showcase/benchmarks/tsc-batch-mode).

View File

@ -144,6 +144,7 @@
- [Add a Package-based Project in an Integrated Repo](/recipes/tips-n-tricks/package-based-in-integrated)
- [Add an Integrated Project in a Package-based Repo](/recipes/tips-n-tricks/integrated-in-package-based)
- [Configuring ESLint with Typescript](/recipes/tips-n-tricks/eslint)
- [Enable Typescript Batch Mode](/recipes/tips-n-tricks/enable-tsc-batch-mode)
- [Define Environment Variables](/recipes/tips-n-tricks/define-environment-variables)
- [Configuring Browser Support](/recipes/tips-n-tricks/browser-support)
- [Include Assets in Build](/recipes/tips-n-tricks/include-assets-in-build)
@ -190,9 +191,11 @@
- [Using Redis with Fastify](/showcase/example-repos/redis-fastify)
- [Using Postgres with Fastify](/showcase/example-repos/postgres-fastify)
- [Using PlanetScale with Serverless Fastify](/showcase/example-repos/serverless-fastify-planetscale)
- [Large Repo and Caching](/showcase/example-repos/caching)
- [Large Repo and DTE](/showcase/example-repos/dte)
- [Nx Micro-Frontend Example](/showcase/example-repos/mfe)
- [Benchmarks](/showcase/benchmarks)
- [Typescript Batch Mode Compilation](/showcase/benchmarks/tsc-batch-mode)
- [Large Repo and Caching](/showcase/benchmarks/caching)
- [Large Repo and DTE](/showcase/benchmarks/dte)
- [Reference](/reference)
- [Nx Configuration](/reference/nx-json)
- [Project Configuration](/reference/project-configuration)