Leosvel Pérez Espinosa 5974851c24
fix(js): infer dependency between typecheck and build tasks and more granular outputs for typecheck (#30549)
## Current Behavior

There is no dependency between the inferred `typecheck` and `build`
tasks. Depending on their run order, this can result in duplicated
processing (type-checking, `.d.ts` generation). Given there's no
explicit dependency, the order would be non-deterministic.

Additionally, when `outDir` is set in the tsconfig files, it's used
as-is in the currently inferred outputs for `typecheck`. This can result
in extra files being cached for the task.

## Expected Behavior

For optimum performance, the inferred `typecheck` task should depend on
the `build` task. The `typecheck` task's outputs should be more granular
so that only the relevant files (declaration files and declaration map
files if enabled) are cached.

### Explanation

Consider a typical setup with specific tsconfig file for files with
different concerns:

- tsconfig.lib.json: TS configuration for the library runtime files
- tsconfig.spec.json: TS configuration for the unit test files
- tsconfig.json: TS solution configuration, a solution file that
references the specific config files above

When running `tsc -b tsconfig.lib.json --verbose` (build), we can see
how the `tsconfig.lib.json` TS project is built:

```bash
Projects in this build:
    * tsconfig.lib.json

Project 'tsconfig.lib.json' is out of date because output file 'dist/tsconfig.lib.tsbuildinfo' does not exist

Building project '<workspace root>/packages/pkg1/tsconfig.lib.json'...
```

After that, if we run `tsc -b tsconfig.json --emitDeclarationOnly
--verbose` (typecheck), we'll see how the `tsc` output for
`tsconfig.lib.json` is reused:

```bash
Projects in this build: 
    * tsconfig.lib.json
    * tsconfig.spec.json
    * tsconfig.json

Project 'tsconfig.lib.json' is up to date because newest input 'src/lib/file.ts' is older than output 'dist/tsconfig.lib.tsbuildinfo'

Project 'tsconfig.spec.json' is out of date because output file 'out-tsc/jest/tsconfig.spec.tsbuildinfo' does not exist

Building project '<workspace root>/packages/pkg1/tsconfig.spec.json'...
```

The relevant bit above is `Project 'tsconfig.lib.json' is up to date
because newest input 'src/lib/file.ts' is older than output
'dist/tsconfig.lib.tsbuildinfo'`. Because the initial `build` task
already typechecks and produces `.d.ts` files for the
`tsconfig.lib.json`, when the `typecheck` task runs, `tsc` identifies
that the outputs for that config files were already produced and can be
reused.

If we were to run the tasks in the inverse order, the results would be
different:

```bash
> npx tsc -b tsconfig.json --emitDeclarationOnly --verbose
Projects in this build: 
    * tsconfig.lib.json
    * tsconfig.spec.json
    * tsconfig.json

Project 'tsconfig.lib.json' is out of date because output file 'dist/tsconfig.lib.tsbuildinfo' does not exist

Building project '<workspace root>/packages/pkg1/tsconfig.lib.json'...

Project 'tsconfig.spec.json' is out of date because output file 'out-tsc/jest/tsconfig.spec.tsbuildinfo' does not exist

Building project '<workspace root>/packages/pkg1/tsconfig.spec.json'...

> npx tsc -b tsconfig.lib.json --verbose
Projects in this build: 
    * tsconfig.lib.json

Project 'tsconfig.lib.json' is out of date because buildinfo file 'dist/tsconfig.lib.tsbuildinfo' indicates there is change in compilerOptions

Building project '<workspace root>/packages/pkg1/tsconfig.lib.json'...
```

Note how when the `build` task is run, `tsc` identifies that there was a
change in `compilerOptions` (`--emitDeclarationOnly`) and it requires
building the project. This is because the `typecheck` task only
generates declaration files and the `build` task must also emit the
transpiled `.js` files.

### Benchmark

Running those two different flows in a simple (non-Nx) project with a TS
configuration structure like the one mentioned above and with 5000 TS
files split in half for runtime and test files yields the following:

```bash
hyperfine -r 5 -p "rm -rf dist out-tsc" \
-n "build => typecheck" "npx tsc -b tsconfig.lib.json && npx tsc -b --emitDeclarationOnly" \
-n "typecheck => build" "npx tsc -b tsconfig.json --emitDeclarationOnly && npx tsc -b tsconfig.lib.json"
Benchmark 1: build => typecheck
  Time (mean ± σ):      6.832 s ±  0.094 s    [User: 11.361 s, System: 1.060 s]
  Range (min … max):    6.734 s …  6.985 s    5 runs
 
Benchmark 2: typecheck => build
  Time (mean ± σ):      8.789 s ±  0.015 s    [User: 14.817 s, System: 1.267 s]
  Range (min … max):    8.771 s …  8.812 s    5 runs
 
Summary
  build => typecheck ran
    1.29 ± 0.02 times faster than typecheck => build
```

## Related Issue(s)

Fixes #
2025-03-31 19:05:52 +02:00
2019-03-07 13:23:11 -05:00

Nx - Smart Monorepos · Fast CI

CircleCI License NPM Version Semantic Release Commitizen friendly Join the chat at https://gitter.im/nrwl-nx/community Join the Official Nx Discord Server


Smart Monorepos · Fast CI

Build system, optimized for monorepos, with AI-powered architectural awareness and advanced CI capabilities.

Create a new Nx workspace with

npx create-nx-workspace

...or run

npx nx init

to add Nx to your existing workspace to get faster task scheduling, caching and more. More in the docs.

Learn about CI with Nx Cloud

Nx Cloud connects directly to your existing CI setup, helping you scale your monorepos on CI by leveraging remote caching, task distribution across multiple machines, automated e2e test splitting and automated task flakiness detection

Connect your existing Nx workspace with

npx nx connect

Learn more in the Nx CI docs »

Nx - Smart Monorepos · Fast CI

Want to help?

If you want to file a bug or submit a PR, read up on our guidelines for contributing and watch this video that will help you get started.

Nx - How to contribute video

Core Team

Victor Savkin Jason Jean Benjamin Cabanes Jack Hsu
Victor Savkin Jason Jean Benjamin Cabanes Jack Hsu
vsavkin FrozenPandaz bcabanes jaysoo
James Henry Jon Cammisuli Isaac Mann Juri Strumpflohner
James Henry Jon Cammisuli Isaac Mann Juri Strumpflohner
JamesHenry cammisuli isaacplmann juristr
Philip Fulcher Caleb Ukle Katerina Skroumpelou Colum Ferry
Philip Fulcher Caleb Ukle Katerina Skroumpelou Colum Ferry
philipjfulcher barbados-clemens mandarini Coly010
Emily Xiong Miroslav Jonaš Leosvel Pérez Espinosa Zachary DeRose
Emily Xiong Miroslav Jonaš Leosvel Pérez Espinosa Zachary DeRose
xiongemi meeroslav leosvelperez ZackDeRose
Craigory Coppola Chau Tran Nicholas Cunningham Max Kless
Craigory Coppola Chau Tran Nicholas Cunningham Max Kless
AgentEnder nartc ndcunningham MaxKless
Description
No description provided
Readme 619 MiB
Languages
TypeScript 95%
Rust 2.9%
JavaScript 1.3%
Kotlin 0.3%
MDX 0.3%
Other 0.1%