From 6753e9f809e5f596a1265ad99ca2008cdf09cd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=9A=80=20Jack?= Date: Fri, 8 Nov 2024 12:02:40 +1100 Subject: [PATCH] fix(js): skip tsc batch builds for implicit dependencies Implicit dependencies are not referenced in code and therefore TSC incremental builds are not applicable closed #28839 --- docs/generated/packages/js/executors/tsc.json | 2 +- docs/shared/recipes/enable-tsc-batch-mode.md | 2 +- packages/js/docs/tsc-examples.md | 2 +- packages/js/src/executors/tsc/lib/get-tsconfig.ts | 13 +++++++++++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/generated/packages/js/executors/tsc.json b/docs/generated/packages/js/executors/tsc.json index 2df446a961f17..7d6c1ec3e6964 100644 --- a/docs/generated/packages/js/executors/tsc.json +++ b/docs/generated/packages/js/executors/tsc.json @@ -183,7 +183,7 @@ ] } }, - "examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Using TypeScript Transformer Plugins\" %}\n\n`@nx/js:tsc` can run the [TypeScript Transformers](https://github.com/madou/typescript-transformer-handbook) by using the `transformers` option.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"transformers\": [\n \"@nestjs/swagger/plugin\",\n {\n \"name\": \"@automapper/classes/transformer-plugin\",\n \"options\": {}\n }\n ]\n }\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Inline libraries\" %}\n\n`@nx/js:tsc` can inline non-buildable libraries by opt-in to **Inlining** mode with `external` option.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"external\": \"all\"\n }\n }\n}\n```\n\n```shell\nnpx nx build ts-lib --external=all\n```\n\n`@nx/js:tsc` can also inline buildable libraries by setting `external: 'none'`\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"external\": \"none\"\n }\n }\n}\n```\n\n```shell\nnpx nx build ts-lib --external=none\n```\n\n{% /tab %}\n{% tab label=\"Batch mode execution\" %}\n\n{% callout type=\"check\" title=\"Available since Nx 16.6.0\" %}\nThe `@nx/js:tsc` batch implementation was introduced in Nx **16.6.0**.\n{% /callout %}\n\nThe `@nx/js:tsc` executor supports running multiple tasks in a single process. When running in batch mode, the executor uses the [TypeScript APIs for incremental builds](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript). 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).\n\n{% callout type=\"warning\" title=\"Experimental feature\" %}\nExecuting tasks in batch mode is an experimental feature.\n{% /callout %}\n\n{% callout type=\"info\" title=\"Requirements\" %}\nBuilding 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.\n{% /callout %}\n\nTo run your builds using the batch implementation, pass in `--batch` flag:\n\n```shell\nnx build ts-lib --batch\n```\n\nFor 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.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"clean\": false\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n", + "examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Using TypeScript Transformer Plugins\" %}\n\n`@nx/js:tsc` can run the [TypeScript Transformers](https://github.com/madou/typescript-transformer-handbook) by using the `transformers` option.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"transformers\": [\n \"@nestjs/swagger/plugin\",\n {\n \"name\": \"@automapper/classes/transformer-plugin\",\n \"options\": {}\n }\n ]\n }\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Inline libraries\" %}\n\n`@nx/js:tsc` can inline non-buildable libraries by opt-in to **Inlining** mode with `external` option.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"external\": \"all\"\n }\n }\n}\n```\n\n```shell\nnpx nx build ts-lib --external=all\n```\n\n`@nx/js:tsc` can also inline buildable libraries by setting `external: 'none'`\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"external\": \"none\"\n }\n }\n}\n```\n\n```shell\nnpx nx build ts-lib --external=none\n```\n\n{% /tab %}\n{% tab label=\"Batch mode execution\" %}\n\n{% callout type=\"check\" title=\"Available since Nx 16.6.0\" %}\nThe `@nx/js:tsc` batch implementation was introduced in Nx **16.6.0**.\n{% /callout %}\n\nThe `@nx/js:tsc` executor supports running multiple tasks in a single process. When running in batch mode, the executor uses the [TypeScript APIs for incremental builds](https://www.typescriptlang.org/docs/handbook/project-references.html#build-mode-for-typescript). 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).\n\n{% callout type=\"warning\" title=\"Experimental feature\" %}\nExecuting tasks in batch mode is an experimental feature.\n{% /callout %}\n\n{% callout type=\"info\" title=\"Requirements\" %}\nBuilding a project with the `@nx/js:tsc` executor in batch mode requires all dependent projects (excluding implicit dependencies) to be buildable and built using the `@nx/js:tsc` executor.\n{% /callout %}\n\nTo run your builds using the batch implementation, pass in `--batch` flag:\n\n```shell\nnx build ts-lib --batch\n```\n\nFor 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.\n\n```json {% fileName=\"libs/ts-lib/project.json\" %}\n{\n \"build\": {\n \"executor\": \"@nx/js:tsc\",\n \"options\": {\n \"outputPath\": \"dist/libs/ts-lib\",\n \"main\": \"libs/ts-lib/src/index.ts\",\n \"tsConfig\": \"libs/ts-lib/tsconfig.lib.json\",\n \"assets\": [\"libs/ts-lib/*.md\"],\n \"clean\": false\n }\n }\n}\n```\n\n{% /tab %}\n{% /tabs %}\n", "presets": [] }, "description": "Build a project using TypeScript.", diff --git a/docs/shared/recipes/enable-tsc-batch-mode.md b/docs/shared/recipes/enable-tsc-batch-mode.md index fd22ae61a2b6e..91320b64b3eec 100644 --- a/docs/shared/recipes/enable-tsc-batch-mode.md +++ b/docs/shared/recipes/enable-tsc-batch-mode.md @@ -11,7 +11,7 @@ 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. +Building a project with the `@nx/js:tsc` executor in batch mode requires all dependent projects (excluding implicit dependencies) to be buildable and built using the `@nx/js:tsc` executor. {% /callout %} To run your builds using the batch implementation, pass in `--batch` flag: diff --git a/packages/js/docs/tsc-examples.md b/packages/js/docs/tsc-examples.md index ec3ee5014a0cd..879b37746a072 100644 --- a/packages/js/docs/tsc-examples.md +++ b/packages/js/docs/tsc-examples.md @@ -85,7 +85,7 @@ 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. +Building a project with the `@nx/js:tsc` executor in batch mode requires all dependent projects (excluding implicit dependencies) to be buildable and built using the `@nx/js:tsc` executor. {% /callout %} To run your builds using the batch implementation, pass in `--batch` flag: diff --git a/packages/js/src/executors/tsc/lib/get-tsconfig.ts b/packages/js/src/executors/tsc/lib/get-tsconfig.ts index 6ab966881d709..9b3016ce513ab 100644 --- a/packages/js/src/executors/tsc/lib/get-tsconfig.ts +++ b/packages/js/src/executors/tsc/lib/get-tsconfig.ts @@ -103,9 +103,18 @@ function getDependencyTasksInOtherProjects( project: string, context: ExecutorContext ): string[] { - return context.taskGraph.dependencies[task].filter( - (t) => t !== task && parseTargetString(t, context).project !== project + const implicitDependencies = new Set( + context.projectGraph.nodes[project].data.implicitDependencies ?? [] ); + return context.taskGraph.dependencies[task].filter((t) => { + const { project: dependencyProject } = parseTargetString(t, context); + // Tasks for implicit dependencies are skipped since incremental builds only apply to explicit dependencies + return ( + t !== task && + dependencyProject !== project && + !implicitDependencies.has(dependencyProject) + ); + }); } function getDependencyTasksInSameProject(