fix(js): do not add typecheck target if tsc is used for build (#30211)
This PR adds support for skipping `typecheck` targets when using `@nx/js/typescript`. Inside `tsconfig.json` for each project, you can set `nx.addTypecheckTarget` to `false` to not infer `typecheck`. This allows use to skip `typecheck` for JS projects using `tsc` to build. Since `tsc` is already used during build, we don't need to run `typecheck` that is just duplicated work. <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior JS libs using `tsc` to build will do typechecking twice. Once during `build` and once during `typecheck`. ## Expected Behavior JS libs using `tsc` do not infer `typecheck` by default. And users can change this behavior by setting `nx.addTypecheckTarget` in `tsconfig.json`. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes # --------- Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
This commit is contained in:
parent
bd78ac25b8
commit
b992e2586b
@ -63,6 +63,104 @@ Nx 20 updates the TS monorepo setup when using `--preset=ts`. The workspace is s
|
||||
To create with the older setup for TS monorepo with `compilerOptions.paths`, use `create-nx-workspace --preset=apps`.
|
||||
{% /callout %}
|
||||
|
||||
### How @nx/js Infers Tasks
|
||||
|
||||
The `@nx/js/typescript` plugin will add a `typecheck` task to projects that have a `tsconfig.json`.
|
||||
|
||||
This plugin adds a `build` task for projects that:
|
||||
|
||||
1. Have a runtime tsconfig file (defaults to `tsconfig.lib.json`).
|
||||
2. Have a `package.json` file containing entry points that are not source files.
|
||||
|
||||
For example, this project is buildable and will have a `build` task.
|
||||
|
||||
```json {% fileName="packages/pkg1/package.json" %}
|
||||
{
|
||||
"name": "@acme/pkg1",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Whereas this project points to source files and will not have a `build` task.
|
||||
|
||||
```json {% fileName="packages/pkg1/package.json" %}
|
||||
{
|
||||
"name": "@acme/pkg1",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### View Inferred Tasks
|
||||
|
||||
To view inferred tasks for a project, open the [project details view](/concepts/inferred-tasks) in Nx Console or run `nx show project my-project` in the command line.
|
||||
|
||||
### @nx/js Configuration
|
||||
|
||||
The `@nx/js/typescript` plugin is configured in the `plugins` array in `nx.json`.
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/js/typescript",
|
||||
"options": {
|
||||
"typecheck": {
|
||||
"targetName": "typecheck"
|
||||
},
|
||||
"build": {
|
||||
"targetName": "build",
|
||||
"configName": "tsconfig.lib.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You can also set `typecheck` and `build` options to `false` to not infer the corresponding tasks.
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/js/typescript",
|
||||
"options": {
|
||||
"build": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Disable Typechecking
|
||||
|
||||
To disable `typecheck` task for a specific project, set the `nx.addTypecheckTarget` property to `false` in `tsconfig.json`.
|
||||
|
||||
```json {% fileName="packages/pkg1/tsconfig.json" highlightLines=["10-12"] %}
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
],
|
||||
"nx": {
|
||||
"addTypecheckTarget": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create Libraries
|
||||
|
||||
You can add a new JS/TS library with the following command:
|
||||
|
||||
@ -63,6 +63,104 @@ Nx 20 updates the TS monorepo setup when using `--preset=ts`. The workspace is s
|
||||
To create with the older setup for TS monorepo with `compilerOptions.paths`, use `create-nx-workspace --preset=apps`.
|
||||
{% /callout %}
|
||||
|
||||
### How @nx/js Infers Tasks
|
||||
|
||||
The `@nx/js/typescript` plugin will add a `typecheck` task to projects that have a `tsconfig.json`.
|
||||
|
||||
This plugin adds a `build` task for projects that:
|
||||
|
||||
1. Have a runtime tsconfig file (defaults to `tsconfig.lib.json`).
|
||||
2. Have a `package.json` file containing entry points that are not source files.
|
||||
|
||||
For example, this project is buildable and will have a `build` task.
|
||||
|
||||
```json {% fileName="packages/pkg1/package.json" %}
|
||||
{
|
||||
"name": "@acme/pkg1",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Whereas this project points to source files and will not have a `build` task.
|
||||
|
||||
```json {% fileName="packages/pkg1/package.json" %}
|
||||
{
|
||||
"name": "@acme/pkg1",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": "./src/index.ts"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### View Inferred Tasks
|
||||
|
||||
To view inferred tasks for a project, open the [project details view](/concepts/inferred-tasks) in Nx Console or run `nx show project my-project` in the command line.
|
||||
|
||||
### @nx/js Configuration
|
||||
|
||||
The `@nx/js/typescript` plugin is configured in the `plugins` array in `nx.json`.
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/js/typescript",
|
||||
"options": {
|
||||
"typecheck": {
|
||||
"targetName": "typecheck"
|
||||
},
|
||||
"build": {
|
||||
"targetName": "build",
|
||||
"configName": "tsconfig.lib.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You can also set `typecheck` and `build` options to `false` to not infer the corresponding tasks.
|
||||
|
||||
```json {% fileName="nx.json" %}
|
||||
{
|
||||
"plugins": [
|
||||
{
|
||||
"plugin": "@nx/js/typescript",
|
||||
"options": {
|
||||
"build": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Disable Typechecking
|
||||
|
||||
To disable `typecheck` task for a specific project, set the `nx.addTypecheckTarget` property to `false` in `tsconfig.json`.
|
||||
|
||||
```json {% fileName="packages/pkg1/tsconfig.json" highlightLines=["10-12"] %}
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
}
|
||||
],
|
||||
"nx": {
|
||||
"addTypecheckTarget": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Create Libraries
|
||||
|
||||
You can add a new JS/TS library with the following command:
|
||||
|
||||
@ -131,19 +131,16 @@ ${content}`
|
||||
|
||||
// check typecheck
|
||||
expect(runCLI(`typecheck ${esbuildParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${esbuildParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${esbuildParentLib} and 4 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${rollupParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${rollupParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${rollupParentLib} and 4 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${swcParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${swcParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${tscParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${tscParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${swcParentLib} and 4 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${viteParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${viteParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${viteParentLib} and 4 tasks it depends on`
|
||||
);
|
||||
|
||||
// check lint
|
||||
|
||||
@ -105,7 +105,6 @@ describe('Node Applications', () => {
|
||||
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
|
||||
expect(() => runCLI(`typecheck ${nodelib}`)).not.toThrow();
|
||||
|
||||
const p = await runCommandUntil(
|
||||
`serve ${nodeapp}`,
|
||||
|
||||
@ -45,9 +45,6 @@ describe('Nx Plugin (TS solution)', () => {
|
||||
expect(runCLI(`lint @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target lint for project @proj/${plugin}`
|
||||
);
|
||||
expect(runCLI(`typecheck @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${plugin}`
|
||||
);
|
||||
expect(runCLI(`build @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target build for project @proj/${plugin}`
|
||||
);
|
||||
|
||||
@ -106,7 +106,7 @@ ${content}`
|
||||
|
||||
// check typecheck
|
||||
expect(runCLI(`typecheck ${reactApp}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${reactApp} and 6 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${reactApp} and 5 tasks it depends on`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -2320,5 +2320,23 @@ describe('lib', () => {
|
||||
'packages/**',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should add nx.addTypecheckTarget to tsconfig.json when using tsc to build to avoid duplicated typechecks', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultOptions,
|
||||
useProjectJson: false,
|
||||
directory: 'my-ts-lib',
|
||||
bundler: 'tsc',
|
||||
unitTestRunner: 'none',
|
||||
linter: 'none',
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'my-ts-lib/tsconfig.json').nx)
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"addTypecheckTarget": false,
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1049,6 +1049,12 @@ function createProjectTsConfigs(
|
||||
json.references.push({
|
||||
path: './tsconfig.lib.json',
|
||||
});
|
||||
// If using `tsc` to build, then we do not want a typecheck target that duplicates the work, since both run `tsc`.
|
||||
// This applies to `@nx/js/typescript` plugin only.
|
||||
if (options.bundler === 'tsc') {
|
||||
json['nx'] ??= {};
|
||||
json['nx'].addTypecheckTarget = false;
|
||||
}
|
||||
return json;
|
||||
});
|
||||
} else {
|
||||
@ -1059,6 +1065,12 @@ function createProjectTsConfigs(
|
||||
include: [],
|
||||
references: [{ path: './tsconfig.lib.json' }],
|
||||
};
|
||||
// If using `tsc` to build, then we do not want a typecheck target that duplicates the work, since both run `tsc`.
|
||||
// This applies to `@nx/js/typescript` plugin only.
|
||||
if (options.bundler === 'tsc') {
|
||||
tsconfig['nx'] ??= {};
|
||||
tsconfig['nx'].addTypecheckTarget = false;
|
||||
}
|
||||
writeJson(
|
||||
tree,
|
||||
joinPathFragments(options.projectRoot, 'tsconfig.json'),
|
||||
|
||||
@ -657,6 +657,77 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it('should not infer typecheck target when nx.addTypecheckTarget is false in tsconfig.json', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
nx: { addTypecheckTarget: false },
|
||||
}),
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: { outDir: 'out-tsc/my-lib', rootDir: 'src' },
|
||||
files: ['src/main.ts'],
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
await expect(
|
||||
invokeCreateNodesOnMatchingFiles(context, {
|
||||
build: {
|
||||
configName: 'tsconfig.lib.json',
|
||||
},
|
||||
})
|
||||
).resolves.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"production",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/out-tsc/my-lib",
|
||||
"{projectRoot}/out-tsc/*.tsbuildinfo",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('inputs', () => {
|
||||
it('should add the config file and the `include` and `exclude` patterns', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
|
||||
@ -380,7 +380,11 @@ function buildTscTargets(
|
||||
|
||||
let internalProjectReferences: Record<string, ParsedTsconfigData>;
|
||||
// Typecheck target
|
||||
if (basename(configFilePath) === 'tsconfig.json' && options.typecheck) {
|
||||
if (
|
||||
basename(configFilePath) === 'tsconfig.json' &&
|
||||
options.typecheck &&
|
||||
tsConfig.raw?.['nx']?.addTypecheckTarget !== false
|
||||
) {
|
||||
internalProjectReferences = resolveInternalProjectReferences(
|
||||
tsConfig,
|
||||
context.workspaceRoot,
|
||||
@ -1291,6 +1295,9 @@ function toAbsolutePaths(
|
||||
updatedCache[key] = {
|
||||
data: {
|
||||
options: { noEmit: data.options.noEmit },
|
||||
raw: {
|
||||
nx: { addTypecheckTarget: data.raw?.['nx']?.addTypecheckTarget },
|
||||
},
|
||||
extendedConfigFile: data.extendedConfigFile,
|
||||
},
|
||||
extendedFilesHash,
|
||||
@ -1347,6 +1354,9 @@ function toRelativePaths(
|
||||
updatedCache[key] = {
|
||||
data: {
|
||||
options: { noEmit: data.options.noEmit },
|
||||
raw: {
|
||||
nx: { addTypecheckTarget: data.raw?.['nx']?.addTypecheckTarget },
|
||||
},
|
||||
extendedConfigFile: data.extendedConfigFile,
|
||||
},
|
||||
extendedFilesHash,
|
||||
|
||||
@ -463,6 +463,9 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
"extends": "../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"nx": {
|
||||
"addTypecheckTarget": false,
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user