diff --git a/docs/shared/configuration/packagejson.md b/docs/shared/configuration/packagejson.md index 268883639fc6b..80e4b9146d87c 100644 --- a/docs/shared/configuration/packagejson.md +++ b/docs/shared/configuration/packagejson.md @@ -37,21 +37,11 @@ You can add Nx-specific configuration as follows: "targets": { "build": { "outputs": ["dist/libs/mylib"], - "dependsOn": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "dependsOn": ["^build"] }, "test": { "outputs": [], - "dependsOn": [ - { - "target": "build", - "projects": "self" - } - ] + "dependsOn": ["build"] } } } @@ -77,13 +67,13 @@ sure that `mylib`'s dependencies are built as well. This doesn't mean Nx is goin artifacts are already in the right place, Nx will do nothing. If they aren't in the right place, but they are available in the cache, Nx will retrieve them from the cache. -Depending on another target of the same project is very common. That's why we provide some syntax sugar, so -`"dependsOn": [{"target": "build", "projects": "self"}]` can be shortened to `"dependsOn": ["build"]`. - Another common scenario is for a target to depend on another target of the same project. For instance, `dependsOn` of the `test` target tells Nx that before it can test `mylib` it needs to make sure that `mylib` is built, which will result in `mylib`'s dependencies being built as well. +> You can also express the same configuration using `{ projects: "self", target: "build"}` +> and `{ projects: "dependencies", target: "build"}`. + This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the configuration above. @@ -185,13 +175,10 @@ The following is an expanded version showing all options. Your `nx.json` will li "tsconfig.base.json": "*", "nx.json": "*" }, - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } }, "cli": { "defaultCollection": "@nrwl/js" @@ -272,30 +259,41 @@ In the example above: - Changing `globalFile` only affects `myapp`. - Changing any CSS file inside the `styles` directory only affects `myapp`. -### Target Dependencies +### Target Defaults Targets can depend on other targets. A common scenario is having to build dependencies of a project first before building the project. The `dependsOn` property in `package.json` can be used to define the list of dependencies of an individual target. Often the same `dependsOn` configuration has to be defined for every project in the repo, and that's when -defining `targetDependencies` in `nx.json` is helpful. +defining `targetDefaults` in `nx.json` is helpful. ```json { - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } + } +} +``` + +The configuration above is identical to adding `{"dependsOn": ["^build"]}` to every build target of every project. + +Another target default you can configure is `outputs`: + +```json +{ + "targetDefaults": { + "build": { + "outputs": ["./custom-dist"] + } } } ``` -The configuration above is identical to adding `{"dependsOn": [{"target": "build", "projects": "dependencies"]}` to -every build target of every project. +> Previous versions of Nx supported `targetDependencies` to configure dependencies in `nx.json`. `targetDefaults` is the +> same mechanism but generalized to support other properties. ### CLI Options diff --git a/docs/shared/configuration/projectjson.md b/docs/shared/configuration/projectjson.md index c5ecaa9a87253..64c82ee2ee258 100644 --- a/docs/shared/configuration/projectjson.md +++ b/docs/shared/configuration/projectjson.md @@ -29,12 +29,7 @@ Let's look at the following `project.json`: "test": { "executor": "@nrwl/jest:jest", "outputs": [], - "dependsOn": [ - { - "target": "build", - "projects": "self" - } - ], + "dependsOn": ["build"], "options": { "jestConfig": "libs/mylib/jest.config.js", "tsConfig": "libs/mylib/tsconfig.spec.json" @@ -43,12 +38,7 @@ Let's look at the following `project.json`: "build": { "executor": "@nrwl/js:tsc", "outputs": ["dist/libs/mylib"], - "dependsOn": [ - { - "target": "build", - "projects": "dependencies" - } - ], + "dependsOn": ["^build"], "options": { "tsConfig": "libs/mylib/tsconfig.lib.json", "main": "libs/mylib/src/main.ts" @@ -79,12 +69,7 @@ Let's look at a sample test target: "test": { "executor": "@nrwl/jest:jest", "outputs": [], - "dependsOn": [ - { - "target": "build", - "projects": "self" - } - ], + "dependsOn": ["build"], "options": { "jestConfig": "libs/mylib/jest.config.js", "tsConfig": "libs/mylib/tsconfig.spec.json" @@ -126,12 +111,7 @@ The `configurations` property provides extra sets of values that will be merged "build": { "executor": "@nrwl/js:tsc", "outputs": ["dist/libs/mylib"], - "dependsOn": [ - { - "target": "build", - "projects": "dependencies" - } - ], + "dependsOn": ["^build"], "options": { "tsConfig": "libs/mylib/tsconfig.lib.json", "main": "libs/mylib/src/main.ts" @@ -177,13 +157,13 @@ sure that `mylib`'s dependencies are built as well. This doesn't mean Nx is goin artifacts are already in the right place, Nx will do nothing. If they aren't in the right place, but they are available in the cache, Nx will retrieve them from the cache. -Depending on another target of the same project is very common. That's why we provide some syntax sugar, so -`"dependsOn": [{"target": "build", "projects": "self"}]` can be shortened to `"dependsOn": ["build"]`. - Another common scenario is for a target to depend on another target of the same project. For instance, `dependsOn` of the `test` target tells Nx that before it can test `mylib` it needs to make sure that `mylib` is built, which will result in `mylib`'s dependencies being built as well. +> You can also express the same configuration using `{ projects: "self", target: "build"}` +> and `{ projects: "dependencies", target: "build"}`. + This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the configuration above. @@ -274,13 +254,10 @@ The following is an expanded version showing all options. Your `nx.json` will li "tsconfig.base.json": "*", "nx.json": "*" }, - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } }, "cli": { "defaultCollection": "@nrwl/js" @@ -361,30 +338,38 @@ In the example above: - Changing `globalFile` only affects `myapp`. - Changing any CSS file inside the `styles` directory only affects `myapp`. -### Target Dependencies +### Target Defaults Targets can depend on other targets. A common scenario is having to build dependencies of a project first before -building the project. The `dependsOn` property in `package.json` can be used to define the list of dependencies of an +building the project. The `dependsOn` property in `project.json` can be used to define the list of dependencies of an individual target. Often the same `dependsOn` configuration has to be defined for every project in the repo, and that's when -defining `targetDependencies` in `nx.json` is helpful. +defining `targetDefaults` in `nx.json` is helpful. ```json { - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } } } ``` -The configuration above is identical to adding `{"dependsOn": [{"target": "build", "projects": "dependencies"]}` to -every build target of every project. +The configuration above is identical to adding `{"dependsOn": ["^build"]}` to every build target of every project. + +Another target default you can configure is `outputs`: + +```json +{ + "targetDefaults": { + "build": { + "outputs": ["./custom-dist"] + } + } +} +``` ### CLI Options diff --git a/docs/shared/guides/setup-incremental-builds-angular.md b/docs/shared/guides/setup-incremental-builds-angular.md index b3d1a7a2956ff..2bd243622bc9d 100644 --- a/docs/shared/guides/setup-incremental-builds-angular.md +++ b/docs/shared/guides/setup-incremental-builds-angular.md @@ -1,26 +1,33 @@ # Setup incremental builds for Angular applications -In this guide we’ll specifically look into which changes need to be made to enable incremental builds for Angular applications. +In this guide we’ll specifically look into which changes need to be made to enable incremental builds for Angular +applications. > Incremental builds requires Nx version 10.4.0 or later. ## Requirements -It’s required that you run the Angular compatibility compiler (`ngcc`) after every package installation if you have Ivy enabled. This comes configured by default in every Nx workspace. The incremental build relies on the fact that `ngcc` must have already been run. You can check your `package.json` and make sure you have the following: +It’s required that you run the Angular compatibility compiler (`ngcc`) after every package installation if you have Ivy +enabled. This comes configured by default in every Nx workspace. The incremental build relies on the fact that `ngcc` +must have already been run. You can check your `package.json` and make sure you have the following: ```json { + ... + "scripts": { ... - "scripts": { - ... - "postinstall": "ngcc --properties es2015 browser module main", - ... - } + "postinstall": "ngcc --properties es2015 browser module main", ... + } + ... } ``` -> Please note that `ngcc` doesn’t support `pnpm` ([#32087](https://github.com/angular/angular/issues/32087#issuecomment-523225437) and [#38023](https://github.com/angular/angular/issues/38023#issuecomment-732423078)), so you need to use either `yarn` or `npm`. +> Please note that `ngcc` doesn’t +> support `pnpm` ([#32087](https://github.com/angular/angular/issues/32087#issuecomment-523225437) +> and [#38023](https://github.com/angular/angular/issues/38023#issuecomment-732423078)), so you need to use +> either `yarn` +> or `npm`. ## Use buildable libraries @@ -32,62 +39,79 @@ You can generate a new buildable library with: nx g @nrwl/angular:lib my-lib --buildable ``` -The generated buildable library uses the `@nrwl/angular:ng-packagr-lite` executor which is optimized for the incremental builds scenario: +The generated buildable library uses the `@nrwl/angular:ng-packagr-lite` executor which is optimized for the incremental +builds scenario: ```json { - "projectType": "library", - ... - "targets": { - "build": { - "executor": "@nrwl/angular:ng-packagr-lite", - "outputs": ["dist/libs/my-lib"], - "options": {...}, - "configurations": {...}, - "defaultConfiguration": "production" - }, + "projectType": "library", + ... + "targets": { + "build": { + "executor": "@nrwl/angular:ng-packagr-lite", + "outputs": [ + "dist/libs/my-lib" + ], + "options": { ... + }, + "configurations": { + ... + }, + "defaultConfiguration": "production" }, - ... + ... + }, + ... }, ``` -> Please note that it is important to keep the `outputs` property in sync with the `dest` property in the file `ng-package.json` located inside the library root. When a library is generated, this is configured correctly, but if the path is later changed in `ng-package.json`, it needs to be updated as well in the project configuration. +> Please note that it is important to keep the `outputs` property in sync with the `dest` property in the +> file `ng-package.json` located inside the library root. When a library is generated, this is configured correctly, but +> if the path is later changed in `ng-package.json`, it needs to be updated as well in the project configuration. -> The `@nrwl/angular:package` executor also supports incremental builds. It is used to build and package an Angular library to be distributed as an NPM package following the Angular Package Format (APF) specification. It will be automatically configured when generating a publishable library (`nx g @nrwl/angular:lib my-lib --publishable --importPath my-lib`). +> The `@nrwl/angular:package` executor also supports incremental builds. It is used to build and package an Angular +> library to be distributed as an NPM package following the Angular Package Format (APF) specification. It will be +> automatically configured when generating a publishable +> library (`nx g @nrwl/angular:lib my-lib --publishable --importPath my-lib`). ## Adjust the application executor -Change your Angular application’s "build" target executor to `@nrwl/angular:webpack-browser` and the "serve" target executor to `@nrwl/web:file-server` as shown below: +Change your Angular application’s "build" target executor to `@nrwl/angular:webpack-browser` and the "serve" target +executor to `@nrwl/web:file-server` as shown below: ```json { - "projectType": "application", - ... - "targets": { - "build": { - "executor": "@nrwl/angular:webpack-browser", - "outputs": ["{options.outputPath}"], - "options": { - "buildLibsFromSource": false - ... - }, - "configurations": { ... }, - "defaultConfiguration": "production" - }, - "serve": { - "executor": "@nrwl/web:file-server", - "options": { - "buildTarget": "my-app:build" - }, - "configurations": { - "production": { - "buildTarget": "my-app:build:production" - } - } - }, + "projectType": "application", + ... + "targets": { + "build": { + "executor": "@nrwl/angular:webpack-browser", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "buildLibsFromSource": false ... - } + }, + "configurations": { + ... + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@nrwl/web:file-server", + "options": { + "buildTarget": "my-app:build" + }, + "configurations": { + "production": { + "buildTarget": "my-app:build:production" + } + } + }, + ... + } }, ``` @@ -105,118 +129,146 @@ To serve an application incrementally use this command: nx serve my-app --parallel ``` -Note: you can specify the `--parallel` flags as part of the options property on the file-server executor in your `project.json` file. The file-server executor will pass those to the `nx build` command it invokes. +Note: you can specify the `--parallel` flags as part of the options property on the file-server executor in +your `project.json` file. The file-server executor will pass those to the `nx build` command it invokes. ```json { - "projectType": "application", - ... - "targets": { - "build": { - "executor": "@nrwl/angular:webpack-browser", - "outputs": ["{options.outputPath}"], - "options": { - "buildLibsFromSource": false - ... - }, - "configurations": { ... } - }, - "serve": { - "executor": "@nrwl/web:file-server", - "options": { - "buildTarget": "my-app:build", - "parallel": true - }, - "configurations": { - "production": { - "buildTarget": "my-app:build:production" - } - } - }, + "projectType": "application", + ... + "targets": { + "build": { + "executor": "@nrwl/angular:webpack-browser", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "buildLibsFromSource": false ... - } + }, + "configurations": { + ... + } + }, + "serve": { + "executor": "@nrwl/web:file-server", + "options": { + "buildTarget": "my-app:build", + "parallel": true + }, + "configurations": { + "production": { + "buildTarget": "my-app:build:production" + } + } + }, + ... + } }, ``` ### Build target name -It is required to use the same target name for the build target (target using one of the executors that support incremental builds: `@nrwl/angular:webpack-browser`, `@nrwl/angular:package` and `@nrwl/angular:ng-packagr-lite`) in the project being built and the buildable libraries it depends on. The executors that support incremental builds rely on the build target name of the project to identify which of the libraries it depends on are buildable. +It is required to use the same target name for the build target (target using one of the executors that support +incremental builds: `@nrwl/angular:webpack-browser`, `@nrwl/angular:package` and `@nrwl/angular:ng-packagr-lite`) in the +project being built and the buildable libraries it depends on. The executors that support incremental builds rely on the +build target name of the project to identify which of the libraries it depends on are buildable. -If you need to have a different build target name for an application (or library) build (e.g. when composing different targets), you need to make sure the build target name of all the relevant projects is the same. +If you need to have a different build target name for an application (or library) build (e.g. when composing different +targets), you need to make sure the build target name of all the relevant projects is the same. Say you have the same application above with a configuration as follows: ```json { - "projectType": "application", - ... - "targets": { - "build-base": { - "executor": "@nrwl/angular:webpack-browser", - "outputs": ["{options.outputPath}"], - "options": { - "buildLibsFromSource": false - ... - }, - "configurations": { ... } - }, - "build": { - "executor": "@nrwl/workspace:run-commands", - "outputs": ["{options.outputPath}"], - "options": { - "commands": [ - "node ./tools/scripts/important-script.js", - "node ./tools/scripts/another-important-script.js" - ], - ... - }, - "configurations": { ... } - }, - "serve": { - "executor": "@nrwl/web:file-server", - "options": { - "buildTarget": "my-app:build-base", - "parallel": true - }, - "configurations": { - "production": { - "buildTarget": "my-app:build-base:production" - } - } - }, + "projectType": "application", + ... + "targets": { + "build-base": { + "executor": "@nrwl/angular:webpack-browser", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "buildLibsFromSource": false ... - } + }, + "configurations": { + ... + } + }, + "build": { + "executor": "@nrwl/workspace:run-commands", + "outputs": [ + "{options.outputPath}" + ], + "options": { + "commands": [ + "node ./tools/scripts/important-script.js", + "node ./tools/scripts/another-important-script.js" + ], + ... + }, + "configurations": { + ... + } + }, + "serve": { + "executor": "@nrwl/web:file-server", + "options": { + "buildTarget": "my-app:build-base", + "parallel": true + }, + "configurations": { + "production": { + "buildTarget": "my-app:build-base:production" + } + } + }, + ... + } }, ``` -And the `targetDependencies` configured in the `nx.json` as: +And the `targetDefaults` configured in the `nx.json` as: ```json { - "targetDependencies": { - "build": [{ "target": "build-base", "projects": "self" }], - "build-base": [{ "target": "build-base", "projects": "dependencies" }] + "targetDefaults": { + "build": { + "dependsOn": ["build-base"] + }, + "build-base": { + "dependsOn": ["^build-base"] + } } } ``` -The build target name of the application is `build-base`. Therefore, the build target name of the buildable libraries it depends on must also be `build-base`: +The build target name of the application is `build-base`. Therefore, the build target name of the buildable libraries it +depends on must also be `build-base`: ```json { - "projectType": "library", - ... - "targets": { - "build-base": { - "executor": "@nrwl/angular:ng-packagr-lite", - "outputs": ["dist/libs/my-lib"], - "options": {...}, - "configurations": {...}, - "defaultConfiguration": "production" - }, + "projectType": "library", + ... + "targets": { + "build-base": { + "executor": "@nrwl/angular:ng-packagr-lite", + "outputs": [ + "dist/libs/my-lib" + ], + "options": { ... + }, + "configurations": { + ... + }, + "defaultConfiguration": "production" }, - ... + ... + }, + ... }, ``` diff --git a/docs/shared/mental-model.md b/docs/shared/mental-model.md index b4a5e64e8887a..e08b31a7a6b3e 100644 --- a/docs/shared/mental-model.md +++ b/docs/shared/mental-model.md @@ -11,7 +11,8 @@ authored in your repository, such as Webpack, React, Angular, and so forth. ![project-graph](/shared/mental-model/project-graph.png) -With Nx, nodes in the project graph are defined in `project.json` files. You can manually define dependencies between the +With Nx, nodes in the project graph are defined in `project.json` files. You can manually define dependencies between +the nodes, but you don’t have to do it very often. Nx analyzes files’ source code, your installed dependencies, TypeScript files, and others figuring out these dependencies for you. Nx also stores the cached project graph, so it only reanalyzes the files you have changed. @@ -49,7 +50,8 @@ running `nx run-many --target=test --projects=app1,app2,lib`, the created task g ![task-graph-creation](/shared/mental-model/task-graph-creation.png) -Even though the apps depend on `lib`, testing `app1` doesn’t depend on the testing `lib`. This means that the two tasks can +Even though the apps depend on `lib`, testing `app1` doesn’t depend on the testing `lib`. This means that the two tasks +can run in parallel. Let’s look at the test target relying on its dependencies. @@ -59,12 +61,7 @@ Let’s look at the test target relying on its dependencies. "test": { "executor": "@nrwl/jest:jest", "outputs": ["coverage/apps/app1"], - "dependsOn": [ - { - "target": "test", - "projects": "dependencies" - } - ], + "dependsOn": ["^test"], "options": { "jestConfig": "apps/app1/jest.config.js", "passWithNoTests": true @@ -77,7 +74,8 @@ With this, running the same test command creates the following task graph: ![task-graph-run](/shared/mental-model/task-graph-run.png) -This often makes more sense for builds, where to build `app1`, you want to build `lib` first. You can also define similar +This often makes more sense for builds, where to build `app1`, you want to build `lib` first. You can also define +similar relationships between targets of the same project, including a test target that depends on the build. A task graph can contain different targets, and those can run in parallel. For instance, as Nx is building `app2`, it @@ -92,7 +90,8 @@ execution time. When you run `nx test app1`, you are telling Nx to run the `app1:test` task plus all the tasks it depends on. -When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two tasks `app1:test` +When you run `nx run-many --target=test --projects=app1,lib`, you are telling Nx to do the same for two +tasks `app1:test` and `lib:test`. When you run `nx run-many --target=test --all`, you are telling Nx to do this for all the projects. @@ -162,14 +161,16 @@ work happens. The rest is either left as is or restored from the cache. ## Distributed task execution Nx supports running commands across multiple machines. You can either set it up by hand ( -see [here](/ci/distributed-builds)) or use Nx Cloud. [Read the comparison of the two approaches.](https://blog.nrwl.io/distributing-ci-binning-and-distributed-task-execution-632fe31a8953?source=friends_link&sk=5120b7ff982730854ed22becfe7a640a) +see [here](/ci/distributed-builds)) or use Nx +Cloud. [Read the comparison of the two approaches.](https://blog.nrwl.io/distributing-ci-binning-and-distributed-task-execution-632fe31a8953?source=friends_link&sk=5120b7ff982730854ed22becfe7a640a) When using the distributed task execution, Nx is able to run any task graph on many agents instead of locally. For instance, `nx affected --build` won't run the build locally (which can take hours for large workspaces). Instead, it will send the Task Graph to Nx Cloud. Nx Cloud Agents will then pick up the tasks they can run and execute them. -Note that this happens transparently. If an agent builds `app1`, it will fetch the outputs for `lib` if it doesn't have them +Note that this happens transparently. If an agent builds `app1`, it will fetch the outputs for `lib` if it doesn't have +them already. As agents complete tasks, the main job where you invoked `nx affected --build` will start receiving created files and diff --git a/e2e/add-nx-to-monorepo/src/add-nx-to-monorepo.test.ts b/e2e/add-nx-to-monorepo/src/add-nx-to-monorepo.test.ts index d7f6ea98c9c3d..8168208eb61a1 100644 --- a/e2e/add-nx-to-monorepo/src/add-nx-to-monorepo.test.ts +++ b/e2e/add-nx-to-monorepo/src/add-nx-to-monorepo.test.ts @@ -48,8 +48,8 @@ describe('add-nx-to-monorepo', () => { expect(output).toContain('🎉 Done!'); expect(readWorkspaceConfig().projects['package-a']).toBeTruthy(); expect(readWorkspaceConfig().projects['package-b']).toBeTruthy(); - expect(readWorkspaceConfig().targetDependencies).toEqual({ - build: [{ projects: 'dependencies', target: 'build' }], + expect(readWorkspaceConfig().targetDefaults).toEqual({ + build: { dependsOn: ['^build'] }, }); expect( readWorkspaceConfig().tasksRunnerOptions['default'].options diff --git a/e2e/angular-core/src/ng-add.test.ts b/e2e/angular-core/src/ng-add.test.ts index 10cd1fd0a2b42..4976e14a46f46 100644 --- a/e2e/angular-core/src/ng-add.test.ts +++ b/e2e/angular-core/src/ng-add.test.ts @@ -153,13 +153,10 @@ describe('convert Angular CLI workspace to an Nx workspace', () => { }, }, npmScope: 'projscope', - targetDependencies: { - build: [ - { - projects: 'dependencies', - target: 'build', - }, - ], + targetDefaults: { + build: { + dependsOn: ['^build'], + }, }, tasksRunnerOptions: { default: { diff --git a/e2e/workspace-integrations/src/run-one.test.ts b/e2e/workspace-integrations/src/run-one.test.ts index 60e3813d0c5fd..9314ddca1cd59 100644 --- a/e2e/workspace-integrations/src/run-one.test.ts +++ b/e2e/workspace-integrations/src/run-one.test.ts @@ -1,9 +1,11 @@ import { + checkFilesExist, cleanupProject, newProject, readFile, readJson, readProjectConfig, + removeFile, runCLI, runCommand, uniq, @@ -126,13 +128,7 @@ describe('run-one', () => { command: 'echo PREP', }, }; - config.targets.build.dependsOn = [ - 'prep', - { - target: 'build', - projects: 'dependencies', - }, - ]; + config.targets.build.dependsOn = ['prep', '^build']; return config; }); @@ -148,21 +144,12 @@ describe('run-one', () => { updateProjectConfig(myapp, () => originalWorkspace); }, 10000); + // deprecated it('should be able to include deps using target dependencies defined at the root', () => { const originalNxJson = readFile('nx.json'); const nxJson = readJson('nx.json'); nxJson.targetDependencies = { - build: [ - { - target: 'build', - projects: 'dependencies', - }, - /** - * At the time of writing, the above object is also the default in nx.json, so we need to make an additional change to ensure - * that the JSON is structurally different and the build results are therefore not read from the cache as part of this test. - */ - { target: 'e2e-extra-entry-to-bust-cache', projects: 'dependencies' }, - ], + build: ['^build', '^e2e-extra-entry-to-bust-cache'], }; updateFile('nx.json', JSON.stringify(nxJson)); @@ -176,5 +163,48 @@ describe('run-one', () => { updateFile('nx.json', originalNxJson); }, 10000); + + it('should be able to include deps using target defaults defined at the root', () => { + const nxJson = readJson('nx.json'); + updateProjectConfig(myapp, (config) => { + config.targets.prep = { + executor: 'nx:run-commands', + options: { + command: 'echo PREP > one.txt', + }, + }; + config.targets.outside = { + executor: 'nx:run-commands', + options: { + command: 'echo OUTSIDE', + }, + }; + return config; + }); + + nxJson.tasksRunnerOptions.default.options.cacheableOperations = [ + 'prep', + 'outside', + ]; + nxJson.targetDefaults = { + prep: { + outputs: ['one.txt'], + }, + outside: { + dependsOn: ['prep'], + }, + }; + updateFile('nx.json', JSON.stringify(nxJson)); + + const output = runCLI(`outside ${myapp}`); + expect(output).toContain( + `NX Running target outside for project ${myapp} and 1 task(s) it depends on` + ); + + removeFile(`one.txt`); + runCLI(`outside ${myapp}`); + + checkFilesExist(`one.txt`); + }, 10000); }); }); diff --git a/packages/add-nx-to-monorepo/src/add-nx-to-monorepo.ts b/packages/add-nx-to-monorepo/src/add-nx-to-monorepo.ts index c2dcaa543f89c..bb7d99126b15d 100644 --- a/packages/add-nx-to-monorepo/src/add-nx-to-monorepo.ts +++ b/packages/add-nx-to-monorepo/src/add-nx-to-monorepo.ts @@ -182,12 +182,12 @@ function createNxJsonFile(repoRoot: string, projects: ProjectDesc[]) { const cacheableOperations = Object.keys(allScripts).filter( (s) => s.indexOf('serve') === -1 && s.indexOf('start') === -1 ); - const targetDependencies = cacheableOperations + const targetDefaults = cacheableOperations .filter((c) => c === 'build' || c === 'prepare' || c === 'package') .reduce( (m, c) => ({ ...m, - [c]: [{ target: c, projects: 'dependencies' }], + [c]: { dependsOn: [`^${c}`] }, }), {} ); @@ -202,7 +202,7 @@ function createNxJsonFile(repoRoot: string, projects: ProjectDesc[]) { }, }, }, - targetDependencies, + targetDefaults, affected: { defaultBase: deduceDefaultBase(), }, diff --git a/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap b/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap index 550e7eb5b553c..b85fc019b783f 100644 --- a/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap +++ b/packages/angular/src/generators/ng-add/__snapshots__/migrate-from-angular-cli.spec.ts.snap @@ -13,13 +13,12 @@ Object { }, }, "npmScope": "my-scope", - "targetDependencies": Object { - "build": Array [ - Object { - "projects": "dependencies", - "target": "build", - }, - ], + "targetDefaults": Object { + "build": Object { + "dependsOn": Array [ + "^build", + ], + }, }, "tasksRunnerOptions": Object { "default": Object { @@ -54,13 +53,12 @@ Object { }, }, "npmScope": "my-scope", - "targetDependencies": Object { - "build": Array [ - Object { - "projects": "dependencies", - "target": "build", - }, - ], + "targetDefaults": Object { + "build": Object { + "dependsOn": Array [ + "^build", + ], + }, }, "tasksRunnerOptions": Object { "default": Object { @@ -174,13 +172,12 @@ Object { }, }, "npmScope": "my-org", - "targetDependencies": Object { - "build": Array [ - Object { - "projects": "dependencies", - "target": "build", - }, - ], + "targetDefaults": Object { + "build": Object { + "dependsOn": Array [ + "^build", + ], + }, }, "tasksRunnerOptions": Object { "default": Object { diff --git a/packages/angular/src/generators/ng-add/utilities/workspace.ts b/packages/angular/src/generators/ng-add/utilities/workspace.ts index bd80aa0605d92..77aca5859351a 100644 --- a/packages/angular/src/generators/ng-add/utilities/workspace.ts +++ b/packages/angular/src/generators/ng-add/utilities/workspace.ts @@ -68,13 +68,8 @@ export function createNxJson( }, }, }, - targetDependencies: { - build: [ - { - target: 'build', - projects: 'dependencies', - }, - ], + targetDefaults: { + build: { dependsOn: ['^build'] }, }, workspaceLayout: setWorkspaceLayoutAsNewProjectRoot ? { appsDir: newProjectRoot, libsDir: newProjectRoot } diff --git a/packages/nx/migrations.json b/packages/nx/migrations.json index 7ffd1c1b92bb3..121e1104d0c55 100644 --- a/packages/nx/migrations.json +++ b/packages/nx/migrations.json @@ -4,25 +4,31 @@ "cli": "nx", "version": "14.0.6", "description": "Remove root property from project.json files", - "factory": "./src/migrations/update-14-0-6/remove-roots" + "implementation": "./src/migrations/update-14-0-6/remove-roots" }, "14-2-0-add-json-schema": { "cli": "nx", "version": "14.2.0-beta.0", "description": "Add JSON Schema to Nx configuration files", - "factory": "./src/migrations/update-14-2-0/add-json-schema" + "implementation": "./src/migrations/update-14-2-0/add-json-schema" }, "14-2-0-remove-default-collection": { "cli": "nx", "version": "14.2.0-beta.0", "description": "Remove default collection from configuration to switch to prompts for collection", - "factory": "./src/migrations/update-14-2-0/remove-default-collection" + "implementation": "./src/migrations/update-14-2-0/remove-default-collection" }, "14-2-0-replace-relative-outputs-with-absolute": { "cli": "nx", "version": "14.2.0-beta.5", "description": "Replace all ./ and ../ in outputs with absolute paths", - "factory": "./src/migrations/update-14-2-0/replace-all-relative-outputs-with-absolute" + "implementation": "./src/migrations/update-14-2-0/replace-all-relative-outputs-with-absolute" + }, + "14.3.4-create-target-defaults": { + "cli": "nx", + "version": "14.3.4-beta.1", + "description": "Replace targetDependencies with targetDefaults", + "implementation": "./src/migrations/update-14-3-4/create-target-defaults" } } } diff --git a/packages/nx/migrations.spec.ts b/packages/nx/migrations.spec.ts deleted file mode 100644 index baa1cc284673a..0000000000000 --- a/packages/nx/migrations.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import path = require('path'); -import json = require('./migrations.json'); - -describe('Nx migrations', () => { - it('should have valid paths', () => { - Object.values(json.generators).forEach((m) => { - expect(() => - require.resolve(path.join(__dirname, `${m.factory}.ts`)) - ).not.toThrow(); - }); - }); -}); diff --git a/packages/nx/schemas/nx-schema.json b/packages/nx/schemas/nx-schema.json index a6d4921725f56..8d0f909105597 100644 --- a/packages/nx/schemas/nx-schema.json +++ b/packages/nx/schemas/nx-schema.json @@ -29,6 +29,13 @@ "$ref": "#/definitions/tasksRunnerOptions" } }, + "targetDefaults": { + "type": "object", + "description": "Target defaults", + "additionalProperties": { + "$ref": "#/definitions/targetDefaultsConfig" + } + }, "targetDependencies": { "type": "object", "description": "Dependencies between different target names across all projects.", @@ -106,22 +113,66 @@ }, "targetDependencyConfig": { "type": "array", - "description": "Target dependency.", "items": { - "type": "object", - "properties": { - "projects": { - "type": "string", - "description": "The projects that the targets belong to.", - "enum": ["self", "dependencies"] + "oneOf": [ + { + "type": "string" }, - "target": { - "type": "string", - "description": "The name of the target." + { + "type": "object", + "properties": { + "projects": { + "type": "string", + "description": "The projects that the targets belong to.", + "enum": ["self", "dependencies"] + }, + "target": { + "type": "string", + "description": "The name of the target." + } + }, + "additionalProperties": false } - }, - "additionalProperties": false + ] } + }, + "targetDefaultsConfig": { + "type": "object", + "description": "Target defaults", + "properties": { + "dependsOn": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "projects": { + "type": "string", + "description": "The projects that the targets belong to.", + "enum": ["self", "dependencies"] + }, + "target": { + "type": "string", + "description": "The name of the target." + } + }, + "additionalProperties": false + } + ] + } + }, + "outputs": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false } } } diff --git a/packages/nx/schemas/project-schema.json b/packages/nx/schemas/project-schema.json index e65afbc92a620..abd33c4f9e948 100644 --- a/packages/nx/schemas/project-schema.json +++ b/packages/nx/schemas/project-schema.json @@ -32,21 +32,27 @@ }, "dependsOn": { "type": "array", - "description": "Target dependency.", "items": { - "type": "object", - "properties": { - "projects": { - "type": "string", - "description": "The projects that the targets belong to.", - "enum": ["self", "dependencies"] + "oneOf": [ + { + "type": "string" }, - "target": { - "type": "string", - "description": "The name of the target." + { + "type": "object", + "properties": { + "projects": { + "type": "string", + "description": "The projects that the targets belong to.", + "enum": ["self", "dependencies"] + }, + "target": { + "type": "string", + "description": "The name of the target." + } + }, + "additionalProperties": false } - }, - "additionalProperties": false + ] } } } diff --git a/packages/nx/src/config/nx-json.ts b/packages/nx/src/config/nx-json.ts index afc796df49fe2..31c80410835ed 100644 --- a/packages/nx/src/config/nx-json.ts +++ b/packages/nx/src/config/nx-json.ts @@ -16,6 +16,19 @@ export interface NxAffectedConfig { defaultBase?: string; } +export type TargetDefaults = Record< + string, + { + outputs?: string[]; + dependsOn?: (TargetDependencyConfig | string)[]; + } +>; + +export type TargetDependencies = Record< + string, + (TargetDependencyConfig | string)[] +>; + /** * Nx.json configuration */ @@ -28,10 +41,15 @@ export interface NxJsonConfiguration { * Map of files to projects that implicitly depend on them */ implicitDependencies?: ImplicitDependencyEntry; + /** + * @deprecated use targetDefaults instead + * Dependencies between different target names across all projects + */ + targetDependencies?: TargetDependencies; /** * Dependencies between different target names across all projects */ - targetDependencies?: Record; + targetDefaults?: TargetDefaults; /** * NPM Scope that the workspace uses */ diff --git a/packages/nx/src/config/workspaces.ts b/packages/nx/src/config/workspaces.ts index ab908e7fc7a63..8440e6c4c0209 100644 --- a/packages/nx/src/config/workspaces.ts +++ b/packages/nx/src/config/workspaces.ts @@ -88,10 +88,37 @@ export class Workspaces { ); assertValidWorkspaceConfiguration(nxJson); - this.cachedWorkspaceConfig = { ...workspace, ...nxJson }; + this.cachedWorkspaceConfig = { + ...this.mergeTargetDefaultsIntoProjectDescriptions(workspace, nxJson), + ...nxJson, + }; return this.cachedWorkspaceConfig; } + private mergeTargetDefaultsIntoProjectDescriptions( + config: ProjectsConfigurations, + nxJson: NxJsonConfiguration + ) { + for (const proj of Object.values(config.projects)) { + if (proj.targets) { + for (const targetName of Object.keys(proj.targets)) { + if (nxJson.targetDefaults[targetName]) { + const projectTargetDefinition = proj.targets[targetName]; + if (!projectTargetDefinition.outputs) { + projectTargetDefinition.outputs = + nxJson.targetDefaults[targetName].outputs; + } + if (!projectTargetDefinition.dependsOn) { + projectTargetDefinition.dependsOn = + nxJson.targetDefaults[targetName].dependsOn; + } + } + } + } + } + return config; + } + isNxExecutor(nodeModule: string, executor: string) { const schema = this.readExecutor(nodeModule, executor).schema; return schema['cli'] === 'nx'; @@ -193,14 +220,17 @@ export class Workspaces { }); const baseNxJson = readJsonFile(extendedNxJsonPath); - return { ...baseNxJson, ...nxJsonConfig }; + return this.mergeTargetDefaultsAndTargetDependencies({ + ...baseNxJson, + ...nxJsonConfig, + }); } else { - return nxJsonConfig; + return this.mergeTargetDefaultsAndTargetDependencies(nxJsonConfig); } } else { try { - return readJsonFile( - join(__dirname, '..', '..', 'presets', 'core.json') + return this.mergeTargetDefaultsAndTargetDependencies( + readJsonFile(join(__dirname, '..', '..', 'presets', 'core.json')) ); } catch (e) { return {}; @@ -208,6 +238,29 @@ export class Workspaces { } } + private mergeTargetDefaultsAndTargetDependencies( + nxJson: NxJsonConfiguration + ) { + if (!nxJson.targetDefaults) { + nxJson.targetDefaults = {}; + } + if (nxJson.targetDependencies) { + for (const targetName of Object.keys(nxJson.targetDependencies)) { + if (!nxJson.targetDefaults[targetName]) { + nxJson.targetDefaults[targetName] = {}; + } + if (!nxJson.targetDefaults[targetName].dependsOn) { + nxJson.targetDefaults[targetName].dependsOn = []; + } + nxJson.targetDefaults[targetName].dependsOn = [ + ...nxJson.targetDefaults[targetName].dependsOn, + ...nxJson.targetDependencies[targetName], + ]; + } + } + return nxJson; + } + private getImplementationFactory( implementation: string, directory: string diff --git a/packages/nx/src/generators/utils/project-configuration.ts b/packages/nx/src/generators/utils/project-configuration.ts index 665faa7ea037b..5e7ff23091ae4 100644 --- a/packages/nx/src/generators/utils/project-configuration.ts +++ b/packages/nx/src/generators/utils/project-configuration.ts @@ -131,6 +131,7 @@ export function updateWorkspaceConfiguration( plugins, pluginsConfig, npmScope, + targetDefaults, targetDependencies, workspaceLayout, tasksRunnerOptions, @@ -143,6 +144,7 @@ export function updateWorkspaceConfiguration( plugins, pluginsConfig, npmScope, + targetDefaults, targetDependencies, workspaceLayout, tasksRunnerOptions, diff --git a/packages/nx/src/migrations/update-14-3-4/create-target-defaults.spec.ts b/packages/nx/src/migrations/update-14-3-4/create-target-defaults.spec.ts new file mode 100644 index 0000000000000..aa1cafa3bbafe --- /dev/null +++ b/packages/nx/src/migrations/update-14-3-4/create-target-defaults.spec.ts @@ -0,0 +1,38 @@ +import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; +import type { Tree } from '../../generators/tree'; +import { + readWorkspaceConfiguration, + updateWorkspaceConfiguration, +} from '../../generators/utils/project-configuration'; +import createTargetDefaults from 'nx/src/migrations/update-14-3-4/create-target-defaults'; + +describe('createTargetDefaults', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(2); + }); + + it('should work', async () => { + const config = readWorkspaceConfiguration(tree); + config.targetDependencies = { + a: [], + b: [ + 'bb', + { target: 'bbb', projects: 'self' }, + { target: 'c', projects: 'dependencies' }, + ], + }; + updateWorkspaceConfiguration(tree, config); + await createTargetDefaults(tree); + + const updated = readWorkspaceConfiguration(tree); + expect(updated.targetDefaults).toEqual({ + a: { dependsOn: [] }, + b: { + dependsOn: ['bb', 'bbb', '^c'], + }, + }); + expect(updated.targetDependencies).toBeUndefined(); + }); +}); diff --git a/packages/nx/src/migrations/update-14-3-4/create-target-defaults.ts b/packages/nx/src/migrations/update-14-3-4/create-target-defaults.ts new file mode 100644 index 0000000000000..5d5875e175b9b --- /dev/null +++ b/packages/nx/src/migrations/update-14-3-4/create-target-defaults.ts @@ -0,0 +1,37 @@ +import { Tree } from '../../generators/tree'; +import { + readWorkspaceConfiguration, + updateWorkspaceConfiguration, +} from '../../generators/utils/project-configuration'; +import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; + +export default async function (tree: Tree) { + const workspaceConfiguration = readWorkspaceConfiguration(tree); + + if (workspaceConfiguration.targetDependencies) { + workspaceConfiguration.targetDefaults = {}; + for (const targetName of Object.keys( + workspaceConfiguration.targetDependencies + )) { + const dependsOn = []; + + for (const c of workspaceConfiguration.targetDependencies[targetName]) { + if (typeof c === 'string') { + dependsOn.push(c); + } else if (c.projects === 'self') { + dependsOn.push(c.target); + } else { + dependsOn.push(`^${c.target}`); + } + } + + workspaceConfiguration.targetDefaults[targetName] = { + dependsOn, + }; + } + } + delete workspaceConfiguration.targetDependencies; + updateWorkspaceConfiguration(tree, workspaceConfiguration); + + await formatChangedFilesWithPrettierIfAvailable(tree); +} diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index b569045de2b3f..2926eeccb0d99 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -6,6 +6,7 @@ import { projectHasTargetAndConfiguration, } from '../utils/project-graph-utils'; import { Task, TaskGraph } from '../config/task-graph'; +import { TargetDependencies } from '../config/nx-json'; export class ProcessTasks { private readonly seen = new Set(); @@ -13,10 +14,7 @@ export class ProcessTasks { readonly dependencies: { [k: string]: string[] } = {}; constructor( - private readonly defaultDependencyConfigs: Record< - string, - (TargetDependencyConfig | string)[] - >, + private readonly defaultDependencyConfigs: TargetDependencies, private readonly projectGraph: ProjectGraph ) {} @@ -197,10 +195,7 @@ export class ProcessTasks { export function createTaskGraph( projectGraph: ProjectGraph, - defaultDependencyConfigs: Record< - string, - (TargetDependencyConfig | string)[] - > = {}, + defaultDependencyConfigs: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index 4c8e792018793..ca8a0b41d6c48 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -14,7 +14,11 @@ import { TaskProfilingLifeCycle } from './life-cycles/task-profiling-life-cycle' import { isCI } from '../utils/is-ci'; import { createRunOneDynamicOutputRenderer } from './life-cycles/dynamic-run-one-terminal-output-life-cycle'; import { ProjectGraph, ProjectGraphProjectNode } from '../config/project-graph'; -import { NxJsonConfiguration } from '../config/nx-json'; +import { + NxJsonConfiguration, + TargetDefaults, + TargetDependencies, +} from '../config/nx-json'; import { Task } from '../config/task-graph'; import { createTaskGraph } from './create-task-graph'; import { findCycle, makeAcyclic } from './task-graph-utils'; @@ -89,7 +93,7 @@ export async function runCommand( const { tasksRunner, runnerOptions } = getRunner(nxArgs, nxJson); const defaultDependencyConfigs = mergeTargetDependencies( - nxJson.targetDependencies, + nxJson.targetDefaults, extraTargetDependencies ); const projectNames = projectsToRun.map((t) => t.name); @@ -183,21 +187,19 @@ export async function runCommand( } function mergeTargetDependencies( - a: Record | null, - b: Record | null -): Record { + defaults: TargetDefaults, + deps: TargetDependencies +): TargetDependencies { const res = {}; - if (a) { - Object.keys(a).forEach((k) => { - res[k] = a[k]; - }); - } - if (b) { - Object.keys(b).forEach((k) => { + Object.keys(defaults).forEach((k) => { + res[k] = defaults[k].dependsOn; + }); + if (deps) { + Object.keys(deps).forEach((k) => { if (res[k]) { - res[k] = [...res[k], b[k]]; + res[k] = [...res[k], deps[k]]; } else { - res[k] = b[k]; + res[k] = deps[k]; } }); diff --git a/packages/nx/src/tasks-runner/utils.ts b/packages/nx/src/tasks-runner/utils.ts index 338ee34058353..3f57e823b1b4a 100644 --- a/packages/nx/src/tasks-runner/utils.ts +++ b/packages/nx/src/tasks-runner/utils.ts @@ -55,7 +55,11 @@ function expandDependencyConfigSyntaxSugar( ): TargetDependencyConfig[] { return deps.map((d) => { if (typeof d === 'string') { - return { projects: 'self', target: d }; + if (d.startsWith('^')) { + return { projects: 'dependencies', target: d.substring(1) }; + } else { + return { projects: 'self', target: d }; + } } else { return d; } diff --git a/packages/workspace/presets/core.json b/packages/workspace/presets/core.json index b77e169d8cede..b57cee16a5f20 100644 --- a/packages/workspace/presets/core.json +++ b/packages/workspace/presets/core.json @@ -7,12 +7,7 @@ ".eslintrc.json": "*" }, "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "build": ["^build"] }, "workspaceLayout": { "appsDir": "packages", diff --git a/packages/workspace/presets/npm.json b/packages/workspace/presets/npm.json index 727296550088f..060d46fc5db0f 100644 --- a/packages/workspace/presets/npm.json +++ b/packages/workspace/presets/npm.json @@ -7,12 +7,7 @@ ".eslintrc.json": "*" }, "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "build": ["^build"] }, "workspaceLayout": { "libsDir": "packages" diff --git a/packages/workspace/src/generators/new/__snapshots__/new.spec.ts.snap b/packages/workspace/src/generators/new/__snapshots__/new.spec.ts.snap index dfe793a03e4d1..06132c4e07582 100644 --- a/packages/workspace/src/generators/new/__snapshots__/new.spec.ts.snap +++ b/packages/workspace/src/generators/new/__snapshots__/new.spec.ts.snap @@ -83,13 +83,12 @@ Object { }, }, "npmScope": "npmScope", - "targetDependencies": Object { - "build": Array [ - Object { - "projects": "dependencies", - "target": "build", - }, - ], + "targetDefaults": Object { + "build": Object { + "dependsOn": Array [ + "^build", + ], + }, }, "tasksRunnerOptions": Object { "default": Object { diff --git a/packages/workspace/src/generators/workspace/files/nx.json__tmpl__ b/packages/workspace/src/generators/workspace/files/nx.json__tmpl__ index 6827f3726dd28..76914de80446a 100644 --- a/packages/workspace/src/generators/workspace/files/nx.json__tmpl__ +++ b/packages/workspace/src/generators/workspace/files/nx.json__tmpl__ @@ -6,7 +6,7 @@ }, <% if (packageManager && cli === 'angular') { -%> "cli": { - "packageManager": "<%=packageManager%>" + "packageManager": "<%=packageManager%>" }, <% } -%> "implicitDependencies": { @@ -24,12 +24,9 @@ } } }, - "targetDependencies": { - "build": [ - { - "target": "build", - "projects": "dependencies" - } - ] + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } } } diff --git a/packages/workspace/src/generators/workspace/workspace.spec.ts b/packages/workspace/src/generators/workspace/workspace.spec.ts index 56a44021c9dec..18049d6afe887 100644 --- a/packages/workspace/src/generators/workspace/workspace.spec.ts +++ b/packages/workspace/src/generators/workspace/workspace.spec.ts @@ -60,13 +60,10 @@ describe('@nrwl/workspace:workspace', () => { }, }, }, - targetDependencies: { - build: [ - { - projects: 'dependencies', - target: 'build', - }, - ], + targetDefaults: { + build: { + dependsOn: ['^build'], + }, }, }); const validateNxJson = ajv.compile(nxSchema); diff --git a/packages/workspace/src/generators/workspace/workspace.ts b/packages/workspace/src/generators/workspace/workspace.ts index 31ad14a17550e..8b56f34234179 100644 --- a/packages/workspace/src/generators/workspace/workspace.ts +++ b/packages/workspace/src/generators/workspace/workspace.ts @@ -36,6 +36,7 @@ function setPresetProperty(tree: Tree, options: Schema) { if (options.preset === Preset.Core || options.preset === Preset.NPM) { addPropertyWithStableKeys(json, 'extends', 'nx/presets/npm.json'); delete json.implicitDependencies; + delete json.targetDefaults; delete json.targetDependencies; delete json.workspaceLayout; } diff --git a/packages/workspace/src/utilities/buildable-libs-utils.ts b/packages/workspace/src/utilities/buildable-libs-utils.ts index 2cd6d3a844eb8..85b669a92e83c 100644 --- a/packages/workspace/src/utilities/buildable-libs-utils.ts +++ b/packages/workspace/src/utilities/buildable-libs-utils.ts @@ -217,7 +217,7 @@ export function checkDependentProjectsHaveBeenBuilt( It looks like all of ${projectName}'s dependencies have not been built yet: ${missing.map((x) => ` - ${x.node.name}`).join('\n')} - You might be missing a "targetDependencies" configuration in your root nx.json (https://nx.dev/configuration/packagejson#target-dependencies), + You might be missing a "targetDefaults" configuration in your root nx.json (https://nx.dev/configuration/packagejson#target-defaults), or "dependsOn" configured in ${projectName}'s angular.json/workspace.json record or project.json (https://nx.dev/configuration/packagejson#dependson) `); } else if (missing.length > 0) {