diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f7c7dbe3d5d4c..736deeab172a8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -13,6 +13,7 @@ env: jobs: build: + if: ${{ github.repository_owner == 'nrwl' }} strategy: fail-fast: false matrix: @@ -157,6 +158,7 @@ jobs: if-no-files-found: error build-freebsd: + if: ${{ github.repository_owner == 'nrwl' }} runs-on: macos-13-large name: Build FreeBSD timeout-minutes: 45 diff --git a/.nx/workflows/agents.yaml b/.nx/workflows/agents.yaml index 78913205228ca..e4c5dc8443016 100644 --- a/.nx/workflows/agents.yaml +++ b/.nx/workflows/agents.yaml @@ -1,7 +1,7 @@ launch-templates: linux-medium: resource-class: 'docker_linux_amd64/medium+' - image: 'ubuntu22.04-node20.9-withDind-v1' + image: 'ubuntu22.04-node20.9-v2' env: GIT_AUTHOR_EMAIL: test@test.com GIT_AUTHOR_NAME: Test diff --git a/.nx/workflows/dynamic-changesets.yaml b/.nx/workflows/dynamic-changesets.yaml index 46501c8bac7cd..0fc5d998c6fcf 100644 --- a/.nx/workflows/dynamic-changesets.yaml +++ b/.nx/workflows/dynamic-changesets.yaml @@ -1,4 +1,4 @@ -distributes-on: +distribute-on: small-changeset: 8 linux-medium medium-changeset: 10 linux-medium large-changeset: 12 linux-medium diff --git a/Cargo.lock b/Cargo.lock index aa12934578a58..be3481ce27efc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1561,6 +1561,7 @@ dependencies = [ "watchexec-events", "watchexec-filterer-ignore", "watchexec-signals", + "winapi", "xxhash-rust", ] diff --git a/community/approved-plugins.json b/community/approved-plugins.json index 1641a5695b5e4..c4867a26b3ae2 100644 --- a/community/approved-plugins.json +++ b/community/approved-plugins.json @@ -39,6 +39,11 @@ "description": "Nx plugin to generate a CDK stack with support for the vitest runner. Supports all CDK commands.", "url": "https://github.com/berenddeboer/nx-plugins/tree/main/packages/nx-aws-cdk" }, + { + "name": "@nx-iac/aws-cdk", + "description": "Empowers your Nx workspace with AWS CDK capabilities ⚡", + "url": "https://github.com/joelklint/nx-aws-cdk" + }, { "name": "@routineless/nx-aws-cdk", "description": "Nx plugin to generate and manage aws cdk app and lambdas.", @@ -279,6 +284,16 @@ "description": "Nx plugin for deploying your resources with Pulumi", "url": "https://github.com/tripss/nx-extend/tree/master/packages/pulumi" }, + { + "name": "@nx-extend/react-email", + "description": "Nx plugin for developing email templates with react.email", + "url": "https://github.com/tripss/nx-extend/tree/master/packages/react-email" + }, + { + "name": "@nx-extend/shadcn-ui", + "description": "Nx plugin for working with shadcn/ui", + "url": "https://github.com/tripss/nx-extend/tree/master/packages/shadcn-ui" + }, { "name": "@nativescript/nx", "description": "Nx Plugin adding first class support for NativeScript in your Nx workspace", diff --git a/docs/changelog/15_0_0.md b/docs/changelog/15_0_0.md index f7530c80a200c..efc6eb599a9de 100644 --- a/docs/changelog/15_0_0.md +++ b/docs/changelog/15_0_0.md @@ -11,7 +11,7 @@ width="100%" /%} ## Breaking Changes -Use [the `nx migrate` command](/core-features/automate-updating-dependencies) to automatically account for these breaking changes. +Use [the `nx migrate` command](/features/automate-updating-dependencies) to automatically account for these breaking changes. {% cards cols="1" smCols="2" mdCols="3" %} diff --git a/docs/changelog/16_0_0.md b/docs/changelog/16_0_0.md index ace3ea80aceff..3ef1f63ea9439 100644 --- a/docs/changelog/16_0_0.md +++ b/docs/changelog/16_0_0.md @@ -30,7 +30,7 @@ Here are some of our feature highlights: ## Breaking Changes -Use [the `nx migrate` command](/core-features/automate-updating-dependencies) to automatically account for these breaking changes. +Use [the `nx migrate` command](/features/automate-updating-dependencies) to automatically account for these breaking changes. {% cards cols="2" %} {% card title="Removed @nrwl/cypress/plugins/preprocessor" type="external" url="https://github.com/nrwl/nx/pull/16170" /%} diff --git a/docs/changelog/17_0_0.md b/docs/changelog/17_0_0.md index c706168603a3d..ef89492afd0a9 100644 --- a/docs/changelog/17_0_0.md +++ b/docs/changelog/17_0_0.md @@ -19,7 +19,7 @@ title="Nx 17.0 Has Landed!!!" ## Breaking Changes -Use [the `nx migrate` command](/core-features/automate-updating-dependencies) to automatically account for these breaking changes. +Use [the `nx migrate` command](/features/automate-updating-dependencies) to automatically account for these breaking changes. {% cards cols="2" %} {% card title="Rename @nx/linter to @nx/eslint" type="document" url="/recipes/other/rescope#rename" /%} diff --git a/docs/generated/cli/add.md b/docs/generated/cli/add.md index cc8e359234370..40b53cd2e18c5 100644 --- a/docs/generated/cli/add.md +++ b/docs/generated/cli/add.md @@ -53,7 +53,7 @@ The package name and optional version (e.g. `@nx/react` or `@nx/react@latest`) t Type: `boolean` -Update `package.json` scripts with inferred targets. Defaults to `true` when `NX_PCV3=true` and the package is a core Nx plugin +Update `package.json` scripts with inferred targets. Defaults to `true` when the package is a core Nx plugin ### verbose diff --git a/docs/generated/cli/init.md b/docs/generated/cli/init.md index f7489013bb241..c56f35d275066 100644 --- a/docs/generated/cli/init.md +++ b/docs/generated/cli/init.md @@ -17,36 +17,12 @@ Install `nx` globally to invoke the command directly using `nx`, or use `npx nx` ## Options -### addE2e - -Type: `boolean` - -Default: `false` - -Set up Cypress E2E tests in integrated workspaces. Only for CRA projects. - -### force - -Type: `boolean` - -Default: `false` - -Force the migration to continue and ignore custom webpack setup or uncommitted changes. Only for CRA projects. - ### help Type: `boolean` Show help -### integrated - -Type: `boolean` - -Default: `false` - -Migrate to an Nx integrated layout workspace. Only for Angular CLI workspaces and CRA projects. - ### interactive Type: `boolean` @@ -59,7 +35,7 @@ When false disables interactive input prompts for options. Type: `boolean` -Set up remote caching with Nx Cloud. +Set up distributed caching with Nx Cloud. ### useDotNxInstallation @@ -74,11 +50,3 @@ Initialize an Nx workspace setup in the .nx directory of the current repository. Type: `boolean` Show version number - -### vite - -Type: `boolean` - -Default: `true` - -Use Vite as the bundler. Only for CRA projects. diff --git a/docs/generated/manifests/ci.json b/docs/generated/manifests/ci.json index fd58a391954a2..fbbe669ccb76d 100644 --- a/docs/generated/manifests/ci.json +++ b/docs/generated/manifests/ci.json @@ -130,77 +130,88 @@ "mediaImage": "", "file": "", "itemList": [ + { + "id": "affected", + "name": "Run Only Tasks Affected by a PR", + "description": "", + "mediaImage": "", + "file": "shared/using-nx/affected", + "itemList": [], + "isExternal": false, + "path": "/ci/features/affected", + "tags": ["run-tasks"] + }, { "id": "remote-cache", - "name": "Use Remote Caching", + "name": "Use Remote Caching (Nx Replay)", "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", "mediaImage": "", - "file": "shared/core-features/remote-cache", + "file": "shared/features/remote-cache", "itemList": [], "isExternal": false, "path": "/ci/features/remote-cache", "tags": ["remote-cache"] }, { - "id": "affected", - "name": "Run Only Tasks Affected by a PR", - "description": "", + "id": "distribute-task-execution", + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", "mediaImage": "", - "file": "shared/using-nx/affected", + "file": "shared/features/distribute-task-execution", "itemList": [], "isExternal": false, - "path": "/ci/features/affected", - "tags": ["run-tasks"] + "path": "/ci/features/distribute-task-execution", + "tags": [] }, { - "id": "distribute-task-execution", - "name": "Distribute Task Execution", - "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Cloud has a built-in DTE mechanism which makes this a trivial task.", + "id": "dynamic-agents", + "name": "Dynamically Allocate Agents", + "description": "", "mediaImage": "", - "file": "shared/core-features/distribute-task-execution", + "file": "nx-cloud/features/dynamic-agents", "itemList": [], "isExternal": false, - "path": "/ci/features/distribute-task-execution", - "tags": ["distribute-task-execution"] + "path": "/ci/features/dynamic-agents", + "tags": [] }, { - "id": "on-premise", - "name": "Set up Nx Cloud On-Premise", - "description": "Set up Nx Cloud on machines that you control", + "id": "split-e2e-tasks", + "name": "Automatically Split E2E Tasks", + "description": "", "mediaImage": "", - "file": "nx-cloud/private/nx-enterprise-on-prem", + "file": "nx-cloud/features/split-e2e-tasks", "itemList": [], "isExternal": false, - "path": "/ci/features/on-premise", - "tags": ["on-premise"] + "path": "/ci/features/split-e2e-tasks", + "tags": [] }, { - "id": "nx-agents", - "name": "Nx Agents", + "id": "flaky-tasks", + "name": "Identify and Re-run Flaky Tasks", "description": "", "mediaImage": "", - "file": "nx-cloud/intro/nx-agents", + "file": "nx-cloud/features/flaky-tasks", "itemList": [], "isExternal": false, - "path": "/ci/features/nx-agents", + "path": "/ci/features/flaky-tasks", "tags": [] + }, + { + "id": "on-premise", + "name": "Set up Nx Cloud On-Premise", + "description": "Set up Nx Cloud on machines that you control", + "mediaImage": "", + "file": "nx-cloud/private/nx-enterprise-on-prem", + "itemList": [], + "isExternal": false, + "path": "/ci/features/on-premise", + "tags": ["on-premise"] } ], "isExternal": false, "path": "/ci/features", "tags": [] }, - "/ci/features/remote-cache": { - "id": "remote-cache", - "name": "Use Remote Caching", - "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", - "mediaImage": "", - "file": "shared/core-features/remote-cache", - "itemList": [], - "isExternal": false, - "path": "/ci/features/remote-cache", - "tags": ["remote-cache"] - }, "/ci/features/affected": { "id": "affected", "name": "Run Only Tasks Affected by a PR", @@ -212,16 +223,60 @@ "path": "/ci/features/affected", "tags": ["run-tasks"] }, + "/ci/features/remote-cache": { + "id": "remote-cache", + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", + "mediaImage": "", + "file": "shared/features/remote-cache", + "itemList": [], + "isExternal": false, + "path": "/ci/features/remote-cache", + "tags": ["remote-cache"] + }, "/ci/features/distribute-task-execution": { "id": "distribute-task-execution", - "name": "Distribute Task Execution", - "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Cloud has a built-in DTE mechanism which makes this a trivial task.", + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", "mediaImage": "", - "file": "shared/core-features/distribute-task-execution", + "file": "shared/features/distribute-task-execution", "itemList": [], "isExternal": false, "path": "/ci/features/distribute-task-execution", - "tags": ["distribute-task-execution"] + "tags": [] + }, + "/ci/features/dynamic-agents": { + "id": "dynamic-agents", + "name": "Dynamically Allocate Agents", + "description": "", + "mediaImage": "", + "file": "nx-cloud/features/dynamic-agents", + "itemList": [], + "isExternal": false, + "path": "/ci/features/dynamic-agents", + "tags": [] + }, + "/ci/features/split-e2e-tasks": { + "id": "split-e2e-tasks", + "name": "Automatically Split E2E Tasks", + "description": "", + "mediaImage": "", + "file": "nx-cloud/features/split-e2e-tasks", + "itemList": [], + "isExternal": false, + "path": "/ci/features/split-e2e-tasks", + "tags": [] + }, + "/ci/features/flaky-tasks": { + "id": "flaky-tasks", + "name": "Identify and Re-run Flaky Tasks", + "description": "", + "mediaImage": "", + "file": "nx-cloud/features/flaky-tasks", + "itemList": [], + "isExternal": false, + "path": "/ci/features/flaky-tasks", + "tags": [] }, "/ci/features/on-premise": { "id": "on-premise", @@ -234,17 +289,6 @@ "path": "/ci/features/on-premise", "tags": ["on-premise"] }, - "/ci/features/nx-agents": { - "id": "nx-agents", - "name": "Nx Agents", - "description": "", - "mediaImage": "", - "file": "nx-cloud/intro/nx-agents", - "itemList": [], - "isExternal": false, - "path": "/ci/features/nx-agents", - "tags": [] - }, "/ci/concepts": { "id": "concepts", "name": "Concepts", @@ -359,6 +403,17 @@ "mediaImage": "", "file": "", "itemList": [ + { + "id": "connect-to-cloud", + "name": "Connect Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/recipes/connect-to-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/set-up/connect-to-cloud", + "tags": [] + }, { "id": "monorepo-ci-azure", "name": "Setting up Azure Pipelines", @@ -666,6 +721,17 @@ "mediaImage": "", "file": "", "itemList": [ + { + "id": "connect-to-cloud", + "name": "Connect Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/recipes/connect-to-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/set-up/connect-to-cloud", + "tags": [] + }, { "id": "monorepo-ci-azure", "name": "Setting up Azure Pipelines", @@ -737,6 +803,17 @@ "path": "/ci/recipes/set-up", "tags": ["distribute-task-execution"] }, + "/ci/recipes/set-up/connect-to-cloud": { + "id": "connect-to-cloud", + "name": "Connect Nx Cloud", + "description": "", + "mediaImage": "", + "file": "nx-cloud/recipes/connect-to-cloud", + "itemList": [], + "isExternal": false, + "path": "/ci/recipes/set-up/connect-to-cloud", + "tags": [] + }, "/ci/recipes/set-up/monorepo-ci-azure": { "id": "monorepo-ci-azure", "name": "Setting up Azure Pipelines", @@ -1232,6 +1309,17 @@ "path": "/ci/reference/nx-cloud-cli", "tags": [] }, + { + "id": "launch-templates", + "name": "Launch Templates", + "description": "", + "mediaImage": "", + "file": "nx-cloud/reference/launch-templates", + "itemList": [], + "isExternal": false, + "path": "/ci/reference/launch-templates", + "tags": [] + }, { "id": "env-vars", "name": "Environment Variables", @@ -1292,6 +1380,17 @@ "path": "/ci/reference/nx-cloud-cli", "tags": [] }, + "/ci/reference/launch-templates": { + "id": "launch-templates", + "name": "Launch Templates", + "description": "", + "mediaImage": "", + "file": "nx-cloud/reference/launch-templates", + "itemList": [], + "isExternal": false, + "path": "/ci/reference/launch-templates", + "tags": [] + }, "/ci/reference/env-vars": { "id": "env-vars", "name": "Environment Variables", diff --git a/docs/generated/manifests/extending-nx.json b/docs/generated/manifests/extending-nx.json index 5c97d566392f2..675a2b0c1e28f 100644 --- a/docs/generated/manifests/extending-nx.json +++ b/docs/generated/manifests/extending-nx.json @@ -105,7 +105,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/local-executors", - "tags": ["use-task-executors"] + "tags": [] }, { "id": "compose-executors", @@ -116,7 +116,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/compose-executors", - "tags": ["use-task-executors"] + "tags": [] }, { "id": "local-generators", @@ -127,7 +127,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/local-generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "composing-generators", @@ -138,7 +138,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/composing-generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "generator-options", @@ -149,7 +149,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/generator-options", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "creating-files", @@ -160,7 +160,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/creating-files", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "modifying-files", @@ -171,7 +171,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/modifying-files", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "migration-generators", @@ -231,7 +231,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/local-executors", - "tags": ["use-task-executors"] + "tags": [] }, "/extending-nx/recipes/compose-executors": { "id": "compose-executors", @@ -242,7 +242,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/compose-executors", - "tags": ["use-task-executors"] + "tags": [] }, "/extending-nx/recipes/local-generators": { "id": "local-generators", @@ -253,7 +253,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/local-generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/extending-nx/recipes/composing-generators": { "id": "composing-generators", @@ -264,7 +264,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/composing-generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/extending-nx/recipes/generator-options": { "id": "generator-options", @@ -275,7 +275,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/generator-options", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/extending-nx/recipes/creating-files": { "id": "creating-files", @@ -286,7 +286,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/creating-files", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/extending-nx/recipes/modifying-files": { "id": "modifying-files", @@ -297,7 +297,7 @@ "itemList": [], "isExternal": false, "path": "/extending-nx/recipes/modifying-files", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/extending-nx/recipes/migration-generators": { "id": "migration-generators", diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index 6c1c21751597f..2d534e0a23173 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -93,14 +93,6 @@ "isExternal": false, "children": [], "disableCollapsible": false - }, - { - "name": "Node Standalone", - "path": "/getting-started/tutorials/node-server-tutorial", - "id": "node-server-tutorial", - "isExternal": false, - "children": [], - "disableCollapsible": false } ], "disableCollapsible": false @@ -193,14 +185,6 @@ "isExternal": false, "children": [], "disableCollapsible": false - }, - { - "name": "Node Standalone", - "path": "/getting-started/tutorials/node-server-tutorial", - "id": "node-server-tutorial", - "isExternal": false, - "children": [], - "disableCollapsible": false } ], "disableCollapsible": false @@ -261,14 +245,6 @@ "children": [], "disableCollapsible": false }, - { - "name": "Node Standalone", - "path": "/getting-started/tutorials/node-server-tutorial", - "id": "node-server-tutorial", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, { "name": "Core Tutorial", "path": "/core-tutorial", @@ -375,223 +351,223 @@ "disableCollapsible": false }, { - "name": "Angular Standalone Tutorial", - "path": "/angular-standalone-tutorial", - "id": "angular-standalone-tutorial", + "name": "Features", + "path": "/features", + "id": "features", "isExternal": false, "children": [ { - "name": "1 - Code Generation", - "path": "/angular-standalone-tutorial/1-code-generation", - "id": "1-code-generation", + "name": "Run Tasks", + "path": "/features/run-tasks", + "id": "run-tasks", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "2 - Project Graph", - "path": "/angular-standalone-tutorial/2-project-graph", - "id": "2-project-graph", + "name": "Cache Task Results", + "path": "/features/cache-task-results", + "id": "cache-task-results", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "3 - Task Running", - "path": "/angular-standalone-tutorial/3-task-running", - "id": "3-task-running", + "name": "Explore your Workspace", + "path": "/features/explore-graph", + "id": "explore-graph", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "4 - Task Pipelines", - "path": "/angular-standalone-tutorial/4-task-pipelines", - "id": "4-task-pipelines", + "name": "Generate Code", + "path": "/features/generate-code", + "id": "generate-code", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "5 - Summary", - "path": "/angular-standalone-tutorial/5-summary", - "id": "5-summary", - "isExternal": false, - "children": [], - "disableCollapsible": false - } - ], - "disableCollapsible": false - }, - { - "name": "1 - Code Generation", - "path": "/angular-standalone-tutorial/1-code-generation", - "id": "1-code-generation", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "2 - Project Graph", - "path": "/angular-standalone-tutorial/2-project-graph", - "id": "2-project-graph", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "3 - Task Running", - "path": "/angular-standalone-tutorial/3-task-running", - "id": "3-task-running", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "4 - Task Pipelines", - "path": "/angular-standalone-tutorial/4-task-pipelines", - "id": "4-task-pipelines", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "5 - Summary", - "path": "/angular-standalone-tutorial/5-summary", - "id": "5-summary", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Node Server Tutorial", - "path": "/node-server-tutorial", - "id": "node-server-tutorial", - "isExternal": false, - "children": [ - { - "name": "1 - Code Generation", - "path": "/node-server-tutorial/1-code-generation", - "id": "1-code-generation", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "2 - Project Graph", - "path": "/node-server-tutorial/2-project-graph", - "id": "2-project-graph", + "name": "Automate Updating Dependencies", + "path": "/features/automate-updating-dependencies", + "id": "automate-updating-dependencies", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "3 - Task Running", - "path": "/node-server-tutorial/3-task-running", - "id": "3-task-running", + "name": "Enforce Module Boundaries", + "path": "/features/enforce-module-boundaries", + "id": "enforce-module-boundaries", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "4 - Task Pipelines", - "path": "/node-server-tutorial/4-task-pipelines", - "id": "4-task-pipelines", + "name": "Integrate with Editors", + "path": "/features/integrate-with-editors", + "id": "integrate-with-editors", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "5 - Docker Target", - "path": "/node-server-tutorial/5-docker-target", - "id": "5-docker-target", + "name": "Manage Releases", + "path": "/features/manage-releases", + "id": "manage-releases", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "6 - Summary", - "path": "/node-server-tutorial/6-summary", - "id": "6-summary", + "name": "CI Features", + "path": "/features/ci-features", + "id": "ci-features", "isExternal": false, - "children": [], + "children": [ + { + "name": "Run Only Tasks Affected by a PR", + "path": "/ci/features/affected", + "id": "affected", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Use Remote Caching (Nx Replay)", + "path": "/ci/features/remote-cache", + "id": "remote-cache", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Distribute Task Execution (Nx Agents)", + "path": "/ci/features/distribute-task-execution", + "id": "distribute-task-execution", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Dynamically Allocate Agents", + "path": "/ci/features/dynamic-agents", + "id": "dynamic-agents", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Automatically Split E2E Tasks", + "path": "/ci/features/split-e2e-tasks", + "id": "split-e2e-tasks", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Identify and Re-run Flaky Tasks", + "path": "/ci/features/flaky-tasks", + "id": "flaky-tasks", + "isExternal": true, + "children": [], + "disableCollapsible": false + }, + { + "name": "Set up Nx Cloud On-Premise", + "path": "/ci/features/on-premise", + "id": "on-premise", + "isExternal": true, + "children": [], + "disableCollapsible": false + } + ], "disableCollapsible": false } ], "disableCollapsible": false }, { - "name": "1 - Code Generation", - "path": "/node-server-tutorial/1-code-generation", - "id": "1-code-generation", + "name": "Run Tasks", + "path": "/features/run-tasks", + "id": "run-tasks", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "2 - Project Graph", - "path": "/node-server-tutorial/2-project-graph", - "id": "2-project-graph", + "name": "Cache Task Results", + "path": "/features/cache-task-results", + "id": "cache-task-results", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "3 - Task Running", - "path": "/node-server-tutorial/3-task-running", - "id": "3-task-running", + "name": "Explore your Workspace", + "path": "/features/explore-graph", + "id": "explore-graph", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "4 - Task Pipelines", - "path": "/node-server-tutorial/4-task-pipelines", - "id": "4-task-pipelines", + "name": "Generate Code", + "path": "/features/generate-code", + "id": "generate-code", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "5 - Docker Target", - "path": "/node-server-tutorial/5-docker-target", - "id": "5-docker-target", + "name": "Automate Updating Dependencies", + "path": "/features/automate-updating-dependencies", + "id": "automate-updating-dependencies", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "6 - Summary", - "path": "/node-server-tutorial/6-summary", - "id": "6-summary", + "name": "Enforce Module Boundaries", + "path": "/features/enforce-module-boundaries", + "id": "enforce-module-boundaries", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Integrate with Editors", + "path": "/features/integrate-with-editors", + "id": "integrate-with-editors", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Manage Releases", + "path": "/features/manage-releases", + "id": "manage-releases", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Core Features", - "path": "/core-features", - "id": "core-features", + "name": "CI Features", + "path": "/features/ci-features", + "id": "ci-features", "isExternal": false, "children": [ { - "name": "Run Tasks", - "path": "/core-features/run-tasks", - "id": "run-tasks", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Cache Task Results", - "path": "/core-features/cache-task-results", - "id": "cache-task-results", - "isExternal": false, + "name": "Run Only Tasks Affected by a PR", + "path": "/ci/features/affected", + "id": "affected", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Use Remote Caching", + "name": "Use Remote Caching (Nx Replay)", "path": "/ci/features/remote-cache", "id": "remote-cache", "isExternal": true, @@ -599,7 +575,7 @@ "disableCollapsible": false }, { - "name": "Distribute Task Execution", + "name": "Distribute Task Execution (Nx Agents)", "path": "/ci/features/distribute-task-execution", "id": "distribute-task-execution", "isExternal": true, @@ -607,91 +583,50 @@ "disableCollapsible": false }, { - "name": "Explore the Graph", - "path": "/core-features/explore-graph", - "id": "explore-graph", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Automate Updating Dependencies", - "path": "/core-features/automate-updating-dependencies", - "id": "automate-updating-dependencies", - "isExternal": false, + "name": "Dynamically Allocate Agents", + "path": "/ci/features/dynamic-agents", + "id": "dynamic-agents", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Enforce Module Boundaries", - "path": "/core-features/enforce-module-boundaries", - "id": "enforce-module-boundaries", - "isExternal": false, + "name": "Automatically Split E2E Tasks", + "path": "/ci/features/split-e2e-tasks", + "id": "split-e2e-tasks", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Integrate with Editors", - "path": "/core-features/integrate-with-editors", - "id": "integrate-with-editors", - "isExternal": false, + "name": "Identify and Re-run Flaky Tasks", + "path": "/ci/features/flaky-tasks", + "id": "flaky-tasks", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Manage Releases", - "path": "/core-features/manage-releases", - "id": "manage-releases", - "isExternal": false, + "name": "Set up Nx Cloud On-Premise", + "path": "/ci/features/on-premise", + "id": "on-premise", + "isExternal": true, "children": [], "disableCollapsible": false - }, - { - "name": "Plugin Features", - "path": "/core-features/plugin-features", - "id": "plugin-features", - "isExternal": false, - "children": [ - { - "name": "Use Task Executors", - "path": "/core-features/plugin-features/use-task-executors", - "id": "use-task-executors", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Use Code Generators", - "path": "/core-features/plugin-features/use-code-generators", - "id": "use-code-generators", - "isExternal": false, - "children": [], - "disableCollapsible": false - } - ], - "disableCollapsible": false } ], "disableCollapsible": false }, { - "name": "Run Tasks", - "path": "/core-features/run-tasks", - "id": "run-tasks", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Cache Task Results", - "path": "/core-features/cache-task-results", - "id": "cache-task-results", - "isExternal": false, + "name": "Run Only Tasks Affected by a PR", + "path": "/ci/features/affected", + "id": "affected", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Use Remote Caching", + "name": "Use Remote Caching (Nx Replay)", "path": "/ci/features/remote-cache", "id": "remote-cache", "isExternal": true, @@ -699,7 +634,7 @@ "disableCollapsible": false }, { - "name": "Distribute Task Execution", + "name": "Distribute Task Execution (Nx Agents)", "path": "/ci/features/distribute-task-execution", "id": "distribute-task-execution", "isExternal": true, @@ -707,83 +642,34 @@ "disableCollapsible": false }, { - "name": "Explore the Graph", - "path": "/core-features/explore-graph", - "id": "explore-graph", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Automate Updating Dependencies", - "path": "/core-features/automate-updating-dependencies", - "id": "automate-updating-dependencies", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Enforce Module Boundaries", - "path": "/core-features/enforce-module-boundaries", - "id": "enforce-module-boundaries", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Integrate with Editors", - "path": "/core-features/integrate-with-editors", - "id": "integrate-with-editors", - "isExternal": false, + "name": "Dynamically Allocate Agents", + "path": "/ci/features/dynamic-agents", + "id": "dynamic-agents", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Manage Releases", - "path": "/core-features/manage-releases", - "id": "manage-releases", - "isExternal": false, + "name": "Automatically Split E2E Tasks", + "path": "/ci/features/split-e2e-tasks", + "id": "split-e2e-tasks", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Plugin Features", - "path": "/core-features/plugin-features", - "id": "plugin-features", - "isExternal": false, - "children": [ - { - "name": "Use Task Executors", - "path": "/core-features/plugin-features/use-task-executors", - "id": "use-task-executors", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, - { - "name": "Use Code Generators", - "path": "/core-features/plugin-features/use-code-generators", - "id": "use-code-generators", - "isExternal": false, - "children": [], - "disableCollapsible": false - } - ], - "disableCollapsible": false - }, - { - "name": "Use Task Executors", - "path": "/core-features/plugin-features/use-task-executors", - "id": "use-task-executors", - "isExternal": false, + "name": "Identify and Re-run Flaky Tasks", + "path": "/ci/features/flaky-tasks", + "id": "flaky-tasks", + "isExternal": true, "children": [], "disableCollapsible": false }, { - "name": "Use Code Generators", - "path": "/core-features/plugin-features/use-code-generators", - "id": "use-code-generators", - "isExternal": false, + "name": "Set up Nx Cloud On-Premise", + "path": "/ci/features/on-premise", + "id": "on-premise", + "isExternal": true, "children": [], "disableCollapsible": false }, @@ -809,6 +695,30 @@ "children": [], "disableCollapsible": false }, + { + "name": "What is a Task Pipeline", + "path": "/concepts/task-pipeline-configuration", + "id": "task-pipeline-configuration", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "What Are Nx Plugins", + "path": "/concepts/nx-plugins", + "id": "nx-plugins", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Inferred Tasks", + "path": "/concepts/inferred-tasks", + "id": "inferred-tasks", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Types of Configuration", "path": "/concepts/types-of-configuration", @@ -818,9 +728,9 @@ "disableCollapsible": false }, { - "name": "What is a Task Pipeline", - "path": "/concepts/task-pipeline-configuration", - "id": "task-pipeline-configuration", + "name": "Executors and Configurations", + "path": "/concepts/executors-and-configurations", + "id": "executors-and-configurations", "isExternal": false, "children": [], "disableCollapsible": false @@ -1038,6 +948,30 @@ "children": [], "disableCollapsible": false }, + { + "name": "What is a Task Pipeline", + "path": "/concepts/task-pipeline-configuration", + "id": "task-pipeline-configuration", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "What Are Nx Plugins", + "path": "/concepts/nx-plugins", + "id": "nx-plugins", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Inferred Tasks", + "path": "/concepts/inferred-tasks", + "id": "inferred-tasks", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Types of Configuration", "path": "/concepts/types-of-configuration", @@ -1047,9 +981,9 @@ "disableCollapsible": false }, { - "name": "What is a Task Pipeline", - "path": "/concepts/task-pipeline-configuration", - "id": "task-pipeline-configuration", + "name": "Executors and Configurations", + "path": "/concepts/executors-and-configurations", + "id": "executors-and-configurations", "isExternal": false, "children": [], "disableCollapsible": false @@ -1429,15 +1363,23 @@ "isExternal": false, "children": [ { - "name": "Fine-tuning Caching with Inputs", - "path": "/recipes/running-tasks/customizing-inputs", - "id": "customizing-inputs", + "name": "Configure Inputs for Task Caching", + "path": "/recipes/running-tasks/configure-inputs", + "id": "configure-inputs", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Configure Outputs for Task Caching", + "path": "/recipes/running-tasks/configure-outputs", + "id": "configure-outputs", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "path": "/recipes/running-tasks/defining-task-pipeline", "id": "defining-task-pipeline", "isExternal": false, @@ -1453,7 +1395,7 @@ "disableCollapsible": false }, { - "name": "Running Custom Commands", + "name": "Run Custom Commands", "path": "/recipes/running-tasks/run-commands-executor", "id": "run-commands-executor", "isExternal": false, @@ -1525,14 +1467,6 @@ "children": [], "disableCollapsible": false }, - { - "name": "Nx and Lerna", - "path": "/recipes/adopting-nx/lerna-and-nx", - "id": "lerna-and-nx", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, { "name": "Preserving Git Histories", "path": "/recipes/adopting-nx/preserving-git-histories", @@ -1993,7 +1927,7 @@ "isExternal": false, "children": [ { - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "path": "/recipes/webpack/webpack-config-setup", "id": "webpack-config-setup", "isExternal": false, @@ -2326,6 +2260,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Project Details View", + "path": "/recipes/nx-console/console-project-details", + "id": "console-project-details", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Generate Command", "path": "/recipes/nx-console/console-generate-command", @@ -2445,15 +2387,23 @@ "isExternal": false, "children": [ { - "name": "Fine-tuning Caching with Inputs", - "path": "/recipes/running-tasks/customizing-inputs", - "id": "customizing-inputs", + "name": "Configure Inputs for Task Caching", + "path": "/recipes/running-tasks/configure-inputs", + "id": "configure-inputs", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Configure Outputs for Task Caching", + "path": "/recipes/running-tasks/configure-outputs", + "id": "configure-outputs", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "path": "/recipes/running-tasks/defining-task-pipeline", "id": "defining-task-pipeline", "isExternal": false, @@ -2469,7 +2419,7 @@ "disableCollapsible": false }, { - "name": "Running Custom Commands", + "name": "Run Custom Commands", "path": "/recipes/running-tasks/run-commands-executor", "id": "run-commands-executor", "isExternal": false, @@ -2512,15 +2462,23 @@ "disableCollapsible": false }, { - "name": "Fine-tuning Caching with Inputs", - "path": "/recipes/running-tasks/customizing-inputs", - "id": "customizing-inputs", + "name": "Configure Inputs for Task Caching", + "path": "/recipes/running-tasks/configure-inputs", + "id": "configure-inputs", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Defining a Task Pipeline", + "name": "Configure Outputs for Task Caching", + "path": "/recipes/running-tasks/configure-outputs", + "id": "configure-outputs", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Define a Task Pipeline", "path": "/recipes/running-tasks/defining-task-pipeline", "id": "defining-task-pipeline", "isExternal": false, @@ -2536,7 +2494,7 @@ "disableCollapsible": false }, { - "name": "Running Custom Commands", + "name": "Run Custom Commands", "path": "/recipes/running-tasks/run-commands-executor", "id": "run-commands-executor", "isExternal": false, @@ -2605,14 +2563,6 @@ "children": [], "disableCollapsible": false }, - { - "name": "Nx and Lerna", - "path": "/recipes/adopting-nx/lerna-and-nx", - "id": "lerna-and-nx", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, { "name": "Preserving Git Histories", "path": "/recipes/adopting-nx/preserving-git-histories", @@ -2656,14 +2606,6 @@ "children": [], "disableCollapsible": false }, - { - "name": "Nx and Lerna", - "path": "/recipes/adopting-nx/lerna-and-nx", - "id": "lerna-and-nx", - "isExternal": false, - "children": [], - "disableCollapsible": false - }, { "name": "Preserving Git Histories", "path": "/recipes/adopting-nx/preserving-git-histories", @@ -3506,7 +3448,7 @@ "isExternal": false, "children": [ { - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "path": "/recipes/webpack/webpack-config-setup", "id": "webpack-config-setup", "isExternal": false, @@ -3525,7 +3467,7 @@ "disableCollapsible": false }, { - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "path": "/recipes/webpack/webpack-config-setup", "id": "webpack-config-setup", "isExternal": false, @@ -4111,6 +4053,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Project Details View", + "path": "/recipes/nx-console/console-project-details", + "id": "console-project-details", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Generate Command", "path": "/recipes/nx-console/console-generate-command", @@ -4170,6 +4120,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Project Details View", + "path": "/recipes/nx-console/console-project-details", + "id": "console-project-details", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Generate Command", "path": "/recipes/nx-console/console-generate-command", @@ -4847,6 +4805,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Inputs and Named Inputs", + "path": "/reference/inputs", + "id": "inputs", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": ".nxignore", "path": "/reference/nxignore", @@ -4898,6 +4864,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Inputs and Named Inputs", + "path": "/reference/inputs", + "id": "inputs", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": ".nxignore", "path": "/reference/nxignore", @@ -4984,6 +4958,22 @@ "children": [], "disableCollapsible": false }, + { + "name": "cacheableOperations", + "path": "/deprecated/cacheable-operations", + "id": "cacheable-operations", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "npmScope", + "path": "/deprecated/npm-scope", + "id": "npm-scope", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "globalImplicitDependencies", "path": "/deprecated/global-implicit-dependencies", @@ -5124,6 +5114,22 @@ "children": [], "disableCollapsible": false }, + { + "name": "cacheableOperations", + "path": "/deprecated/cacheable-operations", + "id": "cacheable-operations", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "npmScope", + "path": "/deprecated/npm-scope", + "id": "npm-scope", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "globalImplicitDependencies", "path": "/deprecated/global-implicit-dependencies", @@ -5741,23 +5747,23 @@ "isExternal": false, "children": [ { - "name": "Use Remote Caching", - "path": "/ci/features/remote-cache", - "id": "remote-cache", + "name": "Run Only Tasks Affected by a PR", + "path": "/ci/features/affected", + "id": "affected", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Run Only Tasks Affected by a PR", - "path": "/ci/features/affected", - "id": "affected", + "name": "Use Remote Caching (Nx Replay)", + "path": "/ci/features/remote-cache", + "id": "remote-cache", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Distribute Task Execution", + "name": "Distribute Task Execution (Nx Agents)", "path": "/ci/features/distribute-task-execution", "id": "distribute-task-execution", "isExternal": false, @@ -5765,17 +5771,33 @@ "disableCollapsible": false }, { - "name": "Set up Nx Cloud On-Premise", - "path": "/ci/features/on-premise", - "id": "on-premise", + "name": "Dynamically Allocate Agents", + "path": "/ci/features/dynamic-agents", + "id": "dynamic-agents", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Automatically Split E2E Tasks", + "path": "/ci/features/split-e2e-tasks", + "id": "split-e2e-tasks", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Identify and Re-run Flaky Tasks", + "path": "/ci/features/flaky-tasks", + "id": "flaky-tasks", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Nx Agents", - "path": "/ci/features/nx-agents", - "id": "nx-agents", + "name": "Set up Nx Cloud On-Premise", + "path": "/ci/features/on-premise", + "id": "on-premise", "isExternal": false, "children": [], "disableCollapsible": false @@ -5784,23 +5806,23 @@ "disableCollapsible": false }, { - "name": "Use Remote Caching", - "path": "/ci/features/remote-cache", - "id": "remote-cache", + "name": "Run Only Tasks Affected by a PR", + "path": "/ci/features/affected", + "id": "affected", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Run Only Tasks Affected by a PR", - "path": "/ci/features/affected", - "id": "affected", + "name": "Use Remote Caching (Nx Replay)", + "path": "/ci/features/remote-cache", + "id": "remote-cache", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Distribute Task Execution", + "name": "Distribute Task Execution (Nx Agents)", "path": "/ci/features/distribute-task-execution", "id": "distribute-task-execution", "isExternal": false, @@ -5808,17 +5830,33 @@ "disableCollapsible": false }, { - "name": "Set up Nx Cloud On-Premise", - "path": "/ci/features/on-premise", - "id": "on-premise", + "name": "Dynamically Allocate Agents", + "path": "/ci/features/dynamic-agents", + "id": "dynamic-agents", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Automatically Split E2E Tasks", + "path": "/ci/features/split-e2e-tasks", + "id": "split-e2e-tasks", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, + { + "name": "Identify and Re-run Flaky Tasks", + "path": "/ci/features/flaky-tasks", + "id": "flaky-tasks", "isExternal": false, "children": [], "disableCollapsible": false }, { - "name": "Nx Agents", - "path": "/ci/features/nx-agents", - "id": "nx-agents", + "name": "Set up Nx Cloud On-Premise", + "path": "/ci/features/on-premise", + "id": "on-premise", "isExternal": false, "children": [], "disableCollapsible": false @@ -5908,6 +5946,14 @@ "id": "set-up", "isExternal": false, "children": [ + { + "name": "Connect Nx Cloud", + "path": "/ci/recipes/set-up/connect-to-cloud", + "id": "connect-to-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Setting up Azure Pipelines", "path": "/ci/recipes/set-up/monorepo-ci-azure", @@ -6132,6 +6178,14 @@ "id": "set-up", "isExternal": false, "children": [ + { + "name": "Connect Nx Cloud", + "path": "/ci/recipes/set-up/connect-to-cloud", + "id": "connect-to-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Setting up Azure Pipelines", "path": "/ci/recipes/set-up/monorepo-ci-azure", @@ -6183,6 +6237,14 @@ ], "disableCollapsible": false }, + { + "name": "Connect Nx Cloud", + "path": "/ci/recipes/set-up/connect-to-cloud", + "id": "connect-to-cloud", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Setting up Azure Pipelines", "path": "/ci/recipes/set-up/monorepo-ci-azure", @@ -6545,6 +6607,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Launch Templates", + "path": "/ci/reference/launch-templates", + "id": "launch-templates", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Environment Variables", "path": "/ci/reference/env-vars", @@ -6588,6 +6658,14 @@ "children": [], "disableCollapsible": false }, + { + "name": "Launch Templates", + "path": "/ci/reference/launch-templates", + "id": "launch-templates", + "isExternal": false, + "children": [], + "disableCollapsible": false + }, { "name": "Environment Variables", "path": "/ci/reference/env-vars", @@ -9284,14 +9362,6 @@ "children": [], "isExternal": false, "disableCollapsible": false - }, - { - "id": "cypress", - "path": "/nx-api/remix/generators/cypress", - "name": "cypress", - "children": [], - "isExternal": false, - "disableCollapsible": false } ], "isExternal": false, diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index db5d044cb95e7..18f1ebd80f917 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -95,7 +95,7 @@ "type": "executor" }, "/nx-api/angular/executors/dev-server": { - "description": "The `dev-server` executor is very similar to the standard `dev-server` builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration.", + "description": "Serves an Angular application using [Webpack](https://webpack.js.org/) when the build target is using a Webpack-based executor, or [Vite](https://vitejs.dev/) when the build target uses an esbuild-based executor.", "file": "generated/packages/angular/executors/dev-server.json", "hidden": false, "name": "dev-server", @@ -917,7 +917,7 @@ }, "generators": { "/nx-api/expo/generators/init": { - "description": "Initialize the @nrwl/expo plugin", + "description": "Initialize the @nx/expo plugin", "file": "generated/packages/expo/generators/init.json", "hidden": true, "name": "init", @@ -1628,7 +1628,7 @@ "itemList": [], "isExternal": false, "path": "/nx-api/nx/documents/generate", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "originalFilePath": "generated/cli/generate" }, "/nx-api/nx/documents/run": { @@ -1639,7 +1639,7 @@ "itemList": [], "isExternal": false, "path": "/nx-api/nx/documents/run", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/run" }, "/nx-api/nx/documents/daemon": { @@ -1672,7 +1672,7 @@ "itemList": [], "isExternal": false, "path": "/nx-api/nx/documents/run-many", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/run-many" }, "/nx-api/nx/documents/affected": { @@ -1683,7 +1683,7 @@ "itemList": [], "isExternal": false, "path": "/nx-api/nx/documents/affected", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/affected" }, "/nx-api/nx/documents/affected-dep-graph": { @@ -2645,15 +2645,6 @@ "originalFilePath": "/packages/remix/src/generators/error-boundary/schema.json", "path": "/nx-api/remix/generators/error-boundary", "type": "generator" - }, - "/nx-api/remix/generators/cypress": { - "description": "Generate a project for testing Remix apps using Cypress", - "file": "generated/packages/remix/generators/cypress.json", - "hidden": false, - "name": "cypress", - "originalFilePath": "/packages/remix/src/generators/cypress/schema.json", - "path": "/nx-api/remix/generators/cypress", - "type": "generator" } }, "path": "/nx-api/remix" diff --git a/docs/generated/manifests/nx.json b/docs/generated/manifests/nx.json index e0560de47010b..af5fbc4210bb5 100644 --- a/docs/generated/manifests/nx.json +++ b/docs/generated/manifests/nx.json @@ -122,17 +122,6 @@ "isExternal": false, "path": "/getting-started/tutorials/vue-standalone-tutorial", "tags": [] - }, - { - "id": "node-server-tutorial", - "name": "Node Standalone", - "description": "", - "mediaImage": "", - "file": "shared/node-server-tutorial/1-code-generation", - "itemList": [], - "isExternal": false, - "path": "/getting-started/tutorials/node-server-tutorial", - "tags": [] } ], "isExternal": false, @@ -260,17 +249,6 @@ "isExternal": false, "path": "/getting-started/tutorials/vue-standalone-tutorial", "tags": [] - }, - { - "id": "node-server-tutorial", - "name": "Node Standalone", - "description": "", - "mediaImage": "", - "file": "shared/node-server-tutorial/1-code-generation", - "itemList": [], - "isExternal": false, - "path": "/getting-started/tutorials/node-server-tutorial", - "tags": [] } ], "isExternal": false, @@ -354,17 +332,6 @@ "path": "/getting-started/tutorials/vue-standalone-tutorial", "tags": [] }, - "/getting-started/tutorials/node-server-tutorial": { - "id": "node-server-tutorial", - "name": "Node Standalone", - "description": "", - "mediaImage": "", - "file": "shared/node-server-tutorial/1-code-generation", - "itemList": [], - "isExternal": false, - "path": "/getting-started/tutorials/node-server-tutorial", - "tags": [] - }, "/core-tutorial": { "id": "core-tutorial", "name": "Core Tutorial", @@ -509,305 +476,305 @@ "path": "/core-tutorial/06-summary", "tags": [] }, - "/angular-standalone-tutorial": { - "id": "angular-standalone-tutorial", - "name": "Angular Standalone Tutorial", - "description": "Learn to use Nx with this Angular tutorial where you will learn about all its main feature with a real project.", + "/features": { + "id": "features", + "name": "Features", + "description": "Learn the core features of Nx with in depth guides.", "mediaImage": "", "file": "", "itemList": [ { - "id": "1-code-generation", - "name": "1 - Code Generation", - "description": "", + "id": "run-tasks", + "name": "Run Tasks", + "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", "mediaImage": "", - "file": "shared/angular-standalone-tutorial/1-code-generation", + "file": "shared/features/run-tasks", "itemList": [], "isExternal": false, - "path": "/angular-standalone-tutorial/1-code-generation", - "tags": [] + "path": "/features/run-tasks", + "tags": ["run-tasks", "cache-task-results"] }, { - "id": "2-project-graph", - "name": "2 - Project Graph", - "description": "", + "id": "cache-task-results", + "name": "Cache Task Results", + "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", "mediaImage": "", - "file": "shared/angular-standalone-tutorial/2-project-graph", + "file": "shared/features/cache-task-results", "itemList": [], "isExternal": false, - "path": "/angular-standalone-tutorial/2-project-graph", - "tags": [] + "path": "/features/cache-task-results", + "tags": ["cache-task-results"] }, { - "id": "3-task-running", - "name": "3 - Task Running", + "id": "explore-graph", + "name": "Explore your Workspace", "description": "", "mediaImage": "", - "file": "shared/angular-standalone-tutorial/3-task-running", + "file": "shared/features/explore-graph", "itemList": [], "isExternal": false, - "path": "/angular-standalone-tutorial/3-task-running", - "tags": [] + "path": "/features/explore-graph", + "tags": ["explore-graph"] }, { - "id": "4-task-pipelines", - "name": "4 - Task Pipelines", + "id": "generate-code", + "name": "Generate Code", "description": "", "mediaImage": "", - "file": "shared/angular-standalone-tutorial/4-task-pipelines", + "file": "shared/features/generate-code", "itemList": [], "isExternal": false, - "path": "/angular-standalone-tutorial/4-task-pipelines", - "tags": [] + "path": "/features/generate-code", + "tags": ["generate-code"] }, { - "id": "5-summary", - "name": "5 - Summary", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/5-summary", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/5-summary", - "tags": [] - } - ], - "isExternal": false, - "path": "/angular-standalone-tutorial", - "tags": [] - }, - "/angular-standalone-tutorial/1-code-generation": { - "id": "1-code-generation", - "name": "1 - Code Generation", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/1-code-generation", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/1-code-generation", - "tags": [] - }, - "/angular-standalone-tutorial/2-project-graph": { - "id": "2-project-graph", - "name": "2 - Project Graph", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/2-project-graph", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/2-project-graph", - "tags": [] - }, - "/angular-standalone-tutorial/3-task-running": { - "id": "3-task-running", - "name": "3 - Task Running", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/3-task-running", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/3-task-running", - "tags": [] - }, - "/angular-standalone-tutorial/4-task-pipelines": { - "id": "4-task-pipelines", - "name": "4 - Task Pipelines", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/4-task-pipelines", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/4-task-pipelines", - "tags": [] - }, - "/angular-standalone-tutorial/5-summary": { - "id": "5-summary", - "name": "5 - Summary", - "description": "", - "mediaImage": "", - "file": "shared/angular-standalone-tutorial/5-summary", - "itemList": [], - "isExternal": false, - "path": "/angular-standalone-tutorial/5-summary", - "tags": [] - }, - "/node-server-tutorial": { - "id": "node-server-tutorial", - "name": "Node Server Tutorial", - "description": "Learn to use Nx with this Node Server Tutorial where you will learn about all its main feature with a real project.", - "mediaImage": "", - "file": "", - "itemList": [ - { - "id": "1-code-generation", - "name": "1 - Code Generation", - "description": "", - "mediaImage": "", - "file": "shared/node-server-tutorial/1-code-generation", - "itemList": [], - "isExternal": false, - "path": "/node-server-tutorial/1-code-generation", - "tags": [] - }, - { - "id": "2-project-graph", - "name": "2 - Project Graph", - "description": "", + "id": "automate-updating-dependencies", + "name": "Automate Updating Dependencies", + "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", "mediaImage": "", - "file": "shared/node-server-tutorial/2-project-graph", + "file": "shared/features/automate-updating-dependencies", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/2-project-graph", - "tags": [] + "path": "/features/automate-updating-dependencies", + "tags": ["automate-updating-dependencies"] }, { - "id": "3-task-running", - "name": "3 - Task Running", - "description": "", + "id": "enforce-module-boundaries", + "name": "Enforce Module Boundaries", + "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", "mediaImage": "", - "file": "shared/node-server-tutorial/3-task-running", + "file": "shared/features/enforce-module-boundaries", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/3-task-running", - "tags": [] + "path": "/features/enforce-module-boundaries", + "tags": ["enforce-module-boundaries"] }, { - "id": "4-task-pipelines", - "name": "4 - Task Pipelines", - "description": "", + "id": "integrate-with-editors", + "name": "Integrate with Editors", + "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", "mediaImage": "", - "file": "shared/node-server-tutorial/4-task-pipelines", + "file": "shared/features/integrate-with-editors", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/4-task-pipelines", - "tags": [] + "path": "/features/integrate-with-editors", + "tags": ["integrate-with-editors"] }, { - "id": "5-docker-target", - "name": "5 - Docker Target", - "description": "", + "id": "manage-releases", + "name": "Manage Releases", + "description": "Learn how Nx provides tools to help you manage releasing your projects.", "mediaImage": "", - "file": "shared/node-server-tutorial/5-docker-target", + "file": "shared/features/manage-releases", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/5-docker-target", - "tags": [] + "path": "/features/manage-releases", + "tags": ["manage-releases"] }, { - "id": "6-summary", - "name": "6 - Summary", - "description": "", + "id": "ci-features", + "name": "CI Features", + "description": "Features of Nx and Nx Cloud that improve CI", "mediaImage": "", - "file": "shared/node-server-tutorial/6-summary", - "itemList": [], + "file": "", + "itemList": [ + { + "id": "affected", + "name": "Run Only Tasks Affected by a PR", + "description": "", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/affected", + "tags": [] + }, + { + "id": "remote-cache", + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/remote-cache", + "tags": [] + }, + { + "id": "distribute-task-execution", + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/distribute-task-execution", + "tags": [] + }, + { + "id": "dynamic-agents", + "name": "Dynamically Allocate Agents", + "description": "", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/dynamic-agents", + "tags": [] + }, + { + "id": "split-e2e-tasks", + "name": "Automatically Split E2E Tasks", + "description": "", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/split-e2e-tasks", + "tags": [] + }, + { + "id": "flaky-tasks", + "name": "Identify and Re-run Flaky Tasks", + "description": "", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/flaky-tasks", + "tags": [] + }, + { + "id": "on-premise", + "name": "Set up Nx Cloud On-Premise", + "description": "Set up Nx Cloud on machines that you control", + "mediaImage": "", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/on-premise", + "tags": [] + } + ], "isExternal": false, - "path": "/node-server-tutorial/6-summary", + "path": "/features/ci-features", "tags": [] } ], "isExternal": false, - "path": "/node-server-tutorial", + "path": "/features", "tags": [] }, - "/node-server-tutorial/1-code-generation": { - "id": "1-code-generation", - "name": "1 - Code Generation", - "description": "", + "/features/run-tasks": { + "id": "run-tasks", + "name": "Run Tasks", + "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", "mediaImage": "", - "file": "shared/node-server-tutorial/1-code-generation", + "file": "shared/features/run-tasks", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/1-code-generation", - "tags": [] + "path": "/features/run-tasks", + "tags": ["run-tasks", "cache-task-results"] }, - "/node-server-tutorial/2-project-graph": { - "id": "2-project-graph", - "name": "2 - Project Graph", - "description": "", + "/features/cache-task-results": { + "id": "cache-task-results", + "name": "Cache Task Results", + "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", "mediaImage": "", - "file": "shared/node-server-tutorial/2-project-graph", + "file": "shared/features/cache-task-results", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/2-project-graph", - "tags": [] + "path": "/features/cache-task-results", + "tags": ["cache-task-results"] }, - "/node-server-tutorial/3-task-running": { - "id": "3-task-running", - "name": "3 - Task Running", + "/features/explore-graph": { + "id": "explore-graph", + "name": "Explore your Workspace", "description": "", "mediaImage": "", - "file": "shared/node-server-tutorial/3-task-running", + "file": "shared/features/explore-graph", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/3-task-running", - "tags": [] + "path": "/features/explore-graph", + "tags": ["explore-graph"] }, - "/node-server-tutorial/4-task-pipelines": { - "id": "4-task-pipelines", - "name": "4 - Task Pipelines", + "/features/generate-code": { + "id": "generate-code", + "name": "Generate Code", "description": "", "mediaImage": "", - "file": "shared/node-server-tutorial/4-task-pipelines", + "file": "shared/features/generate-code", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/4-task-pipelines", - "tags": [] + "path": "/features/generate-code", + "tags": ["generate-code"] }, - "/node-server-tutorial/5-docker-target": { - "id": "5-docker-target", - "name": "5 - Docker Target", - "description": "", + "/features/automate-updating-dependencies": { + "id": "automate-updating-dependencies", + "name": "Automate Updating Dependencies", + "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", "mediaImage": "", - "file": "shared/node-server-tutorial/5-docker-target", + "file": "shared/features/automate-updating-dependencies", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/5-docker-target", - "tags": [] + "path": "/features/automate-updating-dependencies", + "tags": ["automate-updating-dependencies"] }, - "/node-server-tutorial/6-summary": { - "id": "6-summary", - "name": "6 - Summary", - "description": "", + "/features/enforce-module-boundaries": { + "id": "enforce-module-boundaries", + "name": "Enforce Module Boundaries", + "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", "mediaImage": "", - "file": "shared/node-server-tutorial/6-summary", + "file": "shared/features/enforce-module-boundaries", "itemList": [], "isExternal": false, - "path": "/node-server-tutorial/6-summary", - "tags": [] + "path": "/features/enforce-module-boundaries", + "tags": ["enforce-module-boundaries"] }, - "/core-features": { - "id": "core-features", - "name": "Core Features", - "description": "Learn the core features of Nx with in depth guides.", + "/features/integrate-with-editors": { + "id": "integrate-with-editors", + "name": "Integrate with Editors", + "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", + "mediaImage": "", + "file": "shared/features/integrate-with-editors", + "itemList": [], + "isExternal": false, + "path": "/features/integrate-with-editors", + "tags": ["integrate-with-editors"] + }, + "/features/manage-releases": { + "id": "manage-releases", + "name": "Manage Releases", + "description": "Learn how Nx provides tools to help you manage releasing your projects.", + "mediaImage": "", + "file": "shared/features/manage-releases", + "itemList": [], + "isExternal": false, + "path": "/features/manage-releases", + "tags": ["manage-releases"] + }, + "/features/ci-features": { + "id": "ci-features", + "name": "CI Features", + "description": "Features of Nx and Nx Cloud that improve CI", "mediaImage": "", "file": "", "itemList": [ { - "id": "run-tasks", - "name": "Run Tasks", - "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", - "mediaImage": "", - "file": "shared/core-features/run-tasks", - "itemList": [], - "isExternal": false, - "path": "/core-features/run-tasks", - "tags": ["run-tasks", "cache-task-results"] - }, - { - "id": "cache-task-results", - "name": "Cache Task Results", - "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", + "id": "affected", + "name": "Run Only Tasks Affected by a PR", + "description": "", "mediaImage": "", - "file": "shared/core-features/cache-task-results", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/cache-task-results", - "tags": ["cache-task-results"] + "isExternal": true, + "path": "/ci/features/affected", + "tags": [] }, { "id": "remote-cache", - "name": "Use Remote Caching", - "description": "", + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", "mediaImage": "", "file": "", "itemList": [], @@ -817,8 +784,8 @@ }, { "id": "distribute-task-execution", - "name": "Distribute Task Execution", - "description": "", + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", "mediaImage": "", "file": "", "itemList": [], @@ -827,125 +794,69 @@ "tags": [] }, { - "id": "explore-graph", - "name": "Explore the Graph", - "description": "Nx uses a graph behind the scenes to optimize your operations. You can also visualize and use the graph to better understand your workspace structure. Learn more in this guide.", - "mediaImage": "", - "file": "shared/core-features/explore-graph", - "itemList": [], - "isExternal": false, - "path": "/core-features/explore-graph", - "tags": ["explore-graph"] - }, - { - "id": "automate-updating-dependencies", - "name": "Automate Updating Dependencies", - "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", - "mediaImage": "", - "file": "shared/core-features/automate-updating-dependencies", - "itemList": [], - "isExternal": false, - "path": "/core-features/automate-updating-dependencies", - "tags": ["automate-updating-dependencies"] - }, - { - "id": "enforce-module-boundaries", - "name": "Enforce Module Boundaries", - "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", + "id": "dynamic-agents", + "name": "Dynamically Allocate Agents", + "description": "", "mediaImage": "", - "file": "shared/core-features/enforce-module-boundaries", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/enforce-module-boundaries", - "tags": ["enforce-module-boundaries"] + "isExternal": true, + "path": "/ci/features/dynamic-agents", + "tags": [] }, { - "id": "integrate-with-editors", - "name": "Integrate with Editors", - "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", + "id": "split-e2e-tasks", + "name": "Automatically Split E2E Tasks", + "description": "", "mediaImage": "", - "file": "shared/core-features/integrate-with-editors", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/integrate-with-editors", - "tags": ["integrate-with-editors"] + "isExternal": true, + "path": "/ci/features/split-e2e-tasks", + "tags": [] }, { - "id": "manage-releases", - "name": "Manage Releases", - "description": "Learn how Nx provides tools to help you manage releasing your projects.", + "id": "flaky-tasks", + "name": "Identify and Re-run Flaky Tasks", + "description": "", "mediaImage": "", - "file": "shared/core-features/manage-releases", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/manage-releases", - "tags": ["manage-releases"] + "isExternal": true, + "path": "/ci/features/flaky-tasks", + "tags": [] }, { - "id": "plugin-features", - "name": "Plugin Features", - "description": "Learn what is a plugin, the different type of plugins and how to create one.", + "id": "on-premise", + "name": "Set up Nx Cloud On-Premise", + "description": "Set up Nx Cloud on machines that you control", "mediaImage": "", - "file": "", - "itemList": [ - { - "id": "use-task-executors", - "name": "Use Task Executors", - "description": "", - "mediaImage": "", - "file": "shared/plugin-features/use-task-executors", - "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-task-executors", - "tags": ["use-task-executors"] - }, - { - "id": "use-code-generators", - "name": "Use Code Generators", - "description": "", - "mediaImage": "", - "file": "shared/plugin-features/use-code-generators", - "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-code-generators", - "tags": ["use-code-generators"] - } - ], - "isExternal": false, - "path": "/core-features/plugin-features", + "file": "", + "itemList": [], + "isExternal": true, + "path": "/ci/features/on-premise", "tags": [] } ], "isExternal": false, - "path": "/core-features", + "path": "/features/ci-features", "tags": [] }, - "/core-features/run-tasks": { - "id": "run-tasks", - "name": "Run Tasks", - "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", - "mediaImage": "", - "file": "shared/core-features/run-tasks", - "itemList": [], - "isExternal": false, - "path": "/core-features/run-tasks", - "tags": ["run-tasks", "cache-task-results"] - }, - "/core-features/cache-task-results": { - "id": "cache-task-results", - "name": "Cache Task Results", - "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", + "/ci/features/affected": { + "id": "affected", + "name": "Run Only Tasks Affected by a PR", + "description": "", "mediaImage": "", - "file": "shared/core-features/cache-task-results", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/cache-task-results", - "tags": ["cache-task-results"] + "isExternal": true, + "path": "/ci/features/affected", + "tags": [] }, "/ci/features/remote-cache": { "id": "remote-cache", - "name": "Use Remote Caching", - "description": "", + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", "mediaImage": "", "file": "", "itemList": [], @@ -955,8 +866,8 @@ }, "/ci/features/distribute-task-execution": { "id": "distribute-task-execution", - "name": "Distribute Task Execution", - "description": "", + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", "mediaImage": "", "file": "", "itemList": [], @@ -964,116 +875,49 @@ "path": "/ci/features/distribute-task-execution", "tags": [] }, - "/core-features/explore-graph": { - "id": "explore-graph", - "name": "Explore the Graph", - "description": "Nx uses a graph behind the scenes to optimize your operations. You can also visualize and use the graph to better understand your workspace structure. Learn more in this guide.", - "mediaImage": "", - "file": "shared/core-features/explore-graph", - "itemList": [], - "isExternal": false, - "path": "/core-features/explore-graph", - "tags": ["explore-graph"] - }, - "/core-features/automate-updating-dependencies": { - "id": "automate-updating-dependencies", - "name": "Automate Updating Dependencies", - "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", - "mediaImage": "", - "file": "shared/core-features/automate-updating-dependencies", - "itemList": [], - "isExternal": false, - "path": "/core-features/automate-updating-dependencies", - "tags": ["automate-updating-dependencies"] - }, - "/core-features/enforce-module-boundaries": { - "id": "enforce-module-boundaries", - "name": "Enforce Module Boundaries", - "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", - "mediaImage": "", - "file": "shared/core-features/enforce-module-boundaries", - "itemList": [], - "isExternal": false, - "path": "/core-features/enforce-module-boundaries", - "tags": ["enforce-module-boundaries"] - }, - "/core-features/integrate-with-editors": { - "id": "integrate-with-editors", - "name": "Integrate with Editors", - "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", - "mediaImage": "", - "file": "shared/core-features/integrate-with-editors", - "itemList": [], - "isExternal": false, - "path": "/core-features/integrate-with-editors", - "tags": ["integrate-with-editors"] - }, - "/core-features/manage-releases": { - "id": "manage-releases", - "name": "Manage Releases", - "description": "Learn how Nx provides tools to help you manage releasing your projects.", + "/ci/features/dynamic-agents": { + "id": "dynamic-agents", + "name": "Dynamically Allocate Agents", + "description": "", "mediaImage": "", - "file": "shared/core-features/manage-releases", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/manage-releases", - "tags": ["manage-releases"] + "isExternal": true, + "path": "/ci/features/dynamic-agents", + "tags": [] }, - "/core-features/plugin-features": { - "id": "plugin-features", - "name": "Plugin Features", - "description": "Learn what is a plugin, the different type of plugins and how to create one.", + "/ci/features/split-e2e-tasks": { + "id": "split-e2e-tasks", + "name": "Automatically Split E2E Tasks", + "description": "", "mediaImage": "", "file": "", - "itemList": [ - { - "id": "use-task-executors", - "name": "Use Task Executors", - "description": "", - "mediaImage": "", - "file": "shared/plugin-features/use-task-executors", - "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-task-executors", - "tags": ["use-task-executors"] - }, - { - "id": "use-code-generators", - "name": "Use Code Generators", - "description": "", - "mediaImage": "", - "file": "shared/plugin-features/use-code-generators", - "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-code-generators", - "tags": ["use-code-generators"] - } - ], - "isExternal": false, - "path": "/core-features/plugin-features", + "itemList": [], + "isExternal": true, + "path": "/ci/features/split-e2e-tasks", "tags": [] }, - "/core-features/plugin-features/use-task-executors": { - "id": "use-task-executors", - "name": "Use Task Executors", + "/ci/features/flaky-tasks": { + "id": "flaky-tasks", + "name": "Identify and Re-run Flaky Tasks", "description": "", "mediaImage": "", - "file": "shared/plugin-features/use-task-executors", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-task-executors", - "tags": ["use-task-executors"] + "isExternal": true, + "path": "/ci/features/flaky-tasks", + "tags": [] }, - "/core-features/plugin-features/use-code-generators": { - "id": "use-code-generators", - "name": "Use Code Generators", - "description": "", + "/ci/features/on-premise": { + "id": "on-premise", + "name": "Set up Nx Cloud On-Premise", + "description": "Set up Nx Cloud on machines that you control", "mediaImage": "", - "file": "shared/plugin-features/use-code-generators", + "file": "", "itemList": [], - "isExternal": false, - "path": "/core-features/plugin-features/use-code-generators", - "tags": ["use-code-generators"] + "isExternal": true, + "path": "/ci/features/on-premise", + "tags": [] }, "/concepts": { "id": "concepts", @@ -1104,6 +948,39 @@ "path": "/concepts/how-caching-works", "tags": ["cache-task-results"] }, + { + "id": "task-pipeline-configuration", + "name": "What is a Task Pipeline", + "description": "", + "mediaImage": "", + "file": "shared/concepts/task-pipeline-configuration", + "itemList": [], + "isExternal": false, + "path": "/concepts/task-pipeline-configuration", + "tags": ["run-tasks"] + }, + { + "id": "nx-plugins", + "name": "What Are Nx Plugins", + "description": "", + "mediaImage": "", + "file": "shared/concepts/nx-plugins", + "itemList": [], + "isExternal": false, + "path": "/concepts/nx-plugins", + "tags": ["generate-code", "create-your-own-plugin"] + }, + { + "id": "inferred-tasks", + "name": "Inferred Tasks", + "description": "", + "mediaImage": "", + "file": "shared/concepts/inferred-tasks", + "itemList": [], + "isExternal": false, + "path": "/concepts/inferred-tasks", + "tags": ["inferred-tasks"] + }, { "id": "types-of-configuration", "name": "Types of Configuration", @@ -1116,15 +993,15 @@ "tags": [] }, { - "id": "task-pipeline-configuration", - "name": "What is a Task Pipeline", + "id": "executors-and-configurations", + "name": "Executors and Configurations", "description": "", "mediaImage": "", - "file": "shared/concepts/task-pipeline-configuration", + "file": "shared/recipes/running-tasks/executors-and-configurations", "itemList": [], "isExternal": false, - "path": "/concepts/task-pipeline-configuration", - "tags": ["run-tasks", "use-task-executors"] + "path": "/concepts/executors-and-configurations", + "tags": ["run-tasks"] }, { "id": "integrated-vs-package-based", @@ -1164,12 +1041,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/module-federation/faster-builds-with-module-federation", - "tags": [ - "use-task-executors", - "module-federation", - "angular", - "react" - ] + "tags": ["module-federation", "angular", "react"] }, { "id": "micro-frontend-architecture", @@ -1214,7 +1086,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/incremental-builds", - "tags": ["use-task-executors"] + "tags": [] }, { "id": "illustrated-dte", @@ -1280,7 +1152,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/monorepo-nx-enterprise", - "tags": ["enforce-module-boundaries", "use-code-generators"] + "tags": ["enforce-module-boundaries", "generate-code"] }, { "id": "nx-daemon", @@ -1424,6 +1296,39 @@ "path": "/concepts/how-caching-works", "tags": ["cache-task-results"] }, + "/concepts/task-pipeline-configuration": { + "id": "task-pipeline-configuration", + "name": "What is a Task Pipeline", + "description": "", + "mediaImage": "", + "file": "shared/concepts/task-pipeline-configuration", + "itemList": [], + "isExternal": false, + "path": "/concepts/task-pipeline-configuration", + "tags": ["run-tasks"] + }, + "/concepts/nx-plugins": { + "id": "nx-plugins", + "name": "What Are Nx Plugins", + "description": "", + "mediaImage": "", + "file": "shared/concepts/nx-plugins", + "itemList": [], + "isExternal": false, + "path": "/concepts/nx-plugins", + "tags": ["generate-code", "create-your-own-plugin"] + }, + "/concepts/inferred-tasks": { + "id": "inferred-tasks", + "name": "Inferred Tasks", + "description": "", + "mediaImage": "", + "file": "shared/concepts/inferred-tasks", + "itemList": [], + "isExternal": false, + "path": "/concepts/inferred-tasks", + "tags": ["inferred-tasks"] + }, "/concepts/types-of-configuration": { "id": "types-of-configuration", "name": "Types of Configuration", @@ -1435,16 +1340,16 @@ "path": "/concepts/types-of-configuration", "tags": [] }, - "/concepts/task-pipeline-configuration": { - "id": "task-pipeline-configuration", - "name": "What is a Task Pipeline", + "/concepts/executors-and-configurations": { + "id": "executors-and-configurations", + "name": "Executors and Configurations", "description": "", "mediaImage": "", - "file": "shared/concepts/task-pipeline-configuration", + "file": "shared/recipes/running-tasks/executors-and-configurations", "itemList": [], "isExternal": false, - "path": "/concepts/task-pipeline-configuration", - "tags": ["run-tasks", "use-task-executors"] + "path": "/concepts/executors-and-configurations", + "tags": ["run-tasks"] }, "/concepts/integrated-vs-package-based": { "id": "integrated-vs-package-based", @@ -1484,7 +1389,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/module-federation/faster-builds-with-module-federation", - "tags": ["use-task-executors", "module-federation", "angular", "react"] + "tags": ["module-federation", "angular", "react"] }, { "id": "micro-frontend-architecture", @@ -1533,7 +1438,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/module-federation/faster-builds-with-module-federation", - "tags": ["use-task-executors", "module-federation", "angular", "react"] + "tags": ["module-federation", "angular", "react"] }, "/concepts/module-federation/micro-frontend-architecture": { "id": "micro-frontend-architecture", @@ -1573,7 +1478,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/incremental-builds", - "tags": ["use-task-executors"] + "tags": [] }, { "id": "illustrated-dte", @@ -1639,7 +1544,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/monorepo-nx-enterprise", - "tags": ["enforce-module-boundaries", "use-code-generators"] + "tags": ["enforce-module-boundaries", "generate-code"] }, { "id": "nx-daemon", @@ -1765,7 +1670,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/incremental-builds", - "tags": ["use-task-executors"] + "tags": [] }, "/concepts/more-concepts/illustrated-dte": { "id": "illustrated-dte", @@ -1831,7 +1736,7 @@ "itemList": [], "isExternal": false, "path": "/concepts/more-concepts/monorepo-nx-enterprise", - "tags": ["enforce-module-boundaries", "use-code-generators"] + "tags": ["enforce-module-boundaries", "generate-code"] }, "/concepts/more-concepts/nx-daemon": { "id": "nx-daemon", @@ -1958,19 +1863,30 @@ "file": "", "itemList": [ { - "id": "customizing-inputs", - "name": "Fine-tuning Caching with Inputs", + "id": "configure-inputs", + "name": "Configure Inputs for Task Caching", + "description": "", + "mediaImage": "", + "file": "shared/recipes/running-tasks/configure-inputs", + "itemList": [], + "isExternal": false, + "path": "/recipes/running-tasks/configure-inputs", + "tags": ["run-tasks", "cache-task-results"] + }, + { + "id": "configure-outputs", + "name": "Configure Outputs for Task Caching", "description": "", "mediaImage": "", - "file": "shared/recipes/running-tasks/customizing-inputs", + "file": "shared/recipes/running-tasks/configure-outputs", "itemList": [], "isExternal": false, - "path": "/recipes/running-tasks/customizing-inputs", + "path": "/recipes/running-tasks/configure-outputs", "tags": ["run-tasks", "cache-task-results"] }, { "id": "defining-task-pipeline", - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/defining-task-pipeline", @@ -1992,14 +1908,14 @@ }, { "id": "run-commands-executor", - "name": "Running Custom Commands", + "name": "Run Custom Commands", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/running-custom-commands", "itemList": [], "isExternal": false, "path": "/recipes/running-tasks/run-commands-executor", - "tags": ["run-tasks", "use-task-executors"] + "tags": ["run-tasks"] }, { "id": "run-tasks-in-parallel", @@ -2090,17 +2006,6 @@ "path": "/recipes/adopting-nx/adding-to-existing-project", "tags": [] }, - { - "id": "lerna-and-nx", - "name": "Nx and Lerna", - "description": "", - "mediaImage": "", - "file": "shared/migration/lerna-and-nx", - "itemList": [], - "isExternal": false, - "path": "/recipes/adopting-nx/lerna-and-nx", - "tags": [] - }, { "id": "preserving-git-histories", "name": "Preserving Git Histories", @@ -2221,7 +2126,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/react/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "react"] + "tags": ["module-federation", "react"] }, { "id": "deploy-nextjs-to-vercel", @@ -2333,7 +2238,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, { "id": "dynamic-module-federation-with-angular", @@ -2344,7 +2249,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/dynamic-module-federation-with-angular", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, { "id": "setup-incremental-builds-angular", @@ -2730,7 +2635,7 @@ "itemList": [ { "id": "webpack-config-setup", - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "description": "A guide on how to configure webpack on your Nx workspace, and instructions on how to customize your webpack configuration", "mediaImage": "", "file": "shared/packages/webpack/webpack-config-setup", @@ -3160,7 +3065,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/troubleshooting/performance-profiling", - "tags": ["use-task-executors", "environment-variables"] + "tags": ["environment-variables"] } ], "isExternal": false, @@ -3185,6 +3090,17 @@ "path": "/recipes/nx-console/console-telemetry", "tags": ["integrate-with-editors"] }, + { + "id": "console-project-details", + "name": "Project Details View", + "description": "", + "mediaImage": "", + "file": "shared/recipes/console-project-details", + "itemList": [], + "isExternal": false, + "path": "/recipes/nx-console/console-project-details", + "tags": ["integrate-with-editors"] + }, { "id": "console-generate-command", "name": "Generate Command", @@ -3348,19 +3264,30 @@ "file": "", "itemList": [ { - "id": "customizing-inputs", - "name": "Fine-tuning Caching with Inputs", + "id": "configure-inputs", + "name": "Configure Inputs for Task Caching", + "description": "", + "mediaImage": "", + "file": "shared/recipes/running-tasks/configure-inputs", + "itemList": [], + "isExternal": false, + "path": "/recipes/running-tasks/configure-inputs", + "tags": ["run-tasks", "cache-task-results"] + }, + { + "id": "configure-outputs", + "name": "Configure Outputs for Task Caching", "description": "", "mediaImage": "", - "file": "shared/recipes/running-tasks/customizing-inputs", + "file": "shared/recipes/running-tasks/configure-outputs", "itemList": [], "isExternal": false, - "path": "/recipes/running-tasks/customizing-inputs", + "path": "/recipes/running-tasks/configure-outputs", "tags": ["run-tasks", "cache-task-results"] }, { "id": "defining-task-pipeline", - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/defining-task-pipeline", @@ -3382,14 +3309,14 @@ }, { "id": "run-commands-executor", - "name": "Running Custom Commands", + "name": "Run Custom Commands", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/running-custom-commands", "itemList": [], "isExternal": false, "path": "/recipes/running-tasks/run-commands-executor", - "tags": ["run-tasks", "use-task-executors"] + "tags": ["run-tasks"] }, { "id": "run-tasks-in-parallel", @@ -3440,20 +3367,31 @@ "path": "/recipes/running-tasks", "tags": [] }, - "/recipes/running-tasks/customizing-inputs": { - "id": "customizing-inputs", - "name": "Fine-tuning Caching with Inputs", + "/recipes/running-tasks/configure-inputs": { + "id": "configure-inputs", + "name": "Configure Inputs for Task Caching", + "description": "", + "mediaImage": "", + "file": "shared/recipes/running-tasks/configure-inputs", + "itemList": [], + "isExternal": false, + "path": "/recipes/running-tasks/configure-inputs", + "tags": ["run-tasks", "cache-task-results"] + }, + "/recipes/running-tasks/configure-outputs": { + "id": "configure-outputs", + "name": "Configure Outputs for Task Caching", "description": "", "mediaImage": "", - "file": "shared/recipes/running-tasks/customizing-inputs", + "file": "shared/recipes/running-tasks/configure-outputs", "itemList": [], "isExternal": false, - "path": "/recipes/running-tasks/customizing-inputs", + "path": "/recipes/running-tasks/configure-outputs", "tags": ["run-tasks", "cache-task-results"] }, "/recipes/running-tasks/defining-task-pipeline": { "id": "defining-task-pipeline", - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/defining-task-pipeline", @@ -3475,14 +3413,14 @@ }, "/recipes/running-tasks/run-commands-executor": { "id": "run-commands-executor", - "name": "Running Custom Commands", + "name": "Run Custom Commands", "description": "", "mediaImage": "", "file": "shared/recipes/running-tasks/running-custom-commands", "itemList": [], "isExternal": false, "path": "/recipes/running-tasks/run-commands-executor", - "tags": ["run-tasks", "use-task-executors"] + "tags": ["run-tasks"] }, "/recipes/running-tasks/run-tasks-in-parallel": { "id": "run-tasks-in-parallel", @@ -3568,17 +3506,6 @@ "path": "/recipes/adopting-nx/adding-to-existing-project", "tags": [] }, - { - "id": "lerna-and-nx", - "name": "Nx and Lerna", - "description": "", - "mediaImage": "", - "file": "shared/migration/lerna-and-nx", - "itemList": [], - "isExternal": false, - "path": "/recipes/adopting-nx/lerna-and-nx", - "tags": [] - }, { "id": "preserving-git-histories", "name": "Preserving Git Histories", @@ -3639,17 +3566,6 @@ "path": "/recipes/adopting-nx/adding-to-existing-project", "tags": [] }, - "/recipes/adopting-nx/lerna-and-nx": { - "id": "lerna-and-nx", - "name": "Nx and Lerna", - "description": "", - "mediaImage": "", - "file": "shared/migration/lerna-and-nx", - "itemList": [], - "isExternal": false, - "path": "/recipes/adopting-nx/lerna-and-nx", - "tags": [] - }, "/recipes/adopting-nx/preserving-git-histories": { "id": "preserving-git-histories", "name": "Preserving Git Histories", @@ -3765,7 +3681,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/react/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "react"] + "tags": ["module-federation", "react"] }, { "id": "deploy-nextjs-to-vercel", @@ -3869,7 +3785,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/react/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "react"] + "tags": ["module-federation", "react"] }, "/recipes/react/deploy-nextjs-to-vercel": { "id": "deploy-nextjs-to-vercel", @@ -3976,7 +3892,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, { "id": "dynamic-module-federation-with-angular", @@ -3987,7 +3903,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/dynamic-module-federation-with-angular", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, { "id": "setup-incremental-builds-angular", @@ -4136,7 +4052,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, "/recipes/angular/dynamic-module-federation-with-angular": { "id": "dynamic-module-federation-with-angular", @@ -4147,7 +4063,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/angular/dynamic-module-federation-with-angular", - "tags": ["use-task-executors", "module-federation", "angular"] + "tags": ["module-federation", "angular"] }, "/recipes/angular/setup-incremental-builds-angular": { "id": "setup-incremental-builds-angular", @@ -4803,7 +4719,7 @@ "itemList": [ { "id": "webpack-config-setup", - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "description": "A guide on how to configure webpack on your Nx workspace, and instructions on how to customize your webpack configuration", "mediaImage": "", "file": "shared/packages/webpack/webpack-config-setup", @@ -4830,7 +4746,7 @@ }, "/recipes/webpack/webpack-config-setup": { "id": "webpack-config-setup", - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "description": "A guide on how to configure webpack on your Nx workspace, and instructions on how to customize your webpack configuration", "mediaImage": "", "file": "shared/packages/webpack/webpack-config-setup", @@ -5552,7 +5468,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/troubleshooting/performance-profiling", - "tags": ["use-task-executors", "environment-variables"] + "tags": ["environment-variables"] } ], "isExternal": false, @@ -5612,7 +5528,7 @@ "itemList": [], "isExternal": false, "path": "/recipes/troubleshooting/performance-profiling", - "tags": ["use-task-executors", "environment-variables"] + "tags": ["environment-variables"] }, "/recipes/nx-console": { "id": "nx-console", @@ -5632,6 +5548,17 @@ "path": "/recipes/nx-console/console-telemetry", "tags": ["integrate-with-editors"] }, + { + "id": "console-project-details", + "name": "Project Details View", + "description": "", + "mediaImage": "", + "file": "shared/recipes/console-project-details", + "itemList": [], + "isExternal": false, + "path": "/recipes/nx-console/console-project-details", + "tags": ["integrate-with-editors"] + }, { "id": "console-generate-command", "name": "Generate Command", @@ -5714,6 +5641,17 @@ "path": "/recipes/nx-console/console-telemetry", "tags": ["integrate-with-editors"] }, + "/recipes/nx-console/console-project-details": { + "id": "console-project-details", + "name": "Project Details View", + "description": "", + "mediaImage": "", + "file": "shared/recipes/console-project-details", + "itemList": [], + "isExternal": false, + "path": "/recipes/nx-console/console-project-details", + "tags": ["integrate-with-editors"] + }, "/recipes/nx-console/console-generate-command": { "id": "console-generate-command", "name": "Generate Command", @@ -6639,7 +6577,18 @@ "itemList": [], "isExternal": false, "path": "/reference/project-configuration", - "tags": ["use-task-executors"] + "tags": [] + }, + { + "id": "inputs", + "name": "Inputs and Named Inputs", + "description": "", + "mediaImage": "", + "file": "shared/reference/inputs", + "itemList": [], + "isExternal": false, + "path": "/reference/inputs", + "tags": ["cache-task-results"] }, { "id": "nxignore", @@ -6710,7 +6659,18 @@ "itemList": [], "isExternal": false, "path": "/reference/project-configuration", - "tags": ["use-task-executors"] + "tags": [] + }, + "/reference/inputs": { + "id": "inputs", + "name": "Inputs and Named Inputs", + "description": "", + "mediaImage": "", + "file": "shared/reference/inputs", + "itemList": [], + "isExternal": false, + "path": "/reference/inputs", + "tags": ["cache-task-results"] }, "/reference/nxignore": { "id": "nxignore", @@ -6829,6 +6789,28 @@ "path": "/deprecated/runtime-cache-inputs", "tags": [] }, + { + "id": "cacheable-operations", + "name": "cacheableOperations", + "description": "", + "mediaImage": "", + "file": "shared/deprecated/cacheable-operations", + "itemList": [], + "isExternal": false, + "path": "/deprecated/cacheable-operations", + "tags": [] + }, + { + "id": "npm-scope", + "name": "npmScope", + "description": "", + "mediaImage": "", + "file": "shared/deprecated/npm-scope", + "itemList": [], + "isExternal": false, + "path": "/deprecated/npm-scope", + "tags": [] + }, { "id": "global-implicit-dependencies", "name": "globalImplicitDependencies", @@ -7022,6 +7004,28 @@ "path": "/deprecated/runtime-cache-inputs", "tags": [] }, + "/deprecated/cacheable-operations": { + "id": "cacheable-operations", + "name": "cacheableOperations", + "description": "", + "mediaImage": "", + "file": "shared/deprecated/cacheable-operations", + "itemList": [], + "isExternal": false, + "path": "/deprecated/cacheable-operations", + "tags": [] + }, + "/deprecated/npm-scope": { + "id": "npm-scope", + "name": "npmScope", + "description": "", + "mediaImage": "", + "file": "shared/deprecated/npm-scope", + "itemList": [], + "isExternal": false, + "path": "/deprecated/npm-scope", + "tags": [] + }, "/deprecated/global-implicit-dependencies": { "id": "global-implicit-dependencies", "name": "globalImplicitDependencies", @@ -7281,7 +7285,7 @@ "itemList": [], "isExternal": true, "path": "/reference/nx-json#generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, { "id": "sitemap", @@ -7363,7 +7367,7 @@ "itemList": [], "isExternal": true, "path": "/reference/nx-json#generators", - "tags": ["use-code-generators"] + "tags": ["generate-code"] }, "/see-also/sitemap": { "id": "sitemap", diff --git a/docs/generated/manifests/tags.json b/docs/generated/manifests/tags.json index 703205ab07842..6b28f9a9d5c95 100644 --- a/docs/generated/manifests/tags.json +++ b/docs/generated/manifests/tags.json @@ -2,10 +2,10 @@ "run-tasks": [ { "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", - "file": "shared/core-features/run-tasks", + "file": "shared/features/run-tasks", "id": "run-tasks", "name": "Run Tasks", - "path": "/core-features/run-tasks" + "path": "/features/run-tasks" }, { "description": "", @@ -16,23 +16,37 @@ }, { "description": "", - "file": "shared/recipes/running-tasks/customizing-inputs", - "id": "customizing-inputs", - "name": "Fine-tuning Caching with Inputs", - "path": "/recipes/running-tasks/customizing-inputs" + "file": "shared/recipes/running-tasks/executors-and-configurations", + "id": "executors-and-configurations", + "name": "Executors and Configurations", + "path": "/concepts/executors-and-configurations" + }, + { + "description": "", + "file": "shared/recipes/running-tasks/configure-inputs", + "id": "configure-inputs", + "name": "Configure Inputs for Task Caching", + "path": "/recipes/running-tasks/configure-inputs" + }, + { + "description": "", + "file": "shared/recipes/running-tasks/configure-outputs", + "id": "configure-outputs", + "name": "Configure Outputs for Task Caching", + "path": "/recipes/running-tasks/configure-outputs" }, { "description": "", "file": "shared/recipes/running-tasks/defining-task-pipeline", "id": "defining-task-pipeline", - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "path": "/recipes/running-tasks/defining-task-pipeline" }, { "description": "", "file": "shared/recipes/running-tasks/running-custom-commands", "id": "run-commands-executor", - "name": "Running Custom Commands", + "name": "Run Custom Commands", "path": "/recipes/running-tasks/run-commands-executor" }, { @@ -88,17 +102,17 @@ "cache-task-results": [ { "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", - "file": "shared/core-features/run-tasks", + "file": "shared/features/run-tasks", "id": "run-tasks", "name": "Run Tasks", - "path": "/core-features/run-tasks" + "path": "/features/run-tasks" }, { "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", - "file": "shared/core-features/cache-task-results", + "file": "shared/features/cache-task-results", "id": "cache-task-results", "name": "Cache Task Results", - "path": "/core-features/cache-task-results" + "path": "/features/cache-task-results" }, { "description": "", @@ -109,10 +123,17 @@ }, { "description": "", - "file": "shared/recipes/running-tasks/customizing-inputs", - "id": "customizing-inputs", - "name": "Fine-tuning Caching with Inputs", - "path": "/recipes/running-tasks/customizing-inputs" + "file": "shared/recipes/running-tasks/configure-inputs", + "id": "configure-inputs", + "name": "Configure Inputs for Task Caching", + "path": "/recipes/running-tasks/configure-inputs" + }, + { + "description": "", + "file": "shared/recipes/running-tasks/configure-outputs", + "id": "configure-outputs", + "name": "Configure Outputs for Task Caching", + "path": "/recipes/running-tasks/configure-outputs" }, { "description": "", @@ -121,6 +142,13 @@ "name": "Troubleshoot Cache Misses", "path": "/recipes/troubleshooting/troubleshoot-cache-misses" }, + { + "description": "", + "file": "shared/reference/inputs", + "id": "inputs", + "name": "Inputs and Named Inputs", + "path": "/reference/inputs" + }, { "description": "", "file": "", @@ -173,11 +201,11 @@ ], "explore-graph": [ { - "description": "Nx uses a graph behind the scenes to optimize your operations. You can also visualize and use the graph to better understand your workspace structure. Learn more in this guide.", - "file": "shared/core-features/explore-graph", + "description": "", + "file": "shared/features/explore-graph", "id": "explore-graph", - "name": "Explore the Graph", - "path": "/core-features/explore-graph" + "name": "Explore your Workspace", + "path": "/features/explore-graph" }, { "description": "", @@ -215,13 +243,85 @@ "path": "/nx-api/nx/documents/dep-graph" } ], + "generate-code": [ + { + "description": "", + "file": "shared/features/generate-code", + "id": "generate-code", + "name": "Generate Code", + "path": "/features/generate-code" + }, + { + "description": "", + "file": "shared/concepts/nx-plugins", + "id": "nx-plugins", + "name": "What Are Nx Plugins", + "path": "/concepts/nx-plugins" + }, + { + "description": "", + "file": "shared/monorepo-nx-enterprise", + "id": "monorepo-nx-enterprise", + "name": "Using Nx at Enterprises", + "path": "/concepts/more-concepts/monorepo-nx-enterprise" + }, + { + "description": "", + "file": "", + "id": "nxjson-generator-defaults", + "name": "nx.json generator defaults", + "path": "/reference/nx-json#generators" + }, + { + "description": "", + "file": "shared/recipes/generators/local-generators", + "id": "local-generators", + "name": "Write a Simple Generator", + "path": "/extending-nx/recipes/local-generators" + }, + { + "description": "", + "file": "shared/recipes/generators/composing-generators", + "id": "composing-generators", + "name": "Compose Generators", + "path": "/extending-nx/recipes/composing-generators" + }, + { + "description": "", + "file": "shared/recipes/generators/generator-options", + "id": "generator-options", + "name": "Provide Options for Generators", + "path": "/extending-nx/recipes/generator-options" + }, + { + "description": "", + "file": "shared/recipes/generators/creating-files", + "id": "creating-files", + "name": "Create Files", + "path": "/extending-nx/recipes/creating-files" + }, + { + "description": "", + "file": "shared/recipes/generators/modifying-files", + "id": "modifying-files", + "name": "Modify Files", + "path": "/extending-nx/recipes/modifying-files" + }, + { + "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", + "file": "generated/packages/generated/packages/nx/documents/generate", + "id": "generate", + "name": "generate", + "path": "/nx-api/nx/documents/generate" + } + ], "automate-updating-dependencies": [ { "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", - "file": "shared/core-features/automate-updating-dependencies", + "file": "shared/features/automate-updating-dependencies", "id": "automate-updating-dependencies", "name": "Automate Updating Dependencies", - "path": "/core-features/automate-updating-dependencies" + "path": "/features/automate-updating-dependencies" }, { "description": "", @@ -248,10 +348,10 @@ "enforce-module-boundaries": [ { "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", - "file": "shared/core-features/enforce-module-boundaries", + "file": "shared/features/enforce-module-boundaries", "id": "enforce-module-boundaries", "name": "Enforce Module Boundaries", - "path": "/core-features/enforce-module-boundaries" + "path": "/features/enforce-module-boundaries" }, { "description": "", @@ -341,10 +441,10 @@ "integrate-with-editors": [ { "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", - "file": "shared/core-features/integrate-with-editors", + "file": "shared/features/integrate-with-editors", "id": "integrate-with-editors", "name": "Integrate with Editors", - "path": "/core-features/integrate-with-editors" + "path": "/features/integrate-with-editors" }, { "description": "", @@ -353,6 +453,13 @@ "name": "Telemetry", "path": "/recipes/nx-console/console-telemetry" }, + { + "description": "", + "file": "shared/recipes/console-project-details", + "id": "console-project-details", + "name": "Project Details View", + "path": "/recipes/nx-console/console-project-details" + }, { "description": "", "file": "shared/recipes/console-generate-command", @@ -399,198 +506,79 @@ "manage-releases": [ { "description": "Learn how Nx provides tools to help you manage releasing your projects.", - "file": "shared/core-features/manage-releases", + "file": "shared/features/manage-releases", "id": "manage-releases", "name": "Manage Releases", - "path": "/core-features/manage-releases" + "path": "/features/manage-releases" } ], - "use-task-executors": [ - { - "description": "", - "file": "shared/plugin-features/use-task-executors", - "id": "use-task-executors", - "name": "Use Task Executors", - "path": "/core-features/plugin-features/use-task-executors" - }, - { - "description": "", - "file": "shared/concepts/task-pipeline-configuration", - "id": "task-pipeline-configuration", - "name": "What is a Task Pipeline", - "path": "/concepts/task-pipeline-configuration" - }, - { - "description": "", - "file": "shared/guides/module-federation/faster-builds", - "id": "faster-builds-with-module-federation", - "name": "Faster Builds with Module Federation", - "path": "/concepts/module-federation/faster-builds-with-module-federation" - }, - { - "description": "", - "file": "shared/incremental-builds", - "id": "incremental-builds", - "name": "Incremental Builds", - "path": "/concepts/more-concepts/incremental-builds" - }, - { - "description": "", - "file": "shared/recipes/running-tasks/running-custom-commands", - "id": "run-commands-executor", - "name": "Running Custom Commands", - "path": "/recipes/running-tasks/run-commands-executor" - }, - { - "description": "", - "file": "shared/recipes/module-federation-with-ssr", - "id": "module-federation-with-ssr", - "name": "Setup Module Federation with SSR for React", - "path": "/recipes/react/module-federation-with-ssr" - }, - { - "description": "", - "file": "shared/recipes/module-federation-with-ssr", - "id": "module-federation-with-ssr", - "name": "Setup Module Federation with SSR for Angular", - "path": "/recipes/angular/module-federation-with-ssr" - }, - { - "description": "", - "file": "shared/guides/module-federation/dynamic-mfe-angular", - "id": "dynamic-module-federation-with-angular", - "name": "Advanced Micro Frontends with Angular using Dynamic Federation", - "path": "/recipes/angular/dynamic-module-federation-with-angular" - }, - { - "description": "", - "file": "shared/guides/performance-profiling", - "id": "performance-profiling", - "name": "Profiling Build Performance", - "path": "/recipes/troubleshooting/performance-profiling" - }, - { - "description": "", - "file": "shared/reference/project-configuration", - "id": "project-configuration", - "name": "Project Configuration", - "path": "/reference/project-configuration" - }, + "intro": [ { "description": "", - "file": "shared/recipes/plugins/local-executors", - "id": "local-executors", - "name": "Write a Simple Executor", - "path": "/extending-nx/recipes/local-executors" + "file": "shared/mental-model", + "id": "mental-model", + "name": "Mental Model", + "path": "/concepts/mental-model" }, { "description": "", - "file": "shared/recipes/plugins/compose-executors", - "id": "compose-executors", - "name": "Compose Executors", - "path": "/extending-nx/recipes/compose-executors" - }, - { - "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", - "file": "generated/packages/generated/packages/nx/documents/run", - "id": "run", - "name": "run", - "path": "/nx-api/nx/documents/run" - }, - { - "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", - "file": "generated/packages/generated/packages/nx/documents/run-many", - "id": "run-many", - "name": "run-many", - "path": "/nx-api/nx/documents/run-many" - }, - { - "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", - "file": "generated/packages/generated/packages/nx/documents/affected", - "id": "affected", - "name": "affected", - "path": "/nx-api/nx/documents/affected" + "file": "shared/concepts/integrated-vs-package-based", + "id": "integrated-vs-package-based", + "name": "Integrated Repos vs. Package-Based Repos vs. Standalone Apps", + "path": "/concepts/integrated-vs-package-based" } ], - "use-code-generators": [ - { - "description": "", - "file": "shared/plugin-features/use-code-generators", - "id": "use-code-generators", - "name": "Use Code Generators", - "path": "/core-features/plugin-features/use-code-generators" - }, - { - "description": "", - "file": "shared/monorepo-nx-enterprise", - "id": "monorepo-nx-enterprise", - "name": "Using Nx at Enterprises", - "path": "/concepts/more-concepts/monorepo-nx-enterprise" - }, + "create-your-own-plugin": [ { "description": "", - "file": "", - "id": "nxjson-generator-defaults", - "name": "nx.json generator defaults", - "path": "/reference/nx-json#generators" + "file": "shared/concepts/nx-plugins", + "id": "nx-plugins", + "name": "What Are Nx Plugins", + "path": "/concepts/nx-plugins" }, { "description": "", - "file": "shared/recipes/generators/local-generators", - "id": "local-generators", - "name": "Write a Simple Generator", - "path": "/extending-nx/recipes/local-generators" + "file": "shared/guides/nx-devkit-angular-devkit", + "id": "nx-devkit-angular-devkit", + "name": "Nx Devkit and Angular Devkit", + "path": "/concepts/more-concepts/nx-devkit-angular-devkit" }, { "description": "", - "file": "shared/recipes/generators/composing-generators", - "id": "composing-generators", - "name": "Compose Generators", - "path": "/extending-nx/recipes/composing-generators" + "file": "shared/recipes/plugins/migration-generators", + "id": "migration-generators", + "name": "Write a Migration", + "path": "/extending-nx/recipes/migration-generators" }, { "description": "", - "file": "shared/recipes/generators/generator-options", - "id": "generator-options", - "name": "Provide Options for Generators", - "path": "/extending-nx/recipes/generator-options" + "file": "shared/recipes/plugins/create-preset", + "id": "create-preset", + "name": "Create a Preset", + "path": "/extending-nx/recipes/create-preset" }, { "description": "", - "file": "shared/recipes/generators/creating-files", - "id": "creating-files", - "name": "Create Files", - "path": "/extending-nx/recipes/creating-files" + "file": "shared/recipes/plugins/create-install-package", + "id": "create-install-package", + "name": "Create an Install Package", + "path": "/extending-nx/recipes/create-install-package" }, { "description": "", - "file": "shared/recipes/generators/modifying-files", - "id": "modifying-files", - "name": "Modify Files", - "path": "/extending-nx/recipes/modifying-files" - }, - { - "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.", - "file": "generated/packages/generated/packages/nx/documents/generate", - "id": "generate", - "name": "generate", - "path": "/nx-api/nx/documents/generate" + "file": "shared/recipes/plugins/project-graph-plugins", + "id": "project-graph-plugins", + "name": "Modify the Project Graph", + "path": "/extending-nx/recipes/project-graph-plugins" } ], - "intro": [ + "inferred-tasks": [ { "description": "", - "file": "shared/mental-model", - "id": "mental-model", - "name": "Mental Model", - "path": "/concepts/mental-model" - }, - { - "description": "", - "file": "shared/concepts/integrated-vs-package-based", - "id": "integrated-vs-package-based", - "name": "Integrated Repos vs. Package-Based Repos vs. Standalone Apps", - "path": "/concepts/integrated-vs-package-based" + "file": "shared/concepts/inferred-tasks", + "id": "inferred-tasks", + "name": "Inferred Tasks", + "path": "/concepts/inferred-tasks" } ], "repository-types": [ @@ -728,13 +716,6 @@ "name": "CI Documentation", "path": "/ci/intro/ci-with-nx" }, - { - "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Cloud has a built-in DTE mechanism which makes this a trivial task.", - "file": "shared/core-features/distribute-task-execution", - "id": "distribute-task-execution", - "name": "Distribute Task Execution", - "path": "/ci/features/distribute-task-execution" - }, { "description": "", "file": "nx-cloud/concepts/parallelization-distribution", @@ -757,43 +738,6 @@ "path": "/nx-api/nx/documents/connect-to-nx-cloud" } ], - "create-your-own-plugin": [ - { - "description": "", - "file": "shared/guides/nx-devkit-angular-devkit", - "id": "nx-devkit-angular-devkit", - "name": "Nx Devkit and Angular Devkit", - "path": "/concepts/more-concepts/nx-devkit-angular-devkit" - }, - { - "description": "", - "file": "shared/recipes/plugins/migration-generators", - "id": "migration-generators", - "name": "Write a Migration", - "path": "/extending-nx/recipes/migration-generators" - }, - { - "description": "", - "file": "shared/recipes/plugins/create-preset", - "id": "create-preset", - "name": "Create a Preset", - "path": "/extending-nx/recipes/create-preset" - }, - { - "description": "", - "file": "shared/recipes/plugins/create-install-package", - "id": "create-install-package", - "name": "Create an Install Package", - "path": "/extending-nx/recipes/create-install-package" - }, - { - "description": "", - "file": "shared/recipes/plugins/project-graph-plugins", - "id": "project-graph-plugins", - "name": "Modify the Project Graph", - "path": "/extending-nx/recipes/project-graph-plugins" - } - ], "workspace-watching": [ { "description": "", @@ -1189,9 +1133,9 @@ "remote-cache": [ { "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", - "file": "shared/core-features/remote-cache", + "file": "shared/features/remote-cache", "id": "remote-cache", - "name": "Use Remote Caching", + "name": "Use Remote Caching (Nx Replay)", "path": "/ci/features/remote-cache" } ], diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 68908e46d908f..10cd50f108d6f 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -90,7 +90,7 @@ "type": "executor" }, { - "description": "The `dev-server` executor is very similar to the standard `dev-server` builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration.", + "description": "Serves an Angular application using [Webpack](https://webpack.js.org/) when the build target is using a Webpack-based executor, or [Vite](https://vitejs.dev/) when the build target uses an esbuild-based executor.", "file": "generated/packages/angular/executors/dev-server.json", "hidden": false, "name": "dev-server", @@ -903,7 +903,7 @@ ], "generators": [ { - "description": "Initialize the @nrwl/expo plugin", + "description": "Initialize the @nx/expo plugin", "file": "generated/packages/expo/generators/init.json", "hidden": true, "name": "init", @@ -1608,7 +1608,7 @@ "itemList": [], "isExternal": false, "path": "nx/documents/generate", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "originalFilePath": "generated/cli/generate" }, { @@ -1619,7 +1619,7 @@ "itemList": [], "isExternal": false, "path": "nx/documents/run", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/run" }, { @@ -1652,7 +1652,7 @@ "itemList": [], "isExternal": false, "path": "nx/documents/run-many", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/run-many" }, { @@ -1663,7 +1663,7 @@ "itemList": [], "isExternal": false, "path": "nx/documents/affected", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "originalFilePath": "generated/cli/affected" }, { @@ -2618,15 +2618,6 @@ "originalFilePath": "/packages/remix/src/generators/error-boundary/schema.json", "path": "remix/generators/error-boundary", "type": "generator" - }, - { - "description": "Generate a project for testing Remix apps using Cypress", - "file": "generated/packages/remix/generators/cypress.json", - "hidden": false, - "name": "cypress", - "originalFilePath": "/packages/remix/src/generators/cypress/schema.json", - "path": "remix/generators/cypress", - "type": "generator" } ], "githubRoot": "https://github.com/nrwl/nx/blob/master", diff --git a/docs/generated/packages/angular/documents/overview.md b/docs/generated/packages/angular/documents/overview.md index f3a1a7f2b44b6..1c13b60467247 100644 --- a/docs/generated/packages/angular/documents/overview.md +++ b/docs/generated/packages/angular/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Angular Plugin +description: The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. +--- + The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. It provides: @@ -15,35 +20,32 @@ You can easily and mostly **automatically migrate from an Angular CLI** project more [here](/recipes/angular/migration/angular). {% /callout %} -## Setting up the Angular plugin +## Setting Up @nx/angular + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/angular` version that matches the version of `nx` in your repository. If the version -numbers get out of sync, you can encounter some difficult to debug errors. You -can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +Make sure to install the `@nx/angular` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -Adding the Angular plugin to an existing Nx workspace can be done with the following: +In any Nx workspace, you can install `@nx/angular` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/angular +nx add @nx/angular ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/angular -``` +This will install the correct version of `@nx/angular`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/angular` package with your package manager. ```shell -pnpm add -D @nx/angular +npm add -D @nx/angular ``` {% /tab %} diff --git a/docs/generated/packages/angular/executors/dev-server.json b/docs/generated/packages/angular/executors/dev-server.json index 416037746a204..cc4e906d0a731 100644 --- a/docs/generated/packages/angular/executors/dev-server.json +++ b/docs/generated/packages/angular/executors/dev-server.json @@ -6,8 +6,8 @@ "outputCapture": "direct-nodejs", "$schema": "http://json-schema.org/draft-07/schema", "title": "Schema for Webpack Dev Server", - "description": "The dev-server executor is very similar to the standard dev server builder provided by the Angular Devkit. It is usually used in tandem with `@nx/angular:webpack-browser` when your Angular application uses a custom webpack configuration.", - "examplesFile": "##### Seving an application with a custom webpack configuration\n\nThis executor should be used along with `@nx/angular:webpack-browser` to serve an application using a custom webpack configuration.\n\nYour `project.json` file should contain a `build` and `serve` target that matches the following:\n\n```json\n\"build\": {\n \"executor\": \"@nx/angular:webpack-browser\",\n \"options\": {\n ...\n \"customWebpackConfig\": {\n \"path\": \"apps/appName/webpack.config.js\"\n }\n }\n},\n\"serve\": {\n \"executor\": \"@nx/angular:dev-server\",\n \"configurations\": {\n \"production\": {\n \"buildTarget\": \"appName:build:production\"\n },\n \"development\": {\n \"buildTarget\": \"appName:build:development\"\n }\n },\n \"defaultConfiguration\": \"development\",\n}\n```\n", + "description": "Serves an Angular application using [Webpack](https://webpack.js.org/) when the build target is using a Webpack-based executor, or [Vite](https://vitejs.dev/) when the build target uses an esbuild-based executor.", + "examplesFile": "The `@nx/angular:dev-server` executor is very similar to the `@angular-devkit/build-angular:dev-server` builder provided by the Angular CLI. In addition to the features provided by the Angular CLI builder, the `@nx/angular:dev-server` executor also supports the following:\n\n- Best integration for `@nx/angular:webpack-browser`, `@nx/angular:browser-esbuild` and `@nx/angular:application`\n- Providing HTTP request middleware functions when the build target is using an esbuild-based executor\n- Incremental builds\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Using a custom Webpack configuration\" %}\n\nThis executor should be used along with `@nx/angular:webpack-browser` to serve an application using a custom Webpack configuration.\n\nAdd the `serve` target using the `@nx/angular:dev-server` executor, set the `build` target executor as `@nx/angular:webpack-browser` and set the `customWebpackConfig` option as shown below:\n\n```json {% fileName=\"apps/my-app/project.json\" highlightLines=[2,\"5-7\",\"10-20\"] %}\n\"build\": {\n \"executor\": \"@nx/angular:webpack-browser\",\n \"options\": {\n ...\n \"customWebpackConfig\": {\n \"path\": \"apps/my-app/webpack.config.js\"\n }\n }\n},\n\"serve\": {\n \"executor\": \"@nx/angular:dev-server\",\n \"configurations\": {\n \"production\": {\n \"buildTarget\": \"my-app:build:production\"\n },\n \"development\": {\n \"buildTarget\": \"my-app:build:development\"\n }\n },\n \"defaultConfiguration\": \"development\",\n}\n```\n\n```js {% fileName=\"apps/my-app/webpack.config.js\" %}\nmodule.exports = (config) => {\n // update the config with your custom configuration\n\n return config;\n};\n```\n\n{% /tab %}\n\n{% tab label=\"Providing HTTP request middleware function\" %}\n\n{% callout type=\"warning\" title=\"Overrides\" }\n\nAvailable for workspaces using Angular version 17.0.0 or greater and with `build` targets using an esbuild-based executor.\n\n{% /callout %}\n\nThe executor accepts an `esbuildMidleware` option that allows you to provide HTTP require middleware functions that will be used by the Vite development server.\n\n```json {% fileName=\"apps/my-app/project.json\" highlightLines=[8] %}\n{\n ...\n \"targets\": {\n \"serve\": {\n \"executor\": \"@nx/angular:dev-server\",\n \"options\": {\n ...\n \"esbuildMidleware\": [\"apps/my-app/hello-world.middleware.ts\"]\n }\n }\n ...\n }\n}\n```\n\n```ts {% fileName=\"apps/my-app/hello-world.middleware.ts\" %}\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\nconst helloWorldMiddleware = (\n req: IncomingMessage,\n res: ServerResponse,\n next: (err?: unknown) => void\n) => {\n if (req.url === '/hello-world') {\n res.end('

Hello World!

');\n } else {\n next();\n }\n};\n\nexport default helloWorldMiddleware;\n```\n\n{% /tab %}\n", "type": "object", "presets": [ { "name": "Using a Different Port", "keys": ["buildTarget", "port"] } @@ -125,7 +125,7 @@ { "required": ["browserTarget"] } ] }, - "description": "The `dev-server` executor is very similar to the standard `dev-server` builder provided by the Angular Devkit. It is usually used in tandem with `@nrwl/angular:webpack-browser` when your Angular application uses a custom webpack configuration.", + "description": "Serves an Angular application using [Webpack](https://webpack.js.org/) when the build target is using a Webpack-based executor, or [Vite](https://vitejs.dev/) when the build target uses an esbuild-based executor.", "aliases": [], "hidden": false, "path": "/packages/angular/src/builders/dev-server/schema.json", diff --git a/docs/generated/packages/angular/executors/webpack-browser.json b/docs/generated/packages/angular/executors/webpack-browser.json index 3b49517589e60..a40c5755854c0 100644 --- a/docs/generated/packages/angular/executors/webpack-browser.json +++ b/docs/generated/packages/angular/executors/webpack-browser.json @@ -554,9 +554,10 @@ "x-priority": "important", "additionalProperties": false }, - "indexFileTransformer": { + "indexHtmlTransformer": { "description": "Path to transformer function to transform the index.html", - "type": "string" + "type": "string", + "alias": "indexFileTransformer" }, "buildLibsFromSource": { "type": "boolean", diff --git a/docs/generated/packages/angular/generators/cypress-component-configuration.json b/docs/generated/packages/angular/generators/cypress-component-configuration.json index 02d49f3b16008..581d200181ac4 100644 --- a/docs/generated/packages/angular/generators/cypress-component-configuration.json +++ b/docs/generated/packages/angular/generators/cypress-component-configuration.json @@ -1,6 +1,6 @@ { "name": "cypress-component-configuration", - "factory": "./src/generators/cypress-component-configuration/cypress-component-configuration", + "factory": "./src/generators/cypress-component-configuration/cypress-component-configuration#cypressComponentConfigurationInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxAngularCypressComponentConfigurationGenerator", @@ -37,11 +37,11 @@ } }, "required": ["project"], - "examplesFile": "{% callout type=\"caution\" title=\"Can I use component testing?\" %}\nAngular component testing with Nx requires **Cypress version 10.7.0** and up.\n\nYou can migrate with to v10 via the [migrate-to-cypress-10 generator](/packages/cypress/generators/migrate-to-cypress-10).\n\nThis generator is for Cypress based component testing.\n\nIf you want to test components via Storybook with Cypress, then check out the [storybook-configuration generator docs](/nx-api/angular/generators/storybook-configuration). However, this functionality is deprecated, and will be removed on Nx version 18.\n{% /callout %}\n\nThis generator is designed to get your Angular project up and running with Cypress Component Testing.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nRunning this generator, adds the required files to the specified project with a preconfigured `cypress.config.ts` designed for Nx workspaces.\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: nxComponentTestingPreset(__filename),\n});\n```\n\nHere is an example on how to add custom options to the configuration\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: {\n ...nxComponentTestingPreset(__filename),\n // extra options here\n },\n});\n```\n\n## Specifying a Build Target\n\nComponent testing requires a _build target_ to correctly run the component test dev server. This option can be manually specified with `--build-target=some-angular-app:build`, but Nx will infer this usage from the [project graph](/concepts/mental-model#the-project-graph) if one isn't provided.\n\nFor Angular projects, the build target needs to be using the `@nx/angular:webpack-browser` or\n`@angular-devkit/build-angular:browser` executor.\nThe generator will throw an error if a build target can't be found and suggest passing one in manually.\n\nLetting Nx infer the build target by default\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nManually specifying the build target\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --build-target:some-angular-app:build --generate-tests\n```\n\n{% callout type=\"note\" title=\"Build Target with Configuration\" %}\nIf you're wanting to use a build target with a specific configuration. i.e. `my-app:build:production`,\nthen manually providing `--build-target=my-app:build:production` is the best way to do that.\n{% /callout %}\n\n## Auto Generating Tests\n\nYou can optionally use the `--generate-tests` flag to generate a test file for each component in your project.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --generate-tests\n```\n\n## Running Component Tests\n\nA new `component-test` target will be added to the specified project to run your component tests.\n\n```shell\nnx g component-test my-cool-angular-project\n```\n\nHere is an example of the project configuration that is generated. The `--build-target` option is added as the `devServerTarget` which can be changed as needed.\n\n```json {% fileName=\"project.json\" %}\n{\n \"targets\" {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"/cypress.config.ts\",\n \"testingType\": \"component\",\n \"devServerTarget\": \"some-angular-app:build\",\n \"skipServe\": true\n }\n }\n }\n}\n```\n\n## What is bundled\n\nWhen the project being tested is a dependent of the specified `--build-target`, then **assets, scripts, and styles** are applied to the component being tested. You can determine if the project is dependent by using the [project graph](/core-features/explore-graph). If there is no link between the two projects, then the **assets, scripts, and styles** won't be included in the build; therefore, they will not be applied to the component. To have a link between projects, you can import from the project being tested into the specified `--build-target` project, or set the `--build-target` project to [implicitly depend](/reference/project-configuration#implicitdependencies) on the project being tested.\n\nNx also supports [React component testing](/packages/angular/generators/cypress-component-configuration).\n", + "examplesFile": "{% callout type=\"caution\" title=\"Can I use component testing?\" %}\nAngular component testing with Nx requires **Cypress version 10.7.0** and up.\n\nYou can migrate with to v10 via the [migrate-to-cypress-10 generator](/packages/cypress/generators/migrate-to-cypress-10).\n\nThis generator is for Cypress based component testing.\n\nIf you want to test components via Storybook with Cypress, then check out the [storybook-configuration generator docs](/nx-api/angular/generators/storybook-configuration). However, this functionality is deprecated, and will be removed on Nx version 18.\n{% /callout %}\n\nThis generator is designed to get your Angular project up and running with Cypress Component Testing.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nRunning this generator, adds the required files to the specified project with a preconfigured `cypress.config.ts` designed for Nx workspaces.\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: nxComponentTestingPreset(__filename),\n});\n```\n\nHere is an example on how to add custom options to the configuration\n\n```ts {% fileName=\"cypress.config.ts\" %}\nimport { defineConfig } from 'cypress';\nimport { nxComponentTestingPreset } from '@nx/angular/plugins/component-testing';\n\nexport default defineConfig({\n component: {\n ...nxComponentTestingPreset(__filename),\n // extra options here\n },\n});\n```\n\n## Specifying a Build Target\n\nComponent testing requires a _build target_ to correctly run the component test dev server. This option can be manually specified with `--build-target=some-angular-app:build`, but Nx will infer this usage from the [project graph](/concepts/mental-model#the-project-graph) if one isn't provided.\n\nFor Angular projects, the build target needs to be using the `@nx/angular:webpack-browser` or\n`@angular-devkit/build-angular:browser` executor.\nThe generator will throw an error if a build target can't be found and suggest passing one in manually.\n\nLetting Nx infer the build target by default\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project\n```\n\nManually specifying the build target\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --build-target:some-angular-app:build --generate-tests\n```\n\n{% callout type=\"note\" title=\"Build Target with Configuration\" %}\nIf you're wanting to use a build target with a specific configuration. i.e. `my-app:build:production`,\nthen manually providing `--build-target=my-app:build:production` is the best way to do that.\n{% /callout %}\n\n## Auto Generating Tests\n\nYou can optionally use the `--generate-tests` flag to generate a test file for each component in your project.\n\n```shell\nnx g @nx/angular:cypress-component-configuration --project=my-cool-angular-project --generate-tests\n```\n\n## Running Component Tests\n\nA new `component-test` target will be added to the specified project to run your component tests.\n\n```shell\nnx g component-test my-cool-angular-project\n```\n\nHere is an example of the project configuration that is generated. The `--build-target` option is added as the `devServerTarget` which can be changed as needed.\n\n```json {% fileName=\"project.json\" %}\n{\n \"targets\" {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"/cypress.config.ts\",\n \"testingType\": \"component\",\n \"devServerTarget\": \"some-angular-app:build\",\n \"skipServe\": true\n }\n }\n }\n}\n```\n\n## What is bundled\n\nWhen the project being tested is a dependent of the specified `--build-target`, then **assets, scripts, and styles** are applied to the component being tested. You can determine if the project is dependent by using the [project graph](/features/explore-graph). If there is no link between the two projects, then the **assets, scripts, and styles** won't be included in the build; therefore, they will not be applied to the component. To have a link between projects, you can import from the project being tested into the specified `--build-target` project, or set the `--build-target` project to [implicitly depend](/reference/project-configuration#implicitdependencies) on the project being tested.\n\nNx also supports [React component testing](/packages/angular/generators/cypress-component-configuration).\n", "presets": [] }, "description": "Setup Cypress component testing for a project.", - "implementation": "/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.ts", + "implementation": "/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration#cypressComponentConfigurationInternal.ts", "aliases": [], "hidden": false, "path": "/packages/angular/src/generators/cypress-component-configuration/schema.json", diff --git a/docs/generated/packages/cypress/documents/overview.md b/docs/generated/packages/cypress/documents/overview.md index d785f02ad4dd7..0f0022e7e9cc8 100644 --- a/docs/generated/packages/cypress/documents/overview.md +++ b/docs/generated/packages/cypress/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Cypress Plugin +description: The Nx Plugin for Cypress contains executors and generators that support e2e testing with Cypress. This page also explains how to configure Cypress on your Nx workspace. +--- + Cypress is a test runner built for the modern web. It has a lot of great features: - Time travel @@ -7,33 +12,76 @@ Cypress is a test runner built for the modern web. It has a lot of great feature - Network traffic control - Screenshots and videos -## Setting Up Cypress +## Setting Up @nx/cypress > Info about [Cypress Component Testing can be found here](/recipes/cypress/cypress-component-testing) > > Info about [using Cypress and Storybook can be found here](/recipes/storybook/overview-react#cypress-tests-for-storiesbook) -If the `@nx/cypress` package is not installed, install the version that matches your `nx` package version. +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/cypress` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/cypress` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/cypress +nx add @nx/cypress ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/cypress`. -```shell -yarn add -D @nx/cypress +### How @nx/cypress Infers Tasks + +The `@nx/cypress` plugin will create a task for any project that has a Cypress configuration file present. Any of the following files will be recognized as a Cypress configuration file: + +- `cypress.config.js` +- `cypress.config.ts` +- `cypress.config.mjs` +- `cypress.config.mts` +- `cypress.config.cjs` +- `cypress.config.cts` + +### 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 --web` in the command line. + +### @nx/cypress Configuration + +The `@nx/cypress/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/cypress/plugin", + "options": { + "ciTargetName": "e2e-ci", + "targetName": "e2e", + "componentTestingTargetName": "component-test" + } + } + ] +} ``` +- The `targetName`, `ciTargetName` and `componentTestingTargetName` options control the namea of the inferred Cypress tasks. The default names are `e2e`, `e2e-ci` and `component-test`. + +### Splitting E2E tasks by file + +The `@nx/cypress/plugin` will automatically split your e2e tasks by file. You can read more about this feature [here](/ci/features/split-e2e-tasks). + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/cypress` package with your package manager. ```shell -pnpm add -D @nx/cypress +npm add -D @nx/cypress ``` {% /tab %} @@ -67,7 +115,7 @@ Replace `your-app-name` with the app's name as defined in your `tsconfig.base.js Run `nx e2e frontend-e2e` to execute e2e tests with Cypress. -You can run your e2e test against a production build by using the `production` [configuration](https://nx.dev/plugin-features/use-task-executors#use-executor-configurations) +You can run your e2e test against a production build by using the `production` [configuration](https://nx.dev/concepts/executors-and-configurations#use-task-configurations) ```shell nx e2e frontend-e2e --configuration=production diff --git a/docs/generated/packages/cypress/executors/cypress.json b/docs/generated/packages/cypress/executors/cypress.json index 7956bba477683..39a8227cbadd7 100644 --- a/docs/generated/packages/cypress/executors/cypress.json +++ b/docs/generated/packages/cypress/executors/cypress.json @@ -156,7 +156,7 @@ }, "additionalProperties": true, "required": ["cypressConfig"], - "examplesFile": "Depending on your testing type, the Cypress executor is configured in different ways. The following are sample configurations that are created via the [configuration](/packages/cypress/generators/configuration) and [cypress-component-configuration](/packages/cypress/generators/cypress-component-configuration) generators.\n\n{% tabs %}\n{% tab label=\"E2E Testing\" %}\n\n```json\n\"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app-e2e/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:serve\",\n \"testingType\": \"e2e\"\n }\n }\n}\n```\n\n{% callout type=\"note\" title=\"API Testing\" %}\nAPI testing with Cypress is the same setup as e2e testing. Just change which `devServerTarget` is used!\n{% /callout %}\n\n### Providing a Base URL\n\nIf `devServerTarget` is provided, the url returned from started the dev server will be passed to cypress as the `baseUrl` option.\n\nDefining a `baseUrl` in the executor options will override the inferred `baseUrl` from the `devServerTarget`.\n\nThe `baseUrl` defined in the Cypress config file is the last value used if no url is found in the `devServerTarget` or executor options.\n\n### Static Serving\n\nWhen running in CI it doesn't make sense to start up a dev server since there aren't changes to watch for.\n\nYou can use [`@nx/web:file-server`](/packages/web/executors/file-server) to serve the pre-built static files of your frontend project.\n\nIn some _frontend_ application, add a 'static-serve' target.\n\n```json\n\"serve-static\": {\n \"executor\": \"@nx/web:file-server\",\n \"options\":{\n \"buildTarget\": \"frontend:build\"\n }\n}\n```\n\nIn the _e2e_ application add a configuration to change `devServerTarget` to point to the `static-serve` from the _frontend_ application\n\n```json\n\"e2e\": {\n //...\n \"configurations\": {\n \"ci\": {\n \"devServerTarget\": \"frontend:serve-static\"\n }\n }\n}\n```\n\n{% callout type=\"note\" title=\"What about Node projects?\" %}\nThe same can be done for backend node apps with [`@nx/js:node` executor](/packages/js/executors/node)\n{% /callout %}\n\n```bash\nnx e2e my-app-e2e --configuration=ci\n```\n\n{% /tab %}\n{% tab label=\"Component Testing\" %}\n\n{% callout type=\"note\" title=\"Cypress Component Testing\" %}\nWhen adding component testing to a project, it's best to use the framework specific generator, instead `cypress-component-project` directly.\n\n- [React component testing](/packages/react/generators/cypress-component-configuration)\n- [Angular component testing](/packages/angular/generators/cypress-component-configuration)\n\n{% /callout %}\n\n```json\n\"targets\": {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:build\",\n \"testingType\": \"component\",\n \"skipServe\": true\n }\n }\n}\n```\n\nIt's important `skipServe` is set to true. Nx doesn't need to run the `devServerTarget`, Cypress creates its own dev server for component testing.\nInstead, Nx needs to know what build target to create the correct configuration to pass to Cypress, which is why it's still used in component testing.\n\n{% /tab %}\n{% /tabs %}\n\n### Environment Variables\n\nUsing [executor configurations](recipes/executors/use-executor-configurations#use-executor-configurations) offers flexibility to set environment variables\n\n```json\n\"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app-e2e/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:serve\",\n \"testingType\": \"e2e\"\n },\n \"configurations\": {\n \"qa\": {\n \"env\": {\n \"API_URL\": \"https://api.qa.company.com\"\n }\n },\n \"dev\": {\n \"env\": {\n \"API_URL\": \"http://localhost:3333/api\"\n }\n }\n }\n }\n}\n```\n\nRead more on different ways to use [environment variables for cypress executor](/packages/cypress#environment-variables)\n" + "examplesFile": "Depending on your testing type, the Cypress executor is configured in different ways. The following are sample configurations that are created via the [configuration](/packages/cypress/generators/configuration) and [cypress-component-configuration](/packages/cypress/generators/cypress-component-configuration) generators.\n\n{% tabs %}\n{% tab label=\"E2E Testing\" %}\n\n```json\n\"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app-e2e/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:serve\",\n \"testingType\": \"e2e\"\n }\n }\n}\n```\n\n{% callout type=\"note\" title=\"API Testing\" %}\nAPI testing with Cypress is the same setup as e2e testing. Just change which `devServerTarget` is used!\n{% /callout %}\n\n### Providing a Base URL\n\nIf `devServerTarget` is provided, the url returned from started the dev server will be passed to cypress as the `baseUrl` option.\n\nDefining a `baseUrl` in the executor options will override the inferred `baseUrl` from the `devServerTarget`.\n\nThe `baseUrl` defined in the Cypress config file is the last value used if no url is found in the `devServerTarget` or executor options.\n\n### Static Serving\n\nWhen running in CI it doesn't make sense to start up a dev server since there aren't changes to watch for.\n\nYou can use [`@nx/web:file-server`](/packages/web/executors/file-server) to serve the pre-built static files of your frontend project.\n\nIn some _frontend_ application, add a 'static-serve' target.\n\n```json\n\"serve-static\": {\n \"executor\": \"@nx/web:file-server\",\n \"options\":{\n \"buildTarget\": \"frontend:build\"\n }\n}\n```\n\nIn the _e2e_ application add a configuration to change `devServerTarget` to point to the `static-serve` from the _frontend_ application\n\n```json\n\"e2e\": {\n //...\n \"configurations\": {\n \"ci\": {\n \"devServerTarget\": \"frontend:serve-static\"\n }\n }\n}\n```\n\n{% callout type=\"note\" title=\"What about Node projects?\" %}\nThe same can be done for backend node apps with [`@nx/js:node` executor](/packages/js/executors/node)\n{% /callout %}\n\n```bash\nnx e2e my-app-e2e\n```\n\n{% /tab %}\n{% tab label=\"Component Testing\" %}\n\n{% callout type=\"note\" title=\"Cypress Component Testing\" %}\nWhen adding component testing to a project, it's best to use the framework specific generator, instead `cypress-component-project` directly.\n\n- [React component testing](/packages/react/generators/cypress-component-configuration)\n- [Angular component testing](/packages/angular/generators/cypress-component-configuration)\n\n{% /callout %}\n\n```json\n\"targets\": {\n \"component-test\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:build\",\n \"testingType\": \"component\",\n \"skipServe\": true\n }\n }\n}\n```\n\nIt's important `skipServe` is set to true. Nx doesn't need to run the `devServerTarget`, Cypress creates its own dev server for component testing.\nInstead, Nx needs to know what build target to create the correct configuration to pass to Cypress, which is why it's still used in component testing.\n\n{% /tab %}\n{% /tabs %}\n\n### Environment Variables\n\nUsing [executor configurations](recipes/executors/use-executor-configurations#use-executor-configurations) offers flexibility to set environment variables\n\n```json\n\"targets\": {\n \"e2e\": {\n \"executor\": \"@nx/cypress:cypress\",\n \"options\": {\n \"cypressConfig\": \"apps/app-e2e/cypres.config.ts\",\n \"devServerTarget\": \"my-react-app:serve\",\n \"testingType\": \"e2e\"\n },\n \"configurations\": {\n \"qa\": {\n \"env\": {\n \"API_URL\": \"https://api.qa.company.com\"\n }\n },\n \"dev\": {\n \"env\": {\n \"API_URL\": \"http://localhost:3333/api\"\n }\n }\n }\n }\n}\n```\n\nRead more on different ways to use [environment variables for cypress executor](/packages/cypress#environment-variables)\n" }, "description": "Run Cypress E2E tests.", "aliases": [], diff --git a/docs/generated/packages/cypress/generators/component-configuration.json b/docs/generated/packages/cypress/generators/component-configuration.json index db99da216e579..e089357ceeb68 100644 --- a/docs/generated/packages/cypress/generators/component-configuration.json +++ b/docs/generated/packages/cypress/generators/component-configuration.json @@ -1,7 +1,7 @@ { "name": "component-configuration", "aliases": ["cypress-component-configuration"], - "factory": "./src/generators/component-configuration/component-configuration", + "factory": "./src/generators/component-configuration/component-configuration#componentConfigurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxCypressComponentConfiguration", @@ -46,7 +46,7 @@ }, "description": "Set up Cypress Component Test for a project", "hidden": true, - "implementation": "/packages/cypress/src/generators/component-configuration/component-configuration.ts", + "implementation": "/packages/cypress/src/generators/component-configuration/component-configuration#componentConfigurationGeneratorInternal.ts", "path": "/packages/cypress/src/generators/component-configuration/schema.json", "type": "generator" } diff --git a/docs/generated/packages/cypress/generators/configuration.json b/docs/generated/packages/cypress/generators/configuration.json index f2d1a5fc48699..4925f64b63b00 100644 --- a/docs/generated/packages/cypress/generators/configuration.json +++ b/docs/generated/packages/cypress/generators/configuration.json @@ -1,7 +1,7 @@ { "name": "configuration", "aliases": ["cypress-e2e-configuration", "e2e", "e2e-config"], - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#configurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxCypressE2EConfigGenerator", @@ -93,7 +93,7 @@ "presets": [] }, "description": "Add a Cypress E2E Configuration to an existing project.", - "implementation": "/packages/cypress/src/generators/configuration/configuration.ts", + "implementation": "/packages/cypress/src/generators/configuration/configuration#configurationGeneratorInternal.ts", "hidden": false, "path": "/packages/cypress/src/generators/configuration/schema.json", "type": "generator" diff --git a/docs/generated/packages/cypress/generators/init.json b/docs/generated/packages/cypress/generators/init.json index 1059b58cb4594..7a383e52da298 100644 --- a/docs/generated/packages/cypress/generators/init.json +++ b/docs/generated/packages/cypress/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#cypressInitGenerator", + "factory": "./src/generators/init/init#cypressInitGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxCypressInit", @@ -39,7 +39,7 @@ "description": "Initialize the `@nrwl/cypress` plugin.", "aliases": ["ng-add"], "hidden": true, - "implementation": "/packages/cypress/src/generators/init/init#cypressInitGenerator.ts", + "implementation": "/packages/cypress/src/generators/init/init#cypressInitGeneratorInternal.ts", "path": "/packages/cypress/src/generators/init/schema.json", "type": "generator" } diff --git a/docs/generated/packages/detox/documents/overview.md b/docs/generated/packages/detox/documents/overview.md index 5f894f477e9c6..af5cd72b508cf 100644 --- a/docs/generated/packages/detox/documents/overview.md +++ b/docs/generated/packages/detox/documents/overview.md @@ -8,7 +8,9 @@ Detox is gray box end-to-end testing and automation library for mobile apps. It ## Setting Up Detox -### Install applesimutils (Mac only) +### Setup Environment + +#### Install applesimutils (Mac only) [applesimutils](https://github.com/wix/AppleSimulatorUtils) is a collection of utils for Apple simulators. @@ -17,59 +19,80 @@ brew tap wix/brew brew install applesimutils ``` -### Install Jest Globally +#### Install Jest Globally ```sh npm install -g jest ``` -### Generating Applications +### Installation -By default, when creating a mobile application, Nx will use Detox to create the e2e tests project. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/detox` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/detox` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} ```shell -nx g @nx/react-native:app frontend +nx add @nx/detox ``` -### Creating a Detox E2E project for an existing project +This will install the correct version of `@nx/detox`. -You can create a new Detox E2E project for an existing mobile project. +### How @nx/detox Infers Tasks -If the `@nx/detox` package is not installed, install the version that matches your `@nx/workspace` version. +The `@nx/detox` plugin will create a task for any project that has an ESLint configuration file present. Any of the following files will be recognized as an ESLint configuration file: -{% tabs %} -{% tab label="npm" %} +- `.detoxrc.js` +- `.detoxrc.json` +- `detox.config.js` +- `detox.config.json` -```shell -npm add -D @nx/detox -``` +### View Inferred Tasks -{% /tab %} -{% tab label="yarn" %} +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 --web` in the command line. -```shell -yarn add -D @nx/detox -``` +### @nx/detox Configuration -{% /tab %} -{% tab label="pnpm" %} +The `@nx/detox/plugin` is configured in the `plugins` array in `nx.json`. -```shell -pnpm add -D @nx/detox +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/detox/plugin", + "options": { + "buildTargetName": "build", + "startTargetName": "start", + "testTargetName": "test" + } + } + ] +} ``` +Once a Detox configuration file has been identified, the targets are created with the name you specify under `buildTargetName`, `startTargetName` or `testTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `build` and `test`. + {% /tab %} -{% /tabs %} +{% tab label="Nx < 18" %} -Next, generate an E2E project based on an existing project. +Install the `@nx/detox` package with your package manager. -```sh -nx g @nx/detox:app your-app-name-e2e --project=your-app-name +```shell +npm add -D @nx/detox ``` -Replace `your-app-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json`. +### Generating Applications + +By default, when creating a mobile application, Nx will use Detox to create the e2e tests project. -In addition, you need to follow [instructions at Detox](https://github.com/wix/Detox/blob/master/docs/Introduction.Android.md) to do manual setup for Android files. +```shell +nx g @nx/react-native:app frontend --e2eTestRunner=deotx +nx g @nx/expo:app frontend --e2eTestRunner=detox +``` ## Using Detox diff --git a/docs/generated/packages/detox/generators/init.json b/docs/generated/packages/detox/generators/init.json index 805edb186d3bf..8387f89511496 100644 --- a/docs/generated/packages/detox/generators/init.json +++ b/docs/generated/packages/detox/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#detoxInitGenerator", + "factory": "./src/generators/init/init#detoxInitGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "title": "Add Detox Schematics", @@ -37,7 +37,7 @@ }, "description": "Initialize the `@nrwl/detox` plugin.", "hidden": true, - "implementation": "/packages/detox/src/generators/init/init#detoxInitGenerator.ts", + "implementation": "/packages/detox/src/generators/init/init#detoxInitGeneratorInternal.ts", "aliases": [], "path": "/packages/detox/src/generators/init/schema.json", "type": "generator" diff --git a/docs/generated/packages/esbuild/documents/overview.md b/docs/generated/packages/esbuild/documents/overview.md index 577d15f763f8b..e472942780ea2 100644 --- a/docs/generated/packages/esbuild/documents/overview.md +++ b/docs/generated/packages/esbuild/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx esbuild Plugin +description: The Nx Plugin for esbuild contains executors and generators that support building applications using esbuild. This page also explains how to configure esbuild on your Nx workspace. +--- + The Nx Plugin for [esbuild](https://esbuild.github.io/api/), an extremely fast JavaScript bundler. Why should you use this plugin? @@ -7,40 +12,39 @@ Why should you use this plugin? - Intelligent `package.json` output. - Additional [assets](/nx-api/esbuild/executors/esbuild#assets) for the output. -## Setting up esbuild +## Setting Up @nx/esbuild -To create a new workspace, run `npx create-nx-workspace@latest --preset=npm`. +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/esbuild` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the esbuild plugin to an existing workspace, run the following: +In any Nx workspace, you can install `@nx/esbuild` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/esbuild +nx add @nx/esbuild ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/esbuild -``` +This will install the correct version of `@nx/esbuild`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/esbuild` package with your package manager. ```shell -pnpm add -D @nx/esbuild +npm add -D @nx/esbuild ``` {% /tab %} {% /tabs %} +## Using the @nx/esbuild Plugin + ### Creating a new JS library {% callout type="note" title="Directory Flag Behavior Changes" %} diff --git a/docs/generated/packages/eslint-plugin/documents/enforce-module-boundaries.md b/docs/generated/packages/eslint-plugin/documents/enforce-module-boundaries.md index 0bffdba043751..0c2d127ad7383 100644 --- a/docs/generated/packages/eslint-plugin/documents/enforce-module-boundaries.md +++ b/docs/generated/packages/eslint-plugin/documents/enforce-module-boundaries.md @@ -53,7 +53,7 @@ The `depConstraints` is an array of objects representing the constraints defined Read more about the proper usage of this rule: -- [Enforce Module Boundaries](/core-features/enforce-module-boundaries) +- [Enforce Module Boundaries](/features/enforce-module-boundaries) - [Ban Dependencies with Certain Tags](/recipes/enforce-module-boundaries/ban-dependencies-with-tags) - [Tag in Multiple Dimensions](/recipes/enforce-module-boundaries/tag-multiple-dimensions) - [Ban External Imports](/recipes/enforce-module-boundaries/ban-external-imports) diff --git a/docs/generated/packages/eslint-plugin/documents/overview.md b/docs/generated/packages/eslint-plugin/documents/overview.md index b87b4e4285e21..9036a11648559 100644 --- a/docs/generated/packages/eslint-plugin/documents/overview.md +++ b/docs/generated/packages/eslint-plugin/documents/overview.md @@ -13,30 +13,10 @@ Make sure to install the `@nx/eslint-plugin` version that matches the version of In any Nx workspace, you can install `@nx/eslint-plugin` by running the following commands if the package is not already installed: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/eslint-plugin -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/eslint-plugin +nx add @nx/eslint-plugin ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/eslint-plugin -``` - -{% /tab %} -{% /tabs %} - ## Included plugins The plugin contains the following rule configurations divided into sub-plugins. diff --git a/docs/generated/packages/eslint/documents/overview.md b/docs/generated/packages/eslint/documents/overview.md index d5cf2a6f4360d..ca49e9ce2d73f 100644 --- a/docs/generated/packages/eslint/documents/overview.md +++ b/docs/generated/packages/eslint/documents/overview.md @@ -1,6 +1,6 @@ -The ESLint plugin contains executors, generator, plugin and utilities used for linting JavaScript/TypeScript projects within an Nx workspace. +The ESLint plugin integrates [ESLint](https://eslint.org/) with Nx. It allows you to run ESLint through Nx with caching enabled. It also includes code generators to help you set up ESLint in your workspace. -## Setting Up ESLint +## Setting Up @nx/eslint ### Installation @@ -11,24 +11,58 @@ Make sure to install the `@nx/eslint` version that matches the version of `nx` i In any Nx workspace, you can install `@nx/eslint` by running the following command: {% tabs %} -{%tab label="npm"%} +{% tab label="Nx 18+" %} ```shell -npm i -D @nx/eslint +nx add @nx/eslint ``` -{% /tab %} -{%tab label="yarn"%} +This will install the correct version of `@nx/eslint`. -```shell -yarn add -D @nx/eslint +### How @nx/eslint Infers Tasks + +The `@nx/eslint` plugin will create a task for any project that has an ESLint configuration file present. Any of the following files will be recognized as an ESLint configuration file: + +- `.eslintrc` +- `.eslintrc.js` +- `.eslintrc.cjs` +- `.eslintrc.yaml` +- `.eslintrc.yml` +- `.eslintrc.json` +- `eslint.config.js` + +Because ESLint applies configuration files to all subdirectories, the `@nx/eslint` plugin will also infer tasks for projects in subdirectories. So, if there is an ESLint configuration file in the root of the repository, every project will have an inferred ESLint task. + +### 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 --web` in the command line. + +### @nx/eslint Configuration + +The `@nx/eslint/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + } + ] +} ``` +- The `targetName` option controls the name of the inferred ESLint tasks. The default name is `lint`. + {% /tab %} -{%tab label="pnpm"%} +{% tab label="Nx < 18" %} + +Install the `@nx/eslint` package with your package manager. ```shell -pnpm add -D @nx/eslint +npm add -D @nx/eslint ``` {% /tab %} diff --git a/docs/generated/packages/eslint/generators/init.json b/docs/generated/packages/eslint/generators/init.json index 994ed4650209d..28e2fd64100e0 100644 --- a/docs/generated/packages/eslint/generators/init.json +++ b/docs/generated/packages/eslint/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#lintInitGenerator", + "factory": "./src/generators/init/init#initEsLint", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -32,7 +32,7 @@ }, "description": "Set up the ESLint plugin.", "hidden": true, - "implementation": "/packages/eslint/src/generators/init/init#lintInitGenerator.ts", + "implementation": "/packages/eslint/src/generators/init/init#initEsLint.ts", "aliases": [], "path": "/packages/eslint/src/generators/init/schema.json", "type": "generator" diff --git a/docs/generated/packages/expo/documents/overview.md b/docs/generated/packages/expo/documents/overview.md index 67551bd597a0e..9ee33616ac22d 100644 --- a/docs/generated/packages/expo/documents/overview.md +++ b/docs/generated/packages/expo/documents/overview.md @@ -4,44 +4,87 @@ Expo is a set of tools built on top of React Native. The Nx Plugin for Expo cont ## Setting Up Expo -To create a new workspace with expo, run the following command: +To create a new workspace with Expo, run the following command: ```shell - npx create-nx-workspace --preset=expo + npx create-nx-workspace@latest --preset=expo --appName=your-app-name ``` -### Adding Expo to an Existing Project - -Install the expo plugin +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/expo` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/expo` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/expo +nx add @nx/expo ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/expo`. -```shell -yarn add -D @nx/expo +### How @nx/expo Infers Tasks + +The `@nx/expo` plugin will create a task for any project that has an app configuration file present. Any of the following files will be recognized as an app configuration file: + +- `app.config.js` +- `app.json` + +In the app config file, it needs to have key `expo`: + +```json +{ + "expo": { + "name": "MyProject", + "slug": "my-project" + } +} ``` +### 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 --web` in the command line. + +### @nx/expo Configuration + +The `@nx/expo/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/expo/plugin", + "options": { + "startTargetName": "start", + "serveTargetName": "serve", + "runIosTargetName": "run-ios", + "runAndroidTargetName": "run-android", + "exportTargetName": "export", + "prebuildTargetName": "prebuild", + "installTargetName": "install", + "buildTargetName": "build", + "submitTargetName": "submit" + } + } + ] +} +``` + +Once a Expo configuration file has been identified, the targets are created with the name you specify under `startTargetName`, `serveTargetName`, `runIosTargetName`, `runAndroidTargetname`, `exportTargetName`, `prebuildTargetName`, `installTargetName`, `buildTargetName` or `submitTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `start`, `serve`, `run-ios`, `run-anroid`, `export`, `prebuild`, `install`, `build` and `submit`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/expo` package with your package manager. ```shell -pnpm add -D @nx/expo +npm add -D @nx/expo ``` -{% /tab %} -{% /tabs %} - ### Creating Applications Add a new application to your workspace with the following command: diff --git a/docs/generated/packages/expo/generators/init.json b/docs/generated/packages/expo/generators/init.json index 616eff371b5fd..f3449f388e75a 100644 --- a/docs/generated/packages/expo/generators/init.json +++ b/docs/generated/packages/expo/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#expoInitGenerator", + "factory": "./src/generators/init/init#expoInitGeneratorInternal", "schema": { "cli": "nx", "$id": "NxExpoInit", @@ -35,9 +35,9 @@ "required": [], "presets": [] }, - "description": "Initialize the @nrwl/expo plugin", + "description": "Initialize the @nx/expo plugin", "hidden": true, - "implementation": "/packages/expo/src/generators/init/init#expoInitGenerator.ts", + "implementation": "/packages/expo/src/generators/init/init#expoInitGeneratorInternal.ts", "aliases": [], "path": "/packages/expo/src/generators/init/schema.json", "type": "generator" diff --git a/docs/generated/packages/express/documents/overview.md b/docs/generated/packages/express/documents/overview.md index 8709622944378..abda6b0ea476f 100644 --- a/docs/generated/packages/express/documents/overview.md +++ b/docs/generated/packages/express/documents/overview.md @@ -9,6 +9,37 @@ To create a new workspace with a pre-created Express app, run the following comm npx create-nx-workspace --preset=express ``` +## Setting Up @nx/express + +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/express` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/express` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/express +``` + +This will install the correct version of `@nx/express`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/express` package with your package manager. + +```shell +npm add -D @nx/express +``` + +{% /tab %} +{% /tabs %} + ## Recipes - [Add an Express Application to Your Workspace](/showcase/example-repos/add-express) diff --git a/docs/generated/packages/jest/documents/overview.md b/docs/generated/packages/jest/documents/overview.md index c8b02f9bfc9b2..c42b3d0fa6e40 100644 --- a/docs/generated/packages/jest/documents/overview.md +++ b/docs/generated/packages/jest/documents/overview.md @@ -1,52 +1,92 @@ +--- +title: Overview of the Nx Jest Plugin +description: The Nx Plugin for Jest contains executors and generators that support testing projects using Jest. This page also explains how to configure Jest on your Nx workspace. +--- + [Jest](https://jestjs.io/) is an open source test runner created by Facebook. It has a lot of great features: - Immersive watch mode for providing near instant feedback when developing tests. - Snapshot testing for validating features. - Great built-in reporter for printing out test results. -## Setting up Jest +## Setting Up @nx/jest -By default, Nx will use Jest when creating applications and libraries. +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/jest` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} ```shell -nx g @nx/web:app frontend +nx add @nx/jest ``` -### Adding Jest to an Existing Project +This will install the correct version of `@nx/jest`. -Add Jest to a project using the `configuration` generator from `@nx/jest`. +### How @nx/jest Infers Tasks -First, install `@nx/jest`, if not already installed using your preferred package manager. +The `@nx/jest` plugin will create a task for any project that has an Jest configuration file present. Any of the following files will be recognized as an Jest configuration file: -{% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). -{% /callout %} +- `jest.config.js` +- `jest.config.ts` +- `jest.config.mjs` +- `jest.config.mts` +- `jest.config.cjs` +- `jest.config.cts` -{% tabs %} -{% tab label="npm" %} +### View Inferred Tasks -```shell -npm add -D @nx/jest +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 --web` in the command line. + +### @nx/jest Configuration + +The `@nx/jest/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/jest/plugin", + "options": { + "targetName": "test" + } + } + ] +} ``` +- The `targetName` option controls the name of the inferred Jest tasks. The default name is `test`. + {% /tab %} -{% tab label="yarn" %} +{% tab label="Nx < 18" %} + +Install the `@nx/jest` package with your package manager. ```shell -yarn add -D @nx/jest +npm add -D @nx/jest ``` {% /tab %} -{% tab label="pnpm" %} +{% /tabs %} + +## Using Jest + +### Generate a new project set up with Jest + +By default, Nx will use Jest when creating applications and libraries. ```shell -pnpm add -D @nx/jest +nx g @nx/web:app frontend ``` -{% /tab %} -{% /tabs %} +### Add Jest to a project -Once installed, run the `configuration` generator +Run the `configuration` generator ```shell nx g @nx/jest:configuration --project= @@ -56,8 +96,6 @@ nx g @nx/jest:configuration --project= Replacing `` with the name of the project you're wanting to add Jest too. -## Using Jest - ### Testing Applications The recommended way to run/debug Jest tests via an editor diff --git a/docs/generated/packages/jest/executors/jest.json b/docs/generated/packages/jest/executors/jest.json index 1c155bc251750..07818365c09ae 100644 --- a/docs/generated/packages/jest/executors/jest.json +++ b/docs/generated/packages/jest/executors/jest.json @@ -198,7 +198,7 @@ } }, "required": ["jestConfig"], - "examplesFile": "Jest can be configured in many ways, but primarily you'll need to at least have the jestConfig options\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\"\n }\n}\n```\n\nIt is also helpful to have `passWithNoTests: true` set so your project doesn't fail testing while tests are still being added.\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\",\n \"passWithNoTests\": true\n }\n}\n```\n\n### Snapshots\n\nUpdate snapshots running with `--update-snapshot` or `-u` for short.\n\n```bash\nnx test my-project -u\n```\n\nOther times you might not want to allow updating snapshots such as in CI.\nAdding a _ci_ configuration is helpful for adding this behavior.\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\",\n \"passWithNoTests\": true\n },\n \"configurations\": {\n \"ci\": {\n \"ci\": true\n }\n }\n}\n```\n\n```bash\nnx affected --target=test --configuration=ci\n```\n\nLearn more [about _affected_](/ci/features/affected)\n" + "examplesFile": "Jest can be configured in many ways, but primarily you'll need to at least have the jestConfig options\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\"\n }\n}\n```\n\nIt is also helpful to have `passWithNoTests: true` set so your project doesn't fail testing while tests are still being added.\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\",\n \"passWithNoTests\": true\n }\n}\n```\n\n### Snapshots\n\nUpdate snapshots running with `--update-snapshot` or `-u` for short.\n\n```bash\nnx test my-project -u\n```\n\nOther times you might not want to allow updating snapshots such as in CI.\nAdding a _ci_ configuration is helpful for adding this behavior.\n\n```json\n\"test\": {\n \"executor\": \"@nx/jest:jest\",\n \"options\": {\n \"jestConfig\": \"libs/my-lib/jest.config.ts\",\n \"passWithNoTests\": true\n },\n \"configurations\": {\n \"ci\": {\n \"ci\": true\n }\n }\n}\n```\n\n```bash\nnx affected --target=test\n```\n\nLearn more [about _affected_](/ci/features/affected)\n" }, "description": "Run Jest unit tests.", "aliases": [], diff --git a/docs/generated/packages/jest/generators/configuration.json b/docs/generated/packages/jest/generators/configuration.json index 89028bffd4d36..9528f13bd989d 100644 --- a/docs/generated/packages/jest/generators/configuration.json +++ b/docs/generated/packages/jest/generators/configuration.json @@ -1,6 +1,6 @@ { "name": "configuration", - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#configurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxJestProject", @@ -82,7 +82,7 @@ }, "description": "Add Jest configuration to a project.", "hidden": true, - "implementation": "/packages/jest/src/generators/configuration/configuration.ts", + "implementation": "/packages/jest/src/generators/configuration/configuration#configurationGeneratorInternal.ts", "aliases": [], "path": "/packages/jest/src/generators/configuration/schema.json", "type": "generator" diff --git a/docs/generated/packages/jest/generators/init.json b/docs/generated/packages/jest/generators/init.json index 2595f1879def5..445a2a287750b 100644 --- a/docs/generated/packages/jest/generators/init.json +++ b/docs/generated/packages/jest/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#jestInitGenerator", + "factory": "./src/generators/init/init#jestInitGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxJestInit", @@ -40,7 +40,7 @@ "description": "Initialize the `@nrwl/jest` plugin.", "aliases": ["ng-add"], "hidden": true, - "implementation": "/packages/jest/src/generators/init/init#jestInitGenerator.ts", + "implementation": "/packages/jest/src/generators/init/init#jestInitGeneratorInternal.ts", "path": "/packages/jest/src/generators/init/schema.json", "type": "generator" } diff --git a/docs/generated/packages/js/documents/overview.md b/docs/generated/packages/js/documents/overview.md index 2474d369dbb05..0548e3c69e00e 100644 --- a/docs/generated/packages/js/documents/overview.md +++ b/docs/generated/packages/js/documents/overview.md @@ -1,6 +1,11 @@ +--- +title: Overview of the Nx JS Plugin +description: The Nx JS plugin contains executors and generators that are useful for JavaScript/TypeScript projects in an Nx workspace. +--- + The JS plugin contains executors and generators that are useful for JavaScript/TypeScript projects in an Nx workspace. -## Setting Up JS +## Setting Up @nx/js ### Installation @@ -8,27 +13,24 @@ The JS plugin contains executors and generators that are useful for JavaScript/T Make sure to install the `@nx/js` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -In any Nx workspace, you can install `@nx/js` by running the following commands if `@nx/js` package is not installed: +In any Nx workspace, you can install `@nx/js` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/js +nx add @nx/js ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/js -``` +This will install the correct version of `@nx/js`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/js` package with your package manager. ```shell -pnpm add -D @nx/js +npm add -D @nx/js ``` {% /tab %} diff --git a/docs/generated/packages/nest/documents/overview.md b/docs/generated/packages/nest/documents/overview.md index b4b4fd2608fe2..df9b7fe9ec2f5 100644 --- a/docs/generated/packages/nest/documents/overview.md +++ b/docs/generated/packages/nest/documents/overview.md @@ -7,7 +7,9 @@ Nest.js is a framework designed for building scalable server-side applications. Many conventions and best practices used in Angular applications can be also be used in Nest. -## Setting Up Nest +## Setting Up @nx/nest + +### Generating a new workspace To create a new workspace with Nest, run the following command: @@ -21,31 +23,30 @@ Yarn users can use the following command instead: yarn create nx-workspace my-workspace --preset=nest ``` +### Installation + {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/nest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the Nest plugin to an existing workspace, run one the following commands: +In any Nx workspace, you can install `@nx/nest` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/nest +nx add @nx/nest ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/nest -``` +This will install the correct version of `@nx/nest`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/nest` package with your package manager. ```shell -pnpm add -D @nx/nest +npm add -D @nx/nest ``` {% /tab %} diff --git a/docs/generated/packages/next/documents/overview.md b/docs/generated/packages/next/documents/overview.md index 0a0f056e6717f..012d307e277dd 100644 --- a/docs/generated/packages/next/documents/overview.md +++ b/docs/generated/packages/next/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Next.js Plugin +description: The Nx Next.js plugin contains executors and generators for managing Next.js applications and libraries within an Nx workspace. This page also explains how to configure Next.js on your Nx workspace. +--- + When using Next.js in Nx, you get the out-of-the-box support for TypeScript, Cypress, and Jest. No need to configure anything: watch mode, source maps, and typings just work. The Next.js plugin contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides: @@ -6,36 +11,80 @@ The Next.js plugin contains executors and generators for managing Next.js applic - Integration with building, serving, and exporting a Next.js application. - Integration with React libraries within the workspace. -## Setting up Next.js +## Setting up @nx/next + +To create a new Nx workspace with Next.js, run: + +```shell +npx create-nx-workspace@latest --preset=next +``` + +### Installation -To create a new Nx workspace with Next.js, run `npx create-nx-workspace@latest --preset=next`. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/next` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -To add Next.js to an existing Nx workspace, install the `@nx/next` package. Make sure to install the version that matches your `nx` version. +In any workspace, you can install `@nx/next` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/next +nx add @nx/next ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/next`. -```shell -yarn add -D @nx/next +### How @nx/next Infers Tasks + +The `@nx/next` plugin will create tasks for any project that has a Next.js configuration file preset. Any of the following files will be recognized as a Next.js configuration file: + +- `next.config.js` +- `next.config.cjs` +- `next.config.mjs` + +### 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 --web` in your command line. + +### @nx/next Configuration + +The `@nx/next/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/next/plugin", + "options": { + "buildTargetName": "build", + "devTargetName": "dev", + "startTargetName": "start" + } + } + ] +} ``` +- The `buildTargetName` option controls the name of Next.js' compilation task which compiles the application for production deployment. The default name is `build`. +- The `devTargetName` option controls the name of Next.js' development serve task which starts the application in development mode. The default name is `dev`. +- The `startTargetName` option controls the name of Next.js' production serve task which starts the application in production mode. The default name is `start`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/next` package with your package manager. ```shell -pnpm add -D @nx/next +npm add -D @nx/next ``` {% /tab %} {% /tabs %} +## Using @nx/next + ### Creating Applications You can add a new application with the following: @@ -79,7 +128,28 @@ Nx generates components with tests by default. For pages, you can pass the `--wi ### Serving Next.js Applications -You can run `nx serve my-new-app` to serve a Next.js application called `my-new-app` for development. This will start the dev server at http://localhost:4200. +{% tabs %} + +{% tab label="Nx 18+" %} + +You can serve a Next.js application `my-new-app` for development: + +```shell +nx dev my-new-app +``` + +To serve a Next.js application for production: + +```shell +nx start my-new-app +``` + +This will start the server at by default. + +{% /tab %} +{% tab label="Nx < 18" %} + +You can run `nx serve my-new-app` to serve a Next.js application called `my-new-app` for development. This will start the dev server at . To serve a Next.js application for production, add the `--prod` flag to the serve command: @@ -87,6 +157,9 @@ To serve a Next.js application for production, add the `--prod` flag to the serv nx serve my-new-app --prod ``` +{% /tab %} +{% /tabs %} + ### Using an Nx Library in your Application You can import a library called `my-new-lib` in your application as follows. @@ -165,10 +238,15 @@ The library in `dist` is publishable to npm or a private registry. ### Static HTML Export -Next.js applications can be statically exported with: +Next.js applications can be statically exported by changing th eoutput inside your Next.js configuration file. -```shell -nx export my-new-app +```js {% fileName="apps/my-next-app/next.config.js" %} +const nextConfig = { + output: 'export', + nx: { + svgr: false, + }, +}; ``` ### Deploying Next.js Applications diff --git a/docs/generated/packages/next/generators/cypress-component-configuration.json b/docs/generated/packages/next/generators/cypress-component-configuration.json index 5f982889ddc3c..3b011608eeed5 100644 --- a/docs/generated/packages/next/generators/cypress-component-configuration.json +++ b/docs/generated/packages/next/generators/cypress-component-configuration.json @@ -1,6 +1,6 @@ { "name": "cypress-component-configuration", - "factory": "./src/generators/cypress-component-configuration/cypress-component-configuration", + "factory": "./src/generators/cypress-component-configuration/cypress-component-configuration#cypressComponentConfigurationInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -45,7 +45,7 @@ "presets": [] }, "description": "cypress-component-configuration generator", - "implementation": "/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration.ts", + "implementation": "/packages/next/src/generators/cypress-component-configuration/cypress-component-configuration#cypressComponentConfigurationInternal.ts", "aliases": [], "hidden": false, "path": "/packages/next/src/generators/cypress-component-configuration/schema.json", diff --git a/docs/generated/packages/next/generators/init.json b/docs/generated/packages/next/generators/init.json index 55b9f7888bb73..9aec03f12b633 100644 --- a/docs/generated/packages/next/generators/init.json +++ b/docs/generated/packages/next/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#nextInitGenerator", + "factory": "./src/generators/init/init#nextInitGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -38,7 +38,7 @@ }, "description": "Initialize the `@nrwl/next` plugin.", "hidden": true, - "implementation": "/packages/next/src/generators/init/init#nextInitGenerator.ts", + "implementation": "/packages/next/src/generators/init/init#nextInitGeneratorInternal.ts", "aliases": [], "path": "/packages/next/src/generators/init/schema.json", "type": "generator" diff --git a/docs/generated/packages/node/documents/overview.md b/docs/generated/packages/node/documents/overview.md index 21aa25e0e3e5b..ce2127391e9fd 100644 --- a/docs/generated/packages/node/documents/overview.md +++ b/docs/generated/packages/node/documents/overview.md @@ -1,37 +1,38 @@ The Node Plugin contains generators and executors to manage Node applications within an Nx workspace. It provides: -## Setting Up Node +## Setting Up @nx/node + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/node` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the Node plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/node` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/node +nx add @nx/node ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/node -``` +This will install the correct version of `@nx/node`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/node` package with your package manager. ```shell -pnpm add -D @nx/node +npm add -D @nx/node ``` {% /tab %} {% /tabs %} +## Using the @nx/node Plugin + ### Creating Applications You can add a new application with the following: diff --git a/docs/generated/packages/nuxt/documents/overview.md b/docs/generated/packages/nuxt/documents/overview.md index 9eb93e516a5d8..6440d1768d5d6 100644 --- a/docs/generated/packages/nuxt/documents/overview.md +++ b/docs/generated/packages/nuxt/documents/overview.md @@ -5,7 +5,7 @@ description: The Nx Plugin for Nuxt contains generators for managing Nuxt applic The Nx plugin for [Nuxt](https://nuxt.com/). -## Setting up a new Nx workspace with Nuxt +## Setting up a new Nx workspace with @nx/nuxt You can create a new workspace that uses Nuxt with one of the following commands: @@ -15,35 +15,57 @@ You can create a new workspace that uses Nuxt with one of the following commands npx create-nx-workspace@latest --preset=nuxt ``` -## Add Nuxt to an existing workspace +### Installation -There are a number of ways to use Nuxt in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/nuxt` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -### Install the `@nx/nuxt` plugin - -{% tabs %} -{% tab label="npm" %} +In any Nx workspace, you can install `@nx/nuxt` by running the following command: ```shell -npm add -D @nx/nuxt +nx add @nx/nuxt ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/nuxt`. -```shell -yarn add -D @nx/nuxt -``` +### How @nx/nuxt Infers Tasks -{% /tab %} -{% tab label="pnpm" %} +The `@nx/nuxt` plugin will create a task for any project that has an Nuxt configuration file present. Any of the following files will be recognized as an Nuxt configuration file: -```shell -pnpm add -D @nx/nuxt +- `nuxt.config.js` +- `nuxt.config.ts` +- `nuxt.config.mjs` +- `nuxt.config.mts` +- `nuxt.config.cjs` +- `nuxt.config.cts` + +### 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 --web` in the command line. + +### @nx/nuxt Configuration + +The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/nuxt/plugin", + "options": { + "buildTargetName": "build", + "testTargetName": "test", + "serveTargetName": "serve" + } + } + ] +} ``` -{% /tab %} -{% /tabs %} +- The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`. + +## Using Nuxt ### Generate a new Nuxt app diff --git a/docs/generated/packages/nx/documents/add.md b/docs/generated/packages/nx/documents/add.md index cc8e359234370..40b53cd2e18c5 100644 --- a/docs/generated/packages/nx/documents/add.md +++ b/docs/generated/packages/nx/documents/add.md @@ -53,7 +53,7 @@ The package name and optional version (e.g. `@nx/react` or `@nx/react@latest`) t Type: `boolean` -Update `package.json` scripts with inferred targets. Defaults to `true` when `NX_PCV3=true` and the package is a core Nx plugin +Update `package.json` scripts with inferred targets. Defaults to `true` when the package is a core Nx plugin ### verbose diff --git a/docs/generated/packages/nx/documents/init.md b/docs/generated/packages/nx/documents/init.md index f7489013bb241..c56f35d275066 100644 --- a/docs/generated/packages/nx/documents/init.md +++ b/docs/generated/packages/nx/documents/init.md @@ -17,36 +17,12 @@ Install `nx` globally to invoke the command directly using `nx`, or use `npx nx` ## Options -### addE2e - -Type: `boolean` - -Default: `false` - -Set up Cypress E2E tests in integrated workspaces. Only for CRA projects. - -### force - -Type: `boolean` - -Default: `false` - -Force the migration to continue and ignore custom webpack setup or uncommitted changes. Only for CRA projects. - ### help Type: `boolean` Show help -### integrated - -Type: `boolean` - -Default: `false` - -Migrate to an Nx integrated layout workspace. Only for Angular CLI workspaces and CRA projects. - ### interactive Type: `boolean` @@ -59,7 +35,7 @@ When false disables interactive input prompts for options. Type: `boolean` -Set up remote caching with Nx Cloud. +Set up distributed caching with Nx Cloud. ### useDotNxInstallation @@ -74,11 +50,3 @@ Initialize an Nx workspace setup in the .nx directory of the current repository. Type: `boolean` Show version number - -### vite - -Type: `boolean` - -Default: `true` - -Use Vite as the bundler. Only for CRA projects. diff --git a/docs/generated/packages/playwright/documents/overview.md b/docs/generated/packages/playwright/documents/overview.md index c01e59e715428..730ed65055932 100644 --- a/docs/generated/packages/playwright/documents/overview.md +++ b/docs/generated/packages/playwright/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Playwright Plugin +description: The Nx Plugin for Playwright contains executors and generators that support e2e testing with Playwright. This page also explains how to configure Playwright on your Nx workspace. +--- + Playwright is a modern web test runner. With included features such as: - Cross browser support, including mobile browsers @@ -6,29 +11,71 @@ Playwright is a modern web test runner. With included features such as: - Test generation - Screenshots and videos -## Setting Up Playwright +## Setting Up @nx/playwright + +### Installation -If the `@nx/playwright` package is not installed, install the version that matches your `nx` package version. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/playwright` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/playwright` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/playwright +nx add @nx/playwright ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/playwright`. -```shell -yarn add -D @nx/playwright +### How @nx/playwright Infers Tasks + +The `@nx/playwright` plugin will create a task for any project that has a Playwright configuration file present. Any of the following files will be recognized as a Playwright configuration file: + +- `playwright.config.js` +- `playwright.config.ts` +- `playwright.config.mjs` +- `playwright.config.mts` +- `playwright.config.cjs` +- `playwright.config.cts` + +### 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 --web` in the command line. + +### @nx/playwright Configuration + +The `@nx/playwright/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/playwright/plugin", + "options": { + "ciTargetName": "e2e-ci", + "targetName": "e2e" + } + } + ] +} ``` +- The `targetName` and `ciTargetName` options control the namea of the inferred Playwright tasks. The default names are `e2e` and `e2e-ci`. + +### Splitting E2E tasks by file + +The `@nx/playwright/plugin` will automatically split your e2e tasks by file. You can read more about this feature [here](/ci/features/split-e2e-tasks). + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/playwright` package with your package manager. ```shell -pnpm add -D @nx/playwright +npm add -D @nx/playwright ``` {% /tab %} diff --git a/docs/generated/packages/playwright/generators/configuration.json b/docs/generated/packages/playwright/generators/configuration.json index 9f0685f16068a..a354fdcb4d228 100644 --- a/docs/generated/packages/playwright/generators/configuration.json +++ b/docs/generated/packages/playwright/generators/configuration.json @@ -1,6 +1,6 @@ { "name": "configuration", - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#configurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxPlaywrightConfiguration", @@ -74,7 +74,7 @@ "presets": [] }, "description": "Add Nx Playwright configuration to your project", - "implementation": "/packages/playwright/src/generators/configuration/configuration.ts", + "implementation": "/packages/playwright/src/generators/configuration/configuration#configurationGeneratorInternal.ts", "aliases": [], "hidden": false, "path": "/packages/playwright/src/generators/configuration/schema.json", diff --git a/docs/generated/packages/playwright/generators/init.json b/docs/generated/packages/playwright/generators/init.json index ef8bb483cc03a..c705ebc0c5c9b 100644 --- a/docs/generated/packages/playwright/generators/init.json +++ b/docs/generated/packages/playwright/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init", + "factory": "./src/generators/init/init#initGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxPlaywrightInit", @@ -37,7 +37,7 @@ "presets": [] }, "description": "Initializes a Playwright project in the current workspace", - "implementation": "/packages/playwright/src/generators/init/init.ts", + "implementation": "/packages/playwright/src/generators/init/init#initGeneratorInternal.ts", "aliases": [], "hidden": false, "path": "/packages/playwright/src/generators/init/schema.json", diff --git a/docs/generated/packages/plugin/documents/overview.md b/docs/generated/packages/plugin/documents/overview.md index 459807ba2e2ef..30179db3dae2c 100644 --- a/docs/generated/packages/plugin/documents/overview.md +++ b/docs/generated/packages/plugin/documents/overview.md @@ -1,4 +1,4 @@ -Nx plugins are npm packages that contain [generators](/core-features/plugin-features/use-code-generators) and [executors](/core-features/plugin-features/use-task-executors) to extend a Nx workspace. +Nx plugins are npm packages that contain [generators](/features/generate-code) and [executors](/concepts/executors-and-configurations) to extend a Nx workspace. This package contains tooling to help plugin authors create and maintain plugins. diff --git a/docs/generated/packages/react-native/documents/overview.md b/docs/generated/packages/react-native/documents/overview.md index 5a533982f453d..8fa0b538e95fd 100644 --- a/docs/generated/packages/react-native/documents/overview.md +++ b/docs/generated/packages/react-native/documents/overview.md @@ -10,12 +10,10 @@ The Nx Plugin for React Native contains generators for managing React Native app ### Create a New Workspace -The easiest way to create your workspace is via `npx`. +To create a new workspace with React Native, run the following command: ```shell -npx create-nx-workspace your-workspace-name \ ---preset=react-native \ ---appName=your-app-name +npx create-nx-workspace@latest --preset=react-native --appName=your-app-name ``` {% callout type="note" title="Don't know what you need?" %} @@ -26,38 +24,68 @@ You can also run the command without arguments to go through the interactive pro npx create-nx-workspace your-workspace-name ``` -### Adding React Native to an Existing Workspace - -For existing Nx workspaces, install the `@nx/react-native` package to add React Native capabilities to it. +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/react-native` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/react-native` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/react-native +nx add @nx/react-native ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/react-native`. -```shell -yarn add -D @nx/react-native +### How @nx/react-native Infers Tasks + +The `@nx/react-native` plugin will create a task for any project that has an app configuration file present. Any of the following files will be recognized as an app configuration file: + +- `app.config.js` +- `app.json` + +### 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 --web` in the command line. + +### @nx/react-native Configuration + +The `@nx/react-native/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/react-native/plugin", + "options": { + "startTargetName": "start", + "podInstallTargetName": "pod-install", + "bundleTargetName": "bundle", + "runIosTargetName": "run-ios", + "runAndroidTargetName": "run-android", + "buildIosTargetName": "build-ios", + "buildAndroidTargetName": "build-android" + } + } + ] +} ``` +Once a React Native configuration file has been identified, the targets are created with the name you specify under `startTargetName`, `podInstallTargetName`, `bundleTargetName`, `runIosTargetName`, `runAndroidTargetname`, `buildIosTargetName` or `buildAndroidTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `start`, `pod-install`, `bundle`, `run-ios`, `run-anroid`, `build-ios` and `build-android`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/react-native` package with your package manager. ```shell -pnpm add -D @nx/react-native +npm add -D @nx/react-native ``` -{% /tab %} -{% /tabs %} - ### Generating Applications To create additional React Native apps run: @@ -86,7 +114,7 @@ Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.js ### Upgrade React Native -The Nx CLI provides the [`migrate` command](/core-features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx. +The Nx CLI provides the [`migrate` command](/features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx. #### Use upgrade-native Generator @@ -139,7 +167,7 @@ The build artifacts will be located under `/ios/build`. You can specify the build folder by setting the `buildFolder` option: ```shell -nx build ios --buildFolder="./build" +nx build-ios --buildFolder="./build" ``` ### Build Android diff --git a/docs/generated/packages/react-native/generators/init.json b/docs/generated/packages/react-native/generators/init.json index 2a5b8a6e2567f..02718c332abfc 100644 --- a/docs/generated/packages/react-native/generators/init.json +++ b/docs/generated/packages/react-native/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#reactNativeInitGenerator", + "factory": "./src/generators/init/init#reactNativeInitGeneratorInternal", "schema": { "cli": "nx", "$id": "NxReactNativeInit", @@ -39,7 +39,7 @@ }, "description": "Initialize the `@nx/react-native` plugin.", "hidden": true, - "implementation": "/packages/react-native/src/generators/init/init#reactNativeInitGenerator.ts", + "implementation": "/packages/react-native/src/generators/init/init#reactNativeInitGeneratorInternal.ts", "aliases": [], "path": "/packages/react-native/src/generators/init/schema.json", "type": "generator" diff --git a/docs/generated/packages/react-native/generators/storybook-configuration.json b/docs/generated/packages/react-native/generators/storybook-configuration.json index 3b6faac5dc727..e8233f36189fb 100644 --- a/docs/generated/packages/react-native/generators/storybook-configuration.json +++ b/docs/generated/packages/react-native/generators/storybook-configuration.json @@ -1,6 +1,6 @@ { "name": "storybook-configuration", - "factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGenerator", + "factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -76,7 +76,7 @@ "presets": [] }, "description": "Set up Storybook for a React Native application or library.", - "implementation": "/packages/react-native/src/generators/storybook-configuration/configuration#storybookConfigurationGenerator.ts", + "implementation": "/packages/react-native/src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal.ts", "aliases": [], "hidden": false, "path": "/packages/react-native/src/generators/storybook-configuration/schema.json", diff --git a/docs/generated/packages/react/documents/overview.md b/docs/generated/packages/react/documents/overview.md index 7afbe410e1ffa..ca980ce308664 100644 --- a/docs/generated/packages/react/documents/overview.md +++ b/docs/generated/packages/react/documents/overview.md @@ -6,43 +6,46 @@ It provides: - Library build support for publishing packages to npm or other registries. - Utilities for automatic workspace refactoring. -## Setting Up React +## Setting Up @nx/react + +### Generating a new Workspace To create a new workspace with React, run `npx create-nx-workspace@latest --preset=react-standalone`. +{% callout type="note" title="React Tutorials" %} +For a full tutorial experience, follow the [React Standalone Tutorial](/getting-started/tutorials/react-standalone-tutorial) or the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) +{% /callout %} + +### Installation + {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/react` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the React plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/react` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/react +nx add @nx/react ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/react -``` +This will install the correct version of `@nx/react`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/react` package with your package manager. ```shell -pnpm add -D @nx/react +npm add -D @nx/react ``` {% /tab %} {% /tabs %} -{% callout type="note" title="React Tutorials" %} -For a full tutorial experience, follow the [React Standalone Tutorial](/getting-started/tutorials/react-standalone-tutorial) or the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) -{% /callout %} +## Using the @nx/react Plugin ### Creating Applications and Libraries diff --git a/docs/generated/packages/react/generators/storybook-configuration.json b/docs/generated/packages/react/generators/storybook-configuration.json index a66d9d72601d7..75de45d624622 100644 --- a/docs/generated/packages/react/generators/storybook-configuration.json +++ b/docs/generated/packages/react/generators/storybook-configuration.json @@ -1,6 +1,6 @@ { "name": "storybook-configuration", - "factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGenerator", + "factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -93,7 +93,7 @@ }, "description": "Set up storybook for a React app or library.", "hidden": false, - "implementation": "/packages/react/src/generators/storybook-configuration/configuration#storybookConfigurationGenerator.ts", + "implementation": "/packages/react/src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal.ts", "aliases": [], "path": "/packages/react/src/generators/storybook-configuration/schema.json", "type": "generator" diff --git a/docs/generated/packages/remix/documents/overview.md b/docs/generated/packages/remix/documents/overview.md index d234672adf0a9..b38a58fb42780 100644 --- a/docs/generated/packages/remix/documents/overview.md +++ b/docs/generated/packages/remix/documents/overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Remix Plugin +description: The Nx Plugin for Remix contains executors, generators, and utilities for managing Remix applications and libraries within an Nx workspace. +--- + The Nx Plugin for Remix contains executors, generators, and utilities for managing Remix applications and libraries within an Nx workspace. It provides: @@ -10,35 +15,66 @@ within an Nx workspace. It provides: - Meta - Utilities for automatic workspace refactoring. -## Setting up the Remix plugin +## Setting up @nx/remix + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/remix` version that matches the version of `nx` in your repository. If the version -numbers get out of sync, you can encounter some difficult to debug errors. You -can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +Make sure to install the `@nx/remix` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -Adding the Remix plugin to an existing Nx workspace can be done with the following: +In any Nx workspace, you can install `@nx/remix` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/remix +nx add @nx/remix ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/remix`. -```shell -yarn add -D @nx/remix +### How @nx/remix Infers Tasks + +The `@nx/remix` plugin will create a task for any project that has a Remix configuration file present. Any of the following files will be recognized as a Remix configuration file: + +- `remix.config.js` +- `remix.config.mjs` +- `remix.config.cjs` + +### 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 --web` in the command line. + +### @nx/remix Configuration + +The `@nx/remix/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/remix/plugin", + "options": { + "buildTargetName": "build", + "serveTargetName": "serve", + "startTargetName": "start", + "typecheckTargetName": "typecheck" + } + } + ] +} ``` +- The `buildTargetName`, `serveTargetName`, `startTargetName` and `typecheckTargetName` options control the names of the inferred Remix tasks. The default names are `build`, `serve`, `start` and `typecheck`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/remix` package with your package manager. ```shell -pnpm add -D @nx/remix +npm add -D @nx/remix ``` {% /tab %} diff --git a/docs/generated/packages/remix/generators/application.json b/docs/generated/packages/remix/generators/application.json index 97b621c845c86..2d2e45eec901d 100644 --- a/docs/generated/packages/remix/generators/application.json +++ b/docs/generated/packages/remix/generators/application.json @@ -1,6 +1,6 @@ { "name": "application", - "implementation": "/packages/remix/src/generators/application/application.impl.ts", + "implementation": "/packages/remix/src/generators/application/application.impl#remixApplicationGeneratorInternal.ts", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxRemixApplication", diff --git a/docs/generated/packages/remix/generators/cypress-component-configuration.json b/docs/generated/packages/remix/generators/cypress-component-configuration.json index 9f676dbbc5f4a..54cf250d797d0 100644 --- a/docs/generated/packages/remix/generators/cypress-component-configuration.json +++ b/docs/generated/packages/remix/generators/cypress-component-configuration.json @@ -1,6 +1,6 @@ { "name": "cypress-component-configuration", - "implementation": "/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl.ts", + "implementation": "/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl#cypressComponentConfigurationGeneratorInternal.ts", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", diff --git a/docs/generated/packages/remix/generators/cypress.json b/docs/generated/packages/remix/generators/cypress.json deleted file mode 100644 index f18cee4144a46..0000000000000 --- a/docs/generated/packages/remix/generators/cypress.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "cypress", - "implementation": "/packages/remix/src/generators/cypress/cypress.impl.ts", - "schema": { - "$schema": "https://json-schema.org/schema", - "$id": "NxRemixCypress", - "title": "", - "type": "object", - "description": "Generate a Cypress e2e project for a given application.", - "properties": { - "project": { - "type": "string", - "description": "The name of the frontend project to test.", - "$default": { "$source": "projectName" } - }, - "projectNameAndRootFormat": { - "description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).", - "type": "string", - "enum": ["as-provided", "derived"] - }, - "baseUrl": { - "type": "string", - "description": "URL to access the application on", - "default": "http://localhost:3000" - }, - "name": { - "type": "string", - "description": "Name of the E2E Project", - "$default": { "$source": "argv", "index": 0 }, - "x-prompt": "What name would you like to use for the e2e project?" - }, - "directory": { - "type": "string", - "description": "A directory where the project is placed" - }, - "linter": { - "description": "The tool to use for running lint checks.", - "type": "string", - "enum": ["eslint", "none"], - "default": "eslint" - }, - "js": { - "description": "Generate JavaScript files rather than TypeScript files", - "type": "boolean", - "default": false - }, - "skipFormat": { - "description": "Skip formatting files", - "type": "boolean", - "default": false - }, - "setParserOptionsProject": { - "type": "boolean", - "description": "Whether or not to configure the ESLint \"parserOptions.project\" option. We do not do this by default for lint performance reasons.", - "default": false - } - }, - "required": ["name"], - "presets": [] - }, - "description": "Generate a project for testing Remix apps using Cypress", - "aliases": [], - "hidden": false, - "path": "/packages/remix/src/generators/cypress/schema.json", - "type": "generator" -} diff --git a/docs/generated/packages/remix/generators/init.json b/docs/generated/packages/remix/generators/init.json index 92443abc5f4cc..44d9cf16f7f4b 100644 --- a/docs/generated/packages/remix/generators/init.json +++ b/docs/generated/packages/remix/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "implementation": "/packages/remix/src/generators/init/init.ts", + "implementation": "/packages/remix/src/generators/init/init#remixInitGeneratorInternal.ts", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxRemixInit", diff --git a/docs/generated/packages/remix/generators/library.json b/docs/generated/packages/remix/generators/library.json index e1dd418cf8e65..4a4b6dc7708e8 100644 --- a/docs/generated/packages/remix/generators/library.json +++ b/docs/generated/packages/remix/generators/library.json @@ -1,6 +1,6 @@ { "name": "library", - "implementation": "/packages/remix/src/generators/library/library.impl.ts", + "implementation": "/packages/remix/src/generators/library/library.impl#remixLibraryGeneratorInternal.ts", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxRemixLibrary", diff --git a/docs/generated/packages/remix/generators/storybook-configuration.json b/docs/generated/packages/remix/generators/storybook-configuration.json index 0d15ceeac0640..c395840685585 100644 --- a/docs/generated/packages/remix/generators/storybook-configuration.json +++ b/docs/generated/packages/remix/generators/storybook-configuration.json @@ -1,6 +1,6 @@ { "name": "storybook-configuration", - "implementation": "/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl.ts", + "implementation": "/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl#remixStorybookConfiguration.ts", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", diff --git a/docs/generated/packages/storybook/documents/overview.md b/docs/generated/packages/storybook/documents/overview.md index 47590c3960eb3..2e970f928cc72 100644 --- a/docs/generated/packages/storybook/documents/overview.md +++ b/docs/generated/packages/storybook/documents/overview.md @@ -9,31 +9,67 @@ This guide will briefly walk you through using Storybook within an Nx workspace. ## Setting Up Storybook -### Add the Storybook plugin +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/storybook` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/storybook` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/storybook +nx add @nx/storybook ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/storybook`. -```shell -yarn add -D @nx/storybook +### How @nx/storybook Infers Tasks + +The `@nx/storybook` plugin will create a task for any project that has a Storybook configuration file present. Any of the following files will be recognized as a Storybook configuration file: + +- `.storybook/main.js` +- `.storybook/main.ts` +- `.storybook/main.cjs` +- `.storybook/main.cts` +- `.storybook/main.mjs` +- `.storybook/main.mts` + +### 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 --web` in the command line. + +### @nx/storybook Configuration + +The `@nx/storybook/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/storybook/plugin", + "options": { + "buildStorybookTargetName": "build-storybook", + "serveStorybookTargetName": "storybook", + "testStorybookTargetName": "test-storybook", + "staticStorybookTargetName": "static-storybook" + } + } + ] +} ``` +- The `builtStorybookTargetName`, `serveStorybookTargetName`, `testStorybookTargetName` and `staticStorybookTargetName` options control the names of the inferred Storybook tasks. The default names are `build-storybook`, `storybook`, `test-storybook` and `static-storybook`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/storybook` package with your package manager. ```shell -pnpm add -D @nx/storybook +npm add -D @nx/storybook ``` {% /tab %} diff --git a/docs/generated/packages/storybook/generators/configuration.json b/docs/generated/packages/storybook/generators/configuration.json index b615f30218861..7feb6d1797475 100644 --- a/docs/generated/packages/storybook/generators/configuration.json +++ b/docs/generated/packages/storybook/generators/configuration.json @@ -1,6 +1,6 @@ { "name": "configuration", - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#configurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -102,7 +102,7 @@ }, "description": "Add Storybook configuration to a UI library or an application.", "hidden": false, - "implementation": "/packages/storybook/src/generators/configuration/configuration.ts", + "implementation": "/packages/storybook/src/generators/configuration/configuration#configurationGeneratorInternal.ts", "aliases": [], "path": "/packages/storybook/src/generators/configuration/schema.json", "type": "generator" diff --git a/docs/generated/packages/storybook/generators/init.json b/docs/generated/packages/storybook/generators/init.json index 9ab4f6b586bf4..8f90f047a9b0f 100644 --- a/docs/generated/packages/storybook/generators/init.json +++ b/docs/generated/packages/storybook/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init", + "factory": "./src/generators/init/init#initGeneratorInternal", "schema": { "cli": "nx", "title": "Add Storybook Configuration to the workspace", @@ -36,7 +36,7 @@ "description": "Add Storybook configuration to the workspace.", "aliases": ["ng-add"], "hidden": true, - "implementation": "/packages/storybook/src/generators/init/init.ts", + "implementation": "/packages/storybook/src/generators/init/init#initGeneratorInternal.ts", "path": "/packages/storybook/src/generators/init/schema.json", "type": "generator" } diff --git a/docs/generated/packages/vite/documents/overview.md b/docs/generated/packages/vite/documents/overview.md index 8dc7c626606d4..268149d633515 100644 --- a/docs/generated/packages/vite/documents/overview.md +++ b/docs/generated/packages/vite/documents/overview.md @@ -16,7 +16,7 @@ Why should you use this plugin? Read more about Vite and Vitest in the [Vite documentation](https://vitejs.dev/). -## Setting up a new Nx workspace with Vite +## Setting up a new Nx workspace with @nx/vite Here's an example on how to create a new React app with Vite @@ -24,9 +24,80 @@ Here's an example on how to create a new React app with Vite npx create-nx-workspace@latest --preset=react-standalone --bundler=vite ``` -## Add Vite to an existing workspace +### Installation -There is a number of ways to use Vite in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/vite` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/vite` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/vite +``` + +This will install the correct version of `@nx/vite`. + +### How @nx/vite Infers Tasks + +The `@nx/vite` plugin will create a task for any project that has a Vite configuration file present. Any of the following files will be recognized as a Vite configuration file: + +- `vite.config.js` +- `vite.config.ts` +- `vite.config.mjs` +- `vite.config.mts` +- `vite.config.cjs` +- `vite.config.cts` +- `vitest.config.js` +- `vitest.config.ts` +- `vitest.config.mjs` +- `vitest.config.mts` +- `vitest.config.cjs` +- `vitest.config.cts` + +### 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 --web` in the command line. + +### @nx/vite Configuration + +The `@nx/vite/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/vite/plugin", + "options": { + "buildTargetName": "build", + "previewTargetName": "preview", + "testTargetName": "test", + "serveTargetName": "serve", + "serveStaticTargetName": "serve-static" + } + } + ] +} +``` + +- The `buildTargetName`, `previewTargetName`, `testTargetName`, `serveTargetName` and `serveStaticTargetName` options control the names of the inferred Vite tasks. The default names are `build`, `preview`, `test`, `serve` and `serve-static`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/vite` package with your package manager. + +```shell +npm add -D @nx/vite +``` + +{% /tab %} +{% /tabs %} + +## Using @nx/vite ### Generate a new project using Vite @@ -55,49 +126,3 @@ nx g @nx/web:app my-app --bundler=vite You can use the `@nx/vite:configuration` generator to change your React or Web project to use Vite.js. This generator will modify your project's configuration to use Vite.js, and it will also install all the necessary dependencies, including the `@nx/vite` plugin.. You can read more about this generator on the [`@nx/vite:configuration`](/nx-api/vite/generators/configuration) generator page. - -### Initialize Vite - -If you do not want to create any new projects or convert any existing projects yet, you can still use Nx to install all the necessary dependencies for Vite.js. This, for example, could be useful if you want to set up Vite.js manually for a project. - -#### Install the `@nx/vite` plugin - -{% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/vite` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). -{% /callout %} - -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/vite -``` - -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/vite -``` - -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/vite -``` - -{% /tab %} -{% /tabs %} - -#### Ask Nx to install the necessary dependencies - -After you install the plugin, you can automatically initialize the project with Vite using an Nx generator: - -```bash -nx g @nx/vite:init -``` - -{% callout type="note" title="Choosing a framework" %} -You will notice that the generator will ask you of the framework you are planning to use. This is just to make sure that the right dependencies are installed. You can always install manually any other dependencies you need. -{% /callout %} diff --git a/docs/generated/packages/vite/generators/configuration.json b/docs/generated/packages/vite/generators/configuration.json index 8ee70e0f3a3d5..6c5d46e83c53d 100644 --- a/docs/generated/packages/vite/generators/configuration.json +++ b/docs/generated/packages/vite/generators/configuration.json @@ -1,6 +1,6 @@ { "name": "configuration", - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#viteConfigurationGeneratorInternal", "schema": { "cli": "nx", "title": "Configure a project to use Vite.js.", @@ -75,7 +75,7 @@ "description": "Add Vite configuration to an application.", "aliases": ["config"], "hidden": false, - "implementation": "/packages/vite/src/generators/configuration/configuration.ts", + "implementation": "/packages/vite/src/generators/configuration/configuration#viteConfigurationGeneratorInternal.ts", "path": "/packages/vite/src/generators/configuration/schema.json", "type": "generator" } diff --git a/docs/generated/packages/vite/generators/init.json b/docs/generated/packages/vite/generators/init.json index 4208b380bf19c..b1948fddc6e4d 100644 --- a/docs/generated/packages/vite/generators/init.json +++ b/docs/generated/packages/vite/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init", + "factory": "./src/generators/init/init#initGeneratorInternal", "schema": { "cli": "nx", "title": "Initialize Vite in the workspace.", @@ -36,7 +36,7 @@ "description": "Initialize Vite in the workspace.", "aliases": ["ng-add"], "hidden": true, - "implementation": "/packages/vite/src/generators/init/init.ts", + "implementation": "/packages/vite/src/generators/init/init#initGeneratorInternal.ts", "path": "/packages/vite/src/generators/init/schema.json", "type": "generator" } diff --git a/docs/generated/packages/vite/generators/vitest.json b/docs/generated/packages/vite/generators/vitest.json index c2e25d88605b4..1ce2e8f96f47d 100644 --- a/docs/generated/packages/vite/generators/vitest.json +++ b/docs/generated/packages/vite/generators/vitest.json @@ -1,6 +1,6 @@ { "name": "vitest", - "factory": "./src/generators/vitest/vitest-generator", + "factory": "./src/generators/vitest/vitest-generator#vitestGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -57,7 +57,7 @@ "presets": [] }, "description": "Generate a vitest configuration", - "implementation": "/packages/vite/src/generators/vitest/vitest-generator.ts", + "implementation": "/packages/vite/src/generators/vitest/vitest-generator#vitestGeneratorInternal.ts", "aliases": [], "hidden": false, "path": "/packages/vite/src/generators/vitest/schema.json", diff --git a/docs/generated/packages/vue/documents/overview.md b/docs/generated/packages/vue/documents/overview.md index d1e514316220f..814ca05c84040 100644 --- a/docs/generated/packages/vue/documents/overview.md +++ b/docs/generated/packages/vue/documents/overview.md @@ -5,50 +5,47 @@ description: The Nx Plugin for Vue contains generators for managing Vue applicat The Nx plugin for [Vue](https://vuejs.org/). -## Setting up a new Nx workspace with Vue +## Setting Up @nx/vue -You can create a new workspace that uses Vue with one of the following commands: +### Generating a new Workspace -- Generate a new monorepo with a Vue app set up with Vue - -```shell -npx create-nx-workspace@latest --preset=vue -``` +To create a new workspace with React, run `npx create-nx-workspace@latest --preset=vue`. {% callout type="note" title="Vue Standalone Tutorial" %} For a full tutorial experience, follow the [Vue Standalone Tutorial](/getting-started/tutorials/vue-standalone-tutorial) {% /callout %} -## Add Vue to an existing workspace +### Installation -There are a number of ways to use Vue in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/vue` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -### Install the `@nx/vue` plugin +In any Nx workspace, you can install `@nx/vue` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/vue +nx add @nx/vue ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/vue -``` +This will install the correct version of `@nx/vue`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/vue` package with your package manager. ```shell -pnpm add -D @nx/vue +npm add -D @nx/vue ``` {% /tab %} {% /tabs %} +## Using the @nx/vue Plugin + ### Generate a new project using Vue To generate a Vue application, run the following: diff --git a/docs/generated/packages/vue/generators/application.json b/docs/generated/packages/vue/generators/application.json index 848ef8be3bf57..847a7685a4963 100644 --- a/docs/generated/packages/vue/generators/application.json +++ b/docs/generated/packages/vue/generators/application.json @@ -1,6 +1,6 @@ { "name": "application", - "factory": "./src/generators/application/application", + "factory": "./src/generators/application/application#applicationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -135,7 +135,7 @@ }, "aliases": ["app"], "description": "Create a Vue application.", - "implementation": "/packages/vue/src/generators/application/application.ts", + "implementation": "/packages/vue/src/generators/application/application#applicationGeneratorInternal.ts", "hidden": false, "path": "/packages/vue/src/generators/application/schema.json", "type": "generator" diff --git a/docs/generated/packages/vue/generators/library.json b/docs/generated/packages/vue/generators/library.json index bab66b7bddf30..4d3ada2060201 100644 --- a/docs/generated/packages/vue/generators/library.json +++ b/docs/generated/packages/vue/generators/library.json @@ -1,6 +1,6 @@ { "name": "library", - "factory": "./src/generators/library/library", + "factory": "./src/generators/library/library#libraryGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -141,7 +141,7 @@ "aliases": ["lib"], "x-type": "library", "description": "Create a Vue library.", - "implementation": "/packages/vue/src/generators/library/library.ts", + "implementation": "/packages/vue/src/generators/library/library#libraryGeneratorInternal.ts", "hidden": false, "path": "/packages/vue/src/generators/library/schema.json", "type": "generator" diff --git a/docs/generated/packages/vue/generators/storybook-configuration.json b/docs/generated/packages/vue/generators/storybook-configuration.json index 3cd96607aa1df..51a35e1d5fd95 100644 --- a/docs/generated/packages/vue/generators/storybook-configuration.json +++ b/docs/generated/packages/vue/generators/storybook-configuration.json @@ -1,6 +1,6 @@ { "name": "storybook-configuration", - "factory": "./src/generators/storybook-configuration/configuration", + "factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "cli": "nx", @@ -78,7 +78,7 @@ }, "description": "Set up storybook for a Vue app or library.", "hidden": false, - "implementation": "/packages/vue/src/generators/storybook-configuration/configuration.ts", + "implementation": "/packages/vue/src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal.ts", "aliases": [], "path": "/packages/vue/src/generators/storybook-configuration/schema.json", "type": "generator" diff --git a/docs/generated/packages/web/documents/overview.md b/docs/generated/packages/web/documents/overview.md index e24927d7d4c9a..cadc015e3b41e 100644 --- a/docs/generated/packages/web/documents/overview.md +++ b/docs/generated/packages/web/documents/overview.md @@ -4,40 +4,43 @@ The Nx Plugin for Web Components contains generators for managing Web Component - Scaffolding for creating buildable libraries that can be published to npm. - Utilities for automatic workspace refactoring. -## Setting Up Web +## Setting Up @nx/web -To create a new workspace with web, run `npx create-nx-workspace@latest --preset=web-components`. +### Generating a new Workspace + +To create a new workspace with React, run `npx create-nx-workspace@latest --preset=web-components`. + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/web` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the web plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/web` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/web +nx add @nx/web ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/web -``` +This will install the correct version of `@nx/web`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/web` package with your package manager. ```shell -pnpm add -D @nx/web +npm add -D @nx/web ``` {% /tab %} {% /tabs %} +## Using the @nx/web Plugin + ### Creating Applications You can add a new application with the following: diff --git a/docs/generated/packages/webpack/documents/overview.md b/docs/generated/packages/webpack/documents/overview.md index af0c063509a9c..103051397e9bf 100644 --- a/docs/generated/packages/webpack/documents/overview.md +++ b/docs/generated/packages/webpack/documents/overview.md @@ -25,6 +25,72 @@ npx create-nx-workspace@latest --preset=react-standalone --bundler=webpack npx create-nx-workspace@latest --preset=react-monorepo --bundler=webpack ``` +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/webpack` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/webpack` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/webpack +``` + +This will install the correct version of `@nx/webpack`. + +### How @nx/webpack Infers Tasks + +The `@nx/webpack` plugin will create a task for any project that has a Webpack configuration file present. Any of the following files will be recognized as a Webpack configuration file: + +- `webpack.config.js` +- `webpack.config.ts` +- `webpack.config.mjs` +- `webpack.config.mts` +- `webpack.config.cjs` +- `webpack.config.cts` + +### 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 --web` in the command line. + +### @nx/webpack Configuration + +The `@nx/webpack/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/webpack/plugin", + "options": { + "buildTargetName": "build", + "previewTargetName": "preview", + "serveTargetName": "serve", + "serveStaticTargetName": "serve-static" + } + } + ] +} +``` + +- The `buildTargetName`, `previewTargetName`, `serveTargetName` and `serveStaticTargetName` options control the names of the inferred Webpack tasks. The default names are `build`, `preview`, `serve` and `serve-static`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/webpack` package with your package manager. + +```shell +npm add -D @nx/webpack +``` + +{% /tab %} +{% /tabs %} + ## Generate a new project using Webpack You can generate a [React](/nx-api/react) application or a [Web](/nx-api/web) application that uses Webpack in an existing Nx workspace. The [`@nx/react:app`](/nx-api/react/generators/application), [`@nx/node:app`](/nx-api/node/generators/application) and [`@nx/web:app`](/nx-api/web/generators/application) generators accept the `bundler` option, where you can pass `webpack`. This will generate a new application configured to use Webpack, and it will also install all the necessary dependencies, including the `@nx/webpack` plugin. diff --git a/docs/generated/packages/webpack/generators/configuration.json b/docs/generated/packages/webpack/generators/configuration.json index 79ed5f99a6abd..404f53b0f5e63 100644 --- a/docs/generated/packages/webpack/generators/configuration.json +++ b/docs/generated/packages/webpack/generators/configuration.json @@ -1,7 +1,7 @@ { "name": "configuration", "aliases": ["webpack-project"], - "factory": "./src/generators/configuration/configuration", + "factory": "./src/generators/configuration/configuration#configurationGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxWebpackProject", @@ -79,7 +79,7 @@ }, "description": "Add webpack configuration to a project.", "hidden": true, - "implementation": "/packages/webpack/src/generators/configuration/configuration.ts", + "implementation": "/packages/webpack/src/generators/configuration/configuration#configurationGeneratorInternal.ts", "path": "/packages/webpack/src/generators/configuration/schema.json", "type": "generator" } diff --git a/docs/generated/packages/webpack/generators/init.json b/docs/generated/packages/webpack/generators/init.json index 4da1d3070aeeb..d0453038452b9 100644 --- a/docs/generated/packages/webpack/generators/init.json +++ b/docs/generated/packages/webpack/generators/init.json @@ -1,6 +1,6 @@ { "name": "init", - "factory": "./src/generators/init/init#webpackInitGenerator", + "factory": "./src/generators/init/init#webpackInitGeneratorInternal", "schema": { "$schema": "https://json-schema.org/schema", "$id": "NxWebpackInit", @@ -38,7 +38,7 @@ "description": "Initialize the `@nrwl/webpack` plugin.", "aliases": ["ng-add"], "hidden": true, - "implementation": "/packages/webpack/src/generators/init/init#webpackInitGenerator.ts", + "implementation": "/packages/webpack/src/generators/init/init#webpackInitGeneratorInternal.ts", "path": "/packages/webpack/src/generators/init/schema.json", "type": "generator" } diff --git a/docs/map.json b/docs/map.json index f101db1d9c46e..73cc8eeb3b048 100644 --- a/docs/map.json +++ b/docs/map.json @@ -67,11 +67,6 @@ "name": "Vue Standalone", "id": "vue-standalone-tutorial", "file": "shared/vue-standalone-tutorial/vue-standalone" - }, - { - "name": "Node Standalone", - "id": "node-server-tutorial", - "file": "shared/node-server-tutorial/1-code-generation" } ] } @@ -115,77 +110,8 @@ ] }, { - "name": "Angular Standalone Tutorial", - "id": "angular-standalone-tutorial", - "description": "Learn to use Nx with this Angular tutorial where you will learn about all its main feature with a real project.", - "itemList": [ - { - "name": "1 - Code Generation", - "id": "1-code-generation", - "file": "shared/angular-standalone-tutorial/1-code-generation" - }, - { - "name": "2 - Project Graph", - "id": "2-project-graph", - "file": "shared/angular-standalone-tutorial/2-project-graph" - }, - { - "name": "3 - Task Running", - "id": "3-task-running", - "file": "shared/angular-standalone-tutorial/3-task-running" - }, - { - "name": "4 - Task Pipelines", - "id": "4-task-pipelines", - "file": "shared/angular-standalone-tutorial/4-task-pipelines" - }, - { - "name": "5 - Summary", - "id": "5-summary", - "file": "shared/angular-standalone-tutorial/5-summary" - } - ] - }, - { - "name": "Node Server Tutorial", - "id": "node-server-tutorial", - "description": "Learn to use Nx with this Node Server Tutorial where you will learn about all its main feature with a real project.", - "itemList": [ - { - "name": "1 - Code Generation", - "id": "1-code-generation", - "file": "shared/node-server-tutorial/1-code-generation" - }, - { - "name": "2 - Project Graph", - "id": "2-project-graph", - "file": "shared/node-server-tutorial/2-project-graph" - }, - { - "name": "3 - Task Running", - "id": "3-task-running", - "file": "shared/node-server-tutorial/3-task-running" - }, - { - "name": "4 - Task Pipelines", - "id": "4-task-pipelines", - "file": "shared/node-server-tutorial/4-task-pipelines" - }, - { - "name": "5 - Docker Target", - "id": "5-docker-target", - "file": "shared/node-server-tutorial/5-docker-target" - }, - { - "name": "6 - Summary", - "id": "6-summary", - "file": "shared/node-server-tutorial/6-summary" - } - ] - }, - { - "name": "Core Features", - "id": "core-features", + "name": "Features", + "id": "features", "description": "Learn the core features of Nx with in depth guides.", "itemList": [ { @@ -193,80 +119,111 @@ "description": "Learn about the various ways you can use Nx to run tasks in your workspace.", "tags": ["run-tasks", "cache-task-results"], "id": "run-tasks", - "file": "shared/core-features/run-tasks" + "file": "shared/features/run-tasks" }, { "name": "Cache Task Results", "description": "Learn how to define cacheable tasks, how to fine-tune with inputs and outputs, where the cache is stored and much more.", "id": "cache-task-results", "tags": ["cache-task-results"], - "file": "shared/core-features/cache-task-results" - }, - { - "name": "Use Remote Caching", - "id": "remote-cache", - "file": "", - "path": "/ci/features/remote-cache", - "isExternal": true - }, - { - "name": "Distribute Task Execution", - "id": "distribute-task-execution", - "file": "", - "path": "/ci/features/distribute-task-execution", - "isExternal": true + "file": "shared/features/cache-task-results" }, { - "name": "Explore the Graph", + "name": "Explore your Workspace", "id": "explore-graph", - "description": "Nx uses a graph behind the scenes to optimize your operations. You can also visualize and use the graph to better understand your workspace structure. Learn more in this guide.", "tags": ["explore-graph"], - "file": "shared/core-features/explore-graph" + "file": "shared/features/explore-graph" + }, + { + "name": "Generate Code", + "id": "generate-code", + "tags": ["generate-code"], + "file": "shared/features/generate-code" }, { "name": "Automate Updating Dependencies", "description": "Learn how Nx provides automated update scripts to help you keep your workspace, tooling and framework dependencies up to date.", "id": "automate-updating-dependencies", "tags": ["automate-updating-dependencies"], - "file": "shared/core-features/automate-updating-dependencies" + "file": "shared/features/automate-updating-dependencies" }, { "name": "Enforce Module Boundaries", "description": "Learn how to avoid dependency hell and scale a codebase by imposing constraints on your projects using the module boundary lint rule.", "id": "enforce-module-boundaries", "tags": ["enforce-module-boundaries"], - "file": "shared/core-features/enforce-module-boundaries" + "file": "shared/features/enforce-module-boundaries" }, { "name": "Integrate with Editors", "description": "Learn about Nx Console, an extension for VS Code and WebStorm.", "id": "integrate-with-editors", "tags": ["integrate-with-editors"], - "file": "shared/core-features/integrate-with-editors" + "file": "shared/features/integrate-with-editors" }, { "name": "Manage Releases", "description": "Learn how Nx provides tools to help you manage releasing your projects.", "id": "manage-releases", "tags": ["manage-releases"], - "file": "shared/core-features/manage-releases" + "file": "shared/features/manage-releases" }, { - "name": "Plugin Features", - "id": "plugin-features", - "description": "Learn what is a plugin, the different type of plugins and how to create one.", + "name": "CI Features", + "id": "ci-features", + "description": "Features of Nx and Nx Cloud that improve CI", "itemList": [ { - "name": "Use Task Executors", - "id": "use-task-executors", - "tags": ["use-task-executors"], - "file": "shared/plugin-features/use-task-executors" + "name": "Run Only Tasks Affected by a PR", + "id": "affected", + "file": "", + "path": "/ci/features/affected", + "isExternal": true + }, + { + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", + "id": "remote-cache", + "file": "", + "path": "/ci/features/remote-cache", + "isExternal": true + }, + { + "name": "Distribute Task Execution (Nx Agents)", + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", + "id": "distribute-task-execution", + "file": "", + "path": "/ci/features/distribute-task-execution", + "isExternal": true + }, + { + "name": "Dynamically Allocate Agents", + "id": "dynamic-agents", + "file": "", + "path": "/ci/features/dynamic-agents", + "isExternal": true }, { - "name": "Use Code Generators", - "id": "use-code-generators", - "tags": ["use-code-generators"], - "file": "shared/plugin-features/use-code-generators" + "name": "Automatically Split E2E Tasks", + "id": "split-e2e-tasks", + "file": "", + "path": "/ci/features/split-e2e-tasks", + "isExternal": true + }, + { + "name": "Identify and Re-run Flaky Tasks", + "id": "flaky-tasks", + "file": "", + "path": "/ci/features/flaky-tasks", + "isExternal": true + }, + { + "name": "Set up Nx Cloud On-Premise", + "id": "on-premise", + "description": "Set up Nx Cloud on machines that you control", + "file": "", + "path": "/ci/features/on-premise", + "isExternal": true } ] } @@ -289,6 +246,24 @@ "id": "how-caching-works", "file": "shared/concepts/how-caching-works" }, + { + "name": "What is a Task Pipeline", + "tags": ["run-tasks"], + "id": "task-pipeline-configuration", + "file": "shared/concepts/task-pipeline-configuration" + }, + { + "name": "What Are Nx Plugins", + "tags": ["generate-code", "create-your-own-plugin"], + "id": "nx-plugins", + "file": "shared/concepts/nx-plugins" + }, + { + "name": "Inferred Tasks", + "tags": ["inferred-tasks"], + "id": "inferred-tasks", + "file": "shared/concepts/inferred-tasks" + }, { "name": "Types of Configuration", "tags": [], @@ -296,10 +271,10 @@ "file": "shared/concepts/types-of-configuration" }, { - "name": "What is a Task Pipeline", - "tags": ["run-tasks", "use-task-executors"], - "id": "task-pipeline-configuration", - "file": "shared/concepts/task-pipeline-configuration" + "name": "Executors and Configurations", + "id": "executors-and-configurations", + "tags": ["run-tasks"], + "file": "shared/recipes/running-tasks/executors-and-configurations" }, { "name": "Integrated Repos vs. Package-Based Repos vs. Standalone Apps", @@ -321,12 +296,7 @@ { "name": "Faster Builds with Module Federation", "id": "faster-builds-with-module-federation", - "tags": [ - "use-task-executors", - "module-federation", - "angular", - "react" - ], + "tags": ["module-federation", "angular", "react"], "file": "shared/guides/module-federation/faster-builds" }, { @@ -349,7 +319,7 @@ { "name": "Incremental Builds", "id": "incremental-builds", - "tags": ["use-task-executors"], + "tags": [], "file": "shared/incremental-builds" }, { @@ -382,7 +352,7 @@ { "name": "Using Nx at Enterprises", "id": "monorepo-nx-enterprise", - "tags": ["enforce-module-boundaries", "use-code-generators"], + "tags": ["enforce-module-boundaries", "generate-code"], "file": "shared/monorepo-nx-enterprise" }, { @@ -456,13 +426,19 @@ "description": "A series of recipes that show how to run tasks efficiently with Nx", "itemList": [ { - "name": "Fine-tuning Caching with Inputs", - "id": "customizing-inputs", + "name": "Configure Inputs for Task Caching", + "id": "configure-inputs", + "tags": ["run-tasks", "cache-task-results"], + "file": "shared/recipes/running-tasks/configure-inputs" + }, + { + "name": "Configure Outputs for Task Caching", + "id": "configure-outputs", "tags": ["run-tasks", "cache-task-results"], - "file": "shared/recipes/running-tasks/customizing-inputs" + "file": "shared/recipes/running-tasks/configure-outputs" }, { - "name": "Defining a Task Pipeline", + "name": "Define a Task Pipeline", "id": "defining-task-pipeline", "tags": ["run-tasks"], "file": "shared/recipes/running-tasks/defining-task-pipeline" @@ -473,9 +449,9 @@ "file": "shared/recipes/running-tasks/change-cache-location" }, { - "name": "Running Custom Commands", + "name": "Run Custom Commands", "id": "run-commands-executor", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "file": "shared/recipes/running-tasks/running-custom-commands" }, { @@ -524,11 +500,6 @@ "id": "adding-to-existing-project", "file": "shared/migration/adding-to-existing-project" }, - { - "name": "Nx and Lerna", - "id": "lerna-and-nx", - "file": "shared/migration/lerna-and-nx" - }, { "name": "Preserving Git Histories", "id": "preserving-git-histories", @@ -585,7 +556,7 @@ { "name": "Setup Module Federation with SSR for React", "id": "module-federation-with-ssr", - "tags": ["use-task-executors", "module-federation", "react"], + "tags": ["module-federation", "react"], "file": "shared/recipes/module-federation-with-ssr" }, { @@ -640,21 +611,13 @@ { "name": "Setup Module Federation with SSR for Angular", "id": "module-federation-with-ssr", - "tags": [ - "use-task-executors", - "module-federation", - "angular" - ], + "tags": ["module-federation", "angular"], "file": "shared/recipes/module-federation-with-ssr" }, { "name": "Advanced Micro Frontends with Angular using Dynamic Federation", "id": "dynamic-module-federation-with-angular", - "tags": [ - "use-task-executors", - "module-federation", - "angular" - ], + "tags": ["module-federation", "angular"], "file": "shared/guides/module-federation/dynamic-mfe-angular" }, { @@ -882,7 +845,7 @@ "itemList": [ { "id": "webpack-config-setup", - "name": "How to configure webpack on your Nx workspace", + "name": "How to configure Webpack in your Nx workspace", "description": "A guide on how to configure webpack on your Nx workspace, and instructions on how to customize your webpack configuration", "file": "shared/packages/webpack/webpack-config-setup" }, @@ -1109,7 +1072,7 @@ { "name": "Profiling Build Performance", "id": "performance-profiling", - "tags": ["use-task-executors", "environment-variables"], + "tags": ["environment-variables"], "file": "shared/guides/performance-profiling" } ] @@ -1125,6 +1088,12 @@ "tags": ["integrate-with-editors"], "file": "shared/recipes/console-telemetry" }, + { + "name": "Project Details View", + "id": "console-project-details", + "tags": ["integrate-with-editors"], + "file": "shared/recipes/console-project-details" + }, { "name": "Generate Command", "id": "console-generate-command", @@ -1359,9 +1328,15 @@ { "name": "Project Configuration", "id": "project-configuration", - "tags": ["use-task-executors"], + "tags": [], "file": "shared/reference/project-configuration" }, + { + "name": "Inputs and Named Inputs", + "id": "inputs", + "tags": ["cache-task-results"], + "file": "shared/reference/inputs" + }, { "name": ".nxignore", "id": "nxignore", @@ -1422,6 +1397,16 @@ "id": "runtime-cache-inputs", "file": "shared/deprecated/runtime-cache-inputs" }, + { + "name": "cacheableOperations", + "id": "cacheable-operations", + "file": "shared/deprecated/cacheable-operations" + }, + { + "name": "npmScope", + "id": "npm-scope", + "file": "shared/deprecated/npm-scope" + }, { "name": "globalImplicitDependencies", "id": "global-implicit-dependencies", @@ -1539,7 +1524,7 @@ "name": "nx.json generator defaults", "id": "nxjson-generator-defaults", "file": "", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "path": "/reference/nx-json#generators", "isExternal": true }, @@ -1596,43 +1581,43 @@ { "name": "Write a Simple Executor", "id": "local-executors", - "tags": ["use-task-executors"], + "tags": [], "file": "shared/recipes/plugins/local-executors" }, { "name": "Compose Executors", "id": "compose-executors", - "tags": ["use-task-executors"], + "tags": [], "file": "shared/recipes/plugins/compose-executors" }, { "name": "Write a Simple Generator", "id": "local-generators", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "shared/recipes/generators/local-generators" }, { "name": "Compose Generators", "id": "composing-generators", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "shared/recipes/generators/composing-generators" }, { "name": "Provide Options for Generators", "id": "generator-options", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "shared/recipes/generators/generator-options" }, { "name": "Create Files", "id": "creating-files", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "shared/recipes/generators/creating-files" }, { "name": "Modify Files", "id": "modifying-files", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "shared/recipes/generators/modifying-files" }, { @@ -1702,13 +1687,6 @@ "id": "features", "description": "Features of Nx and Nx Cloud that improve CI", "itemList": [ - { - "name": "Use Remote Caching", - "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", - "id": "remote-cache", - "tags": ["remote-cache"], - "file": "shared/core-features/remote-cache" - }, { "name": "Run Only Tasks Affected by a PR", "tags": ["run-tasks"], @@ -1716,11 +1694,32 @@ "file": "shared/using-nx/affected" }, { - "name": "Distribute Task Execution", - "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Cloud has a built-in DTE mechanism which makes this a trivial task.", + "name": "Use Remote Caching (Nx Replay)", + "description": "Learn how to enable remote caching s.t. you don't just benefit locally from it but also in CI.", + "id": "remote-cache", + "tags": ["remote-cache"], + "file": "shared/features/remote-cache" + }, + { + "name": "Distribute Task Execution (Nx Agents)", "id": "distribute-task-execution", - "tags": ["distribute-task-execution"], - "file": "shared/core-features/distribute-task-execution" + "description": "Learn how to efficiently distribute tasks across machines to take full advantage of parallelization. Nx Agents make this a trivial task.", + "file": "shared/features/distribute-task-execution" + }, + { + "name": "Dynamically Allocate Agents", + "id": "dynamic-agents", + "file": "nx-cloud/features/dynamic-agents" + }, + { + "name": "Automatically Split E2E Tasks", + "id": "split-e2e-tasks", + "file": "nx-cloud/features/split-e2e-tasks" + }, + { + "name": "Identify and Re-run Flaky Tasks", + "id": "flaky-tasks", + "file": "nx-cloud/features/flaky-tasks" }, { "name": "Set up Nx Cloud On-Premise", @@ -1728,11 +1727,6 @@ "id": "on-premise", "tags": ["on-premise"], "file": "nx-cloud/private/nx-enterprise-on-prem" - }, - { - "name": "Nx Agents", - "id": "nx-agents", - "file": "nx-cloud/intro/nx-agents" } ] }, @@ -1777,6 +1771,11 @@ "description": "Learn how to set up Nx Cloud for your workspace.", "tags": ["distribute-task-execution"], "itemList": [ + { + "name": "Connect Nx Cloud", + "id": "connect-to-cloud", + "file": "nx-cloud/recipes/connect-to-cloud" + }, { "name": "Setting up Azure Pipelines", "id": "monorepo-ci-azure", @@ -1935,6 +1934,11 @@ "id": "nx-cloud-cli", "file": "nx-cloud/reference/nx-cloud-cli" }, + { + "name": "Launch Templates", + "id": "launch-templates", + "file": "nx-cloud/reference/launch-templates" + }, { "name": "Environment Variables", "id": "env-vars", @@ -1984,12 +1988,12 @@ { "name": "generate", "id": "generate", - "tags": ["use-code-generators"], + "tags": ["generate-code"], "file": "generated/cli/generate" }, { "name": "run", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "id": "run", "file": "generated/cli/run" }, @@ -2006,13 +2010,13 @@ }, { "name": "run-many", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "id": "run-many", "file": "generated/cli/run-many" }, { "name": "affected", - "tags": ["run-tasks", "use-task-executors"], + "tags": ["run-tasks"], "id": "affected", "file": "generated/cli/affected" }, diff --git a/docs/nx-cloud/concepts/building-blocks-fast-ci.md b/docs/nx-cloud/concepts/building-blocks-fast-ci.md index 4c30307204c94..86f20389566da 100644 --- a/docs/nx-cloud/concepts/building-blocks-fast-ci.md +++ b/docs/nx-cloud/concepts/building-blocks-fast-ci.md @@ -6,7 +6,7 @@ Nx has many features that make your CI faster. Each of these features speeds up The purpose of a CI pipeline is to run tasks like `build`, `test`, `lint` and `e2e`. You use different tools to run these tasks (like Webpack or Vite for you `build` task). If the individual tasks in your CI pipeline are slow, then your overall CI pipeline will be slow. Nx has two ways to help with this. -Nx provides plugins for popular tools that make it easy to update to the latest version of that tool and [automatically updates](/core-features/automate-updating-dependencies) your configuration files to take advantage of enhancements in the tool. The tool authors are always looking for ways to improve their product and the best way to get the most out of the tool you're using is to make sure you're on the latest version. Also, the recommended configuration settings for a tool will change over time so even if you're on the latest version of a tool, you may be using a slower version of it because you don't know about a new configuration setting. [`nx migrate`](/core-features/automate-updating-dependencies) will automatically change the default settings of in your tooling config to use the latest recommended settings so that your repo won't be left behind. +Nx provides plugins for popular tools that make it easy to update to the latest version of that tool and [automatically updates](/features/automate-updating-dependencies) your configuration files to take advantage of enhancements in the tool. The tool authors are always looking for ways to improve their product and the best way to get the most out of the tool you're using is to make sure you're on the latest version. Also, the recommended configuration settings for a tool will change over time so even if you're on the latest version of a tool, you may be using a slower version of it because you don't know about a new configuration setting. [`nx migrate`](/features/automate-updating-dependencies) will automatically change the default settings of in your tooling config to use the latest recommended settings so that your repo won't be left behind. Because Nx plugins have a consistent interface for how they are invoked and how they interact with the codebase, it is easier to try out a different tool to see if it is better than what you're currently using. Newer tools that were created with different technologies or different design decisions can be orders of magnitude faster than your existing tools. Or the new tool might not help your project. Browse through the [list of Nx plugins](/plugin-registry), like [vite](/nx-api/vite) or [rspack](/nx-api/rspack), and try it out on your project with the default settings already configured for you. @@ -25,11 +25,3 @@ Every time you use Nx to run a task, Nx will attempt to run the task and all its There's a limit to how many tasks can be run in parallel on the same machine, but the logic that Nx uses to assign tasks to parallel processes can also be used by Nx Cloud to efficiently [distribute tasks across multiple agent machines](/ci/features/distribute-task-execution). Once those tasks are run, the [remote cache](/ci/features/remote-cache) is used to replay those task results on the main machine. After the pipeline is finished, it looks like all the tasks were run on a single machine - but much faster than a single machine could do it. For a detailed analysis of different strategies for running tasks concurrently, read the [Parallelization and Distribution guide](/ci/concepts/parallelization-distribution) - -## More CI Performance Features Coming Soon - -The Nx team is continuing to push the limits of how fast CI can be. - -Soon, you'll be able to use [Nx Agents](/ci/features/nx-agents) to have Nx Cloud spin up agents for you based on how large your PR is. [Nx Agents](/ci/features/nx-agents) will also allow you to automatically identify and re-run flaky tests in their own agent. Later, Nx Workflows will enable you to use Nx Cloud directly as your CI provider, which will open up the possibility for more optimizations. - -{% call-to-action title="Sign Up for Early Access" icon="nxcloud" description="Experience Nx Cloud Agents for yourself" url="https://cloud.nx.app/workflows-early-access" /%} diff --git a/docs/nx-cloud/concepts/cache-security.md b/docs/nx-cloud/concepts/cache-security.md index b7ca6bd25fced..badfaf1fdb365 100644 --- a/docs/nx-cloud/concepts/cache-security.md +++ b/docs/nx-cloud/concepts/cache-security.md @@ -36,7 +36,7 @@ When an employee leaves a company, it is standard practice to change all the pas ### Skip the Cache When Creating a Deployment Artifact -In order to guarantee that cache poisoning will never affect your end users, [skip the cache](/core-features/cache-task-results#turn-off-or-skip-the-cache) when creating build artifacts that will actually be deployed. Skipping the cache for this one CI run is a very small performance cost, but it gives you 100% confidence that cache poisoning will not be an issue for the end users. +In order to guarantee that cache poisoning will never affect your end users, [skip the cache](/features/cache-task-results#turn-off-or-skip-the-cache) when creating build artifacts that will actually be deployed. Skipping the cache for this one CI run is a very small performance cost, but it gives you 100% confidence that cache poisoning will not be an issue for the end users. ### Do Not Manually Share Your Local Cache diff --git a/docs/nx-cloud/concepts/parallelization-distribution.md b/docs/nx-cloud/concepts/parallelization-distribution.md index a84713d0416a7..71add1b446cfe 100644 --- a/docs/nx-cloud/concepts/parallelization-distribution.md +++ b/docs/nx-cloud/concepts/parallelization-distribution.md @@ -70,47 +70,34 @@ It is possible in a smaller repository to manually calculate the best order for | Debuggability | ⛔️ Con | Build artifacts and logs are scattered across agent machines. | | Speed | 🎉 Pro | Faster than using a single machine | -### Nx Cloud Distributed Task Execution +### Distributed Task Execution Using Nx Agents -When you use Nx Cloud's distributed task execution you gain even more speed than manual distribution while preserving the simple set up and easy debuggability of the single machine scenario. +When you use **Nx Agents** (feature of Nx Cloud) you gain even more speed than manual distribution while preserving the simple set up and easy debuggability of the single machine scenario. The setup looks like this: ```yaml {% fileName="main-job.yml" %} # Coordinate the agents to run the tasks and stop agents when the build tasks are done -- npx nx-cloud start-ci-run --stop-agents-after=build +- npx nx-cloud start-ci-run --distribute-on="8 linux-medium-js" --stop-agents-after=build # Run any commands you want here -- nx affected -t lint,test,build +- nx affected -t lint test build ``` -```yaml {% fileName="agent.yml" %} -# Wait for tasks to execute -- npx nx-cloud start-agent -``` - -The visualization for distributed task execution looks like this: -![CI using DTE](/shared/images/dte/3agents.svg) +The visualization looks like this: +![CI using Agents](/shared/images/dte/3agents.svg) In the same way that Nx efficiently assigns tasks to parallel processes on a single machine so that pre-requisite tasks are executed first, Nx Cloud's distributed task execution efficiently assigns tasks to agent machines so that the idle time of each agent machine is kept to a minimum. Nx performs these calculations for each PR, so no matter which projects are affected or how your project structure changes, Nx will optimally assign tasks to the agents available. -As your repository grows and CI runs start to slow down, add another agent machine to your pipeline and Nx Cloud will use that extra capacity to handle the larger volume of tasks. If you would like Nx Cloud to automatically provision the agents for you, check out [Nx Agents](/ci/features/nx-agents). - #### Pros and Cons of Using Nx Cloud's Distributed Task Execution: -| Characteristic | Pro/Con | Notes | -| -------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Complexity | 🎉 Pro | The pipeline uses the same commands a developer would use on their local machine, but with one extra line before running tasks and a single line for each agent to execute. | -| Debuggability | 🎉 Pro | Build artifacts and logs are collated to the main machine as if all tasks were executed on that machine | -| Speed | 🎉 Pro | Fastest possible task distribution for each PR | - -### Nx Cloud Concurrency Limits - -As you scale your usage of Nx Cloud, you may run into concurrency limits. Nx Cloud puts a [limit on the number of CI machines](https://nx.app/pricing) in your workspace that are simultaneously connecting to Nx Cloud. This includes any machine running in CI - both the main CI pipeline machine and any agent machines. - -The Free plan offers 30 concurrent connections, the Startup plan offers 50 concurrent connections, the Pro plan offers 70 concurrent connections and the enterprise plan has no limit on concurrent connections. If each pipeline uses 9 agents in addition to the main job, that makes 10 concurrent connections for each PR. This would mean that on a Pro plan, you can have a maximum of 7 PRs running in CI simultaneously. If an eighth PR was submitted while those 7 were still running, your CI pipeline would experience some degradation and eventually failed CI runs. Once your organization's usage goes below the limit, Nx Cloud will resume functioning as normal. +| Characteristic | Pro/Con | Notes | +| -------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Complexity | 🎉 Pro | The pipeline uses the same commands a developer would use on their local machine, but with one extra line before running tasks. | +| Debuggability | 🎉 Pro | Build artifacts and logs are collated to the main machine as if all tasks were executed on that machine | +| Speed | 🎉 Pro | Fastest possible task distribution for each PR | ## Conclusion -If your repo is starting to grow large enough that CI times are suffering, or if your parallelization strategy is growing too complex to manage effectively, try [setting up Nx Cloud with Distributed Task Execution](/ci/features/distribute-task-execution). You can [generate a simple workflow](/nx-api/workspace/generators/ci-workflow) for common CI providers with a `nx g ci-workflow` or follow one of the [CI setup recipes](/ci/recipes/set-up). +If your repo is starting to grow large enough that CI times are suffering, or if your parallelization strategy is growing too complex to manage effectively, try [setting up Nx Agents](/ci/features/distribute-task-execution). You can [generate a simple workflow](/nx-api/workspace/generators/ci-workflow) for common CI providers with a `nx g ci-workflow` or follow one of the [CI setup recipes](/ci/recipes/set-up). Organizations that want extra help setting up Nx Cloud or getting the most out of Nx can [sign up for Nx Enterprise](https://nx.app/enterprise/). This package comes with extra support from the Nx team and the option to host Nx Cloud on your own servers. diff --git a/docs/nx-cloud/features/dynamic-agents.md b/docs/nx-cloud/features/dynamic-agents.md new file mode 100644 index 0000000000000..cf81b0736ea94 --- /dev/null +++ b/docs/nx-cloud/features/dynamic-agents.md @@ -0,0 +1,36 @@ +# Dynamically Allocate Agents + +The standard way to set up [Nx Agents](/ci/features/distribute-task-execution) is to use this flag: + +``` +--distribute-on="8 linux-medium-js" +``` + +...which always runs tasks on the same amount of machines, you can also have Nx Cloud scale the number of agents based on the size of your PR. Specify the number and type of agents to use for small, medium and large changesets by creating a yaml file like this: + +```yaml {% fileName=".nx/workflows/dynamic-changesets.yaml" %} +distribute-on: + small-changeset: 1 linux-medium-js + medium-changeset: 6 linux-medium-js + large-changeset: 10 linux-medium-js +``` + +{% callout type="note" title="How is the size of the PR determined?" %} +To determine the size of the PR, Nx Cloud calculates the relationship between the number of [affected projects](/ci/features/affected) and the total number of projects in the workspace. It then assigns it to one of the three categories: small, medium, or large. +{% /callout %} + +You can then reference it in your CI pipeline configuration: + +```yaml {% fileName=".github/workflows/main.yaml" %} +... +jobs: + - job: main + displayName: Main Job + ... + steps: + - checkout + - run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e-ci" + - ... +``` + +Now PRs that affect a small percentage of the repo will run on 1 agent, mid-size PRs will use 6 agents and large PRs will use 10 agents. This feature helps save costs on the smaller PRs while maintaining the high performance necessary for large PRs. diff --git a/docs/nx-cloud/features/flaky-tasks.md b/docs/nx-cloud/features/flaky-tasks.md new file mode 100644 index 0000000000000..9307845c8191d --- /dev/null +++ b/docs/nx-cloud/features/flaky-tasks.md @@ -0,0 +1,21 @@ +# Identify and Re-run Flaky Tasks + +Sometimes there are tasks in CI that can fail or succeed without any related code changes. These tasks are called flaky tasks. Because the cause of the flakiness can be difficult to determine, developers will typically re-run CI in the hopes that another run will cause the task to succeed and allow them to merge their PR. Every time a developer has to do this, it is harming their productivity and the productivity of the company as a whole. + +Nx is perfectly positioned to detect which tasks are flaky and automatically re-run the flaky task in a different agent so that developers can have confidence that a failed CI pipeline is a real failure. + +## Identify Flaky Tasks + +Nx creates a hash of all the inputs for a task whenever it is run. If Nx ever encounters a task that fails with a particular set of inputs and then succeeds with those same inputs, Nx knows for a fact that the task is flaky. Nx can't know with certainty when the task has been fixed to no longer be flaky, so if a particular task has no flakiness incidents for 2 weeks, the `flaky` flag is removed for that task. + +## Manually Mark a Task as Flaky or Not Flaky + +If you need to manually mark a task as flaky or not flaky, you can do so from the run details screen. Flaky tasks will have a button that says `Mark task as no longer flaky` and failed tasks that are not flaky will have a button that says `Mark task as likely flaky`. Using these buttons, you can ensure that Nx Cloud treats tasks in the appropriate way. + +![Mark task as no longer flaky button](/nx-cloud/features/mark-task-as-no-longer-flaky.png) + +![Mark task as likely flaky button](/nx-cloud/features/mark-task-as-likely-flaky.png) + +## Re-run Flaky Tasks + +When a flaky task fails in CI with [distributed task execution](/ci/features/distribute-task-execution) enabled, Nx will automatically send that task to a different agent and run it again (up to 2 tries in total). Its important to run the task on a different agent to ensure that the agent itself or the other tasks that were run on that agent are not the reason for the flakiness. diff --git a/docs/nx-cloud/features/mark-task-as-likely-flaky.png b/docs/nx-cloud/features/mark-task-as-likely-flaky.png new file mode 100644 index 0000000000000..3dba1a6dacdab Binary files /dev/null and b/docs/nx-cloud/features/mark-task-as-likely-flaky.png differ diff --git a/docs/nx-cloud/features/mark-task-as-no-longer-flaky.png b/docs/nx-cloud/features/mark-task-as-no-longer-flaky.png new file mode 100644 index 0000000000000..54047c921491b Binary files /dev/null and b/docs/nx-cloud/features/mark-task-as-no-longer-flaky.png differ diff --git a/docs/nx-cloud/features/split-e2e-tasks.md b/docs/nx-cloud/features/split-e2e-tasks.md new file mode 100644 index 0000000000000..e671325caa72b --- /dev/null +++ b/docs/nx-cloud/features/split-e2e-tasks.md @@ -0,0 +1,62 @@ +# Automatically Split E2E Tasks by File + +In almost every codebase, e2e tests are the largest portion of the CI pipeline. Typically, e2e tests are grouped by application so that whenever an application's code changes, all the e2e tests for that application are run. These large groupings of e2e tests make caching and distribution less effective. Also, because e2e tests deal with a lot of integration code, they are at a much higher risk to be flaky. + +You could manually address these problems by splitting your e2e tests into smaller tasks, but this requires developer time to maintain and adds additional configuration overhead to your codebase. Or, you could allow Nx to automatically split your Cypress or Playwright e2e tests by file. + +## Set up + +To enable automatically split e2e tasks, you need to turn on [inferred tasks](/concepts/inferred-tasks) for the [@nx/cypress](/nx-api/cypress) or [@nx/playwright](/nx-api/playwright) plugins. Run this command to set up inferred tasks: + +{% tabs %} +{% tab label="Cypress" %} + +```shell +nx add @nx/cypress +``` + +{% /tab %} +{% tab label="Playwright" %} + +```shell +nx add @nx/playwright +``` + +{% /tab %} +{% /tabs %} + +This command will register the appropriate plugin in the `plugins` array of `nx.json`. + +## Manual Configuration + +If you are already using the `@nx/cypress` or `@nx/playwright` plugin, you need to manually add the appropriate configuration to the `plugins` array of `nx.json`. The configuration settings can be found on the [Cypress](/nx-api/cypress#nxcypress-configuration) or [Playwright](/nx-api/playwright#nxplaywright-configuration) plugin docs. + +## Usage + +You can view the available tasks in the graph: + +```shell +nx graph +``` + +You'll see that there are tasks named `e2e`, `e2e-ci` and a task for each e2e test file. + +Developers can run all e2e tests locally the same way as usual: + +```shell +nx e2e my-project-e2e +``` + +You can update your CI pipeline to run `e2e-ci`, which will automatically run all the inferred tasks for the individual e2e test files. Run it like this: + +```shell +nx e2e-ci my-project-e2e +``` + +## Benefits + +Smaller e2e tasks enable the following benefits: + +- Nx's cache can be used for all the e2e tasks that succeeded and only the failed tasks need to be re-run +- Distributed Task Execution allows your e2e tests to be run on multiple machines simultaneously, which reduces the total time of the CI pipeline +- Nx Agents can [automatically re-run failed flaky e2e tests](/ci/features/flaky-tasks) on a separate agent without a developer needing to manually re-run the CI pipeline diff --git a/docs/nx-cloud/intro/ci-with-nx.md b/docs/nx-cloud/intro/ci-with-nx.md index d27830471ff62..26a2a5552ced7 100644 --- a/docs/nx-cloud/intro/ci-with-nx.md +++ b/docs/nx-cloud/intro/ci-with-nx.md @@ -20,23 +20,16 @@ npx nx connect {% cards cols="2" lgCols="4" mdCols="4" smCols="2" %} -{% link-card title="What is Nx Cloud?" type="video" url="https://youtu.be/NZF0ZJpgaJM" icon="nxcloud" /%} +{% link-card title="Circle CI with Nx" type="tutorial" url="/ci/intro/tutorials/circle" icon="circleci" /%} + +{% link-card title="GitHub Actions with Nx" type="tutorial" url="/ci/intro/tutorials/github-actions" icon="github" /%} {% link-card title="E2E Test Auto-Splitting and Distribution" type="video" url="https://youtu.be/XLOUFZeqRpM" icon="nxcloud" /%} -{% link-card title="Nx in 10 minutes!" type="video" url="https://youtu.be/-_4WMl-Fn0w" icon="nx" /%} {% link-card title="More On Youtube" type="video" url="https://www.youtube.com/@nxdevtools" icon="youtube" /%} {% /cards %} -{% cards cols="2" lgCols="2" mdCols="2" smCols="2" %} - -{% link-card title="Circle CI with Nx" type="tutorial" url="/ci/intro/tutorials/circle" icon="circleci" /%} - -{% link-card title="GitHub Actions with Nx" type="tutorial" url="/ci/intro/tutorials/github-actions" icon="github" /%} - -{% /cards %} - ## Ready? Get Started With Your Provider Not interested in a tutorial but you want to jump right in? Run the following command diff --git a/docs/nx-cloud/intro/nx-agents.md b/docs/nx-cloud/intro/nx-agents.md deleted file mode 100644 index 29ba53a6550da..0000000000000 --- a/docs/nx-cloud/intro/nx-agents.md +++ /dev/null @@ -1,140 +0,0 @@ -# Nx Agents: The Next Leap in Distributed Task Execution - -{% callout type="note" title="Early Preview Doc - Subject to Change" %} -**Early Preview of Nx Agents:** This is a work-in-progress feature, with a public launch anticipated in Feb 2024. Keep an eye on this document for continuous updates. Interested in early access? [Sign up here](https://go.nx.dev/nx-agents-ea). -{% /callout %} - -{% youtube -src="https://youtu.be/XLOUFZeqRpM" -title="Nx Agents in action splitting e2e tests at a file level" - /%} - -Nx Agents represent the next evolution of [Nx Cloud's Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), bringing a new level of efficiency and simplicity to your CI/CD pipelines. It takes away the complexity of configuring agents and comes with features such as scaling of agents based on the PR, flaky task re-running, and intelligent task splitting and distribution. Keep reading to learn more. - -Currently in private beta, Nx Agents are slated for public release in February 2024. Don't miss the opportunity to be among the first to experience this groundbreaking tool. Sign up now for early access. - -{% call-to-action title="Sign Up for Early Access" icon="nxcloud" description="Experience Nx Agents for yourself" url="https://go.nx.dev/nx-agents-ea" /%} - -## What's the Difference to DTE? - -Nx Cloud's [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution) introduced an easy way to intelligently distribute tasks across machines, allowing for a more fine-grained distribution taking historical data as well as the task dependencies into account. - -Using DTE you have to configure and instantiate your agents, which might be more or less complex depending on your CI provider. We have some guides on how to do that [here](/ci/recipes/set-up). - -![Diagram showing Nx Cloud distributing tasks to multiple agents on your CI provider](/shared/images/dte/distributed-caching-and-task-execution.svg) - -Nx Agents take away that complexity by delegating the agent management to Nx Cloud. You can think of them as a managed version of DTE. - -![Diagram showing Nx Cloud distributing tasks to multiple Nx Agents](/shared/images/dte/distributed-task-execution-on-workflows.svg) - -Keep reading to learn what the configuration and setup looks like. - -## Managed Agents, Seamless Configuration - -Enabling task distribution with Nx Agents can be done in a single line. Simply add the `--distribute-on` property to the `start-ci-run` line in your CI pipeline configuration: - -```yaml -- name: Start CI run - run: 'npx nx-cloud start-ci-run --distribute-on="8 linux-medium-js"' - ... -``` - -This instructs Nx Cloud to distribute tasks across 8 agents of type `linux-medium-js`. `linux-medium-js` is the name of the launch template that will be used to provision the agent. The default launch templates [can be found here](https://github.com/nrwl/nx-cloud-workflows/blob/main/launch-templates/linux.yaml) (there will be more once Nx Agents is publicly available). - -You can also define your own "launch templates" (here's an [example from the Nx repo](https://github.com/nrwl/nx/blob/master/.nx/workflows/agents.yaml)): - -```yaml -# .nx/workflows/agents.yaml -launch-templates: - linux-medium: - resource-class: 'docker_linux_amd64/medium+' - env: - CI: 'true' - GIT_AUTHOR_EMAIL: test@test.com - ... - NX_CLOUD_ACCESS_TOKEN: '{{secrets.NX_CLOUD_ACCESS_TOKEN}}' - init-steps: - ... - - name: Install Pnpm - script: | - npm install -g @pnpm/exe@8.7.4 - - - name: Pnpm Install - script: | - pnpm install --frozen-lockfile - - - name: Install Cypress - script: pnpm exec cypress install - - - name: Install Rust - - ... -``` - -Here are the [available resource classes](https://nx.app/pricing#resource-classes). - -## Intelligent Dynamic Scaling - -Instead of defining - -``` ---distribute-on="8 linux-medium-js" -``` - -...which always runs tasks on the same amount of machines, you can also have Nx Cloud scale the number of agents based on the size of your PR. - -```yaml {% fileName=".nx/workflows/dynamic-changesets.yaml" %} -distribute-on: - small-changeset: 1 linux-medium-js - medium-changeset: 6 linux-medium-js - large-changeset: 10 linux-medium-js -``` - -{% callout type="note" title="How is the size of the PR determined?" %} -To determine the size of the PR, Nx Cloud calculates the relationship between the number of [affected projects](/ci/features/affected) and the total number of projects in the workspace. It then assigns it to one of the three categories: small, medium, or large. This calculation is static right now but might be configurable once Nx Agents is publicly available. -{% /callout %} - -You can then reference it in your CI pipeline configuration: - -```yaml {% fileName=".github/workflows/main.yaml" %} -... -jobs: - - job: main - displayName: Main Job - ... - steps: - - checkout - - run: npx nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml" --stop-agents-after="e2e-wrapper" - - ... -``` - -## Automatic Task Splitting - -Imagine you're working on an end-to-end (e2e) project using tools like Cypress or Playwright. Traditionally, to make the most of features like [affected](/ci/features/affected), [caching](/ci/features/remote-cache), and [distribution](/ci/features/distribute-task-execution), you'd need to divide your project into smaller parts. But this approach can often be cumbersome and less efficient for developers. - -Nx is on the verge of introducing a game-changing feature that enables dynamic target definitions for projects (more details to come). Paired with Nx Agents, this innovation allows you to distribute e2e tests at the file level across various agents. - -This significantly cuts down the time required to run e2e tests. For instance, in the video shown at the beginning of the page, e2e test durations plummeted from 90 minutes to just 10 minutes. - -## Flaky Task Re-Running: Enhancing Reliability - -Flaky tasks are a common headache, particularly with tests and end-to-end (e2e) tests. Nx Agents offer a solid solution to detect and automatically retry such unreliable tasks. - -Nx Cloud keeps track of the targets being executed. A task, like `myapp:e2e`, is labeled as flaky **if it shows different outcomes (status codes) for the same cache hash key**. This key is an ideal task identifier, encompassing the command, environment variables, source files, and more. - -Consider this scenario: - -- An Nx agent runs `myapp:e2e`. -- Nx calculates the cache hash key for this task. -- **`myapp:e2e` fails**; Nx Cloud notes this failure along with the cache key. -- In a subsequent run, `myapp:e2e` is executed again. -- Nx recalculates the cache hash key, which matches the previous run's key (no existing cache since the initial task failed). -- This time, `myapp:e2e` **succeeds**. -- Nx Cloud identifies the task as flaky and stores this data temporarily. - -As a result, if Nx Cloud has marked a task as flaky, it will be automatically retried, ideally on a different Nx Agent to prevent issues from any residues of earlier runs. - ---- - -Sign up now for early access and be one of the first to try Nx Agents. - -{% call-to-action title="Sign Up for Early Access" icon="nxcloud" description="Experience Nx Cloud Agents for yourself" url="https://go.nx.dev/nx-agents-ea" /%} diff --git a/docs/nx-cloud/recipes/connect-to-cloud.md b/docs/nx-cloud/recipes/connect-to-cloud.md new file mode 100644 index 0000000000000..5311911815aff --- /dev/null +++ b/docs/nx-cloud/recipes/connect-to-cloud.md @@ -0,0 +1,33 @@ +# Connect to Nx Cloud + +Create an account on [nx.app](https://nx.app). There are several ways to connect your repository to Nx Cloud. + +#### Connect Directly Through GitHub + +If your repository is hosted on GitHub, we recommend you create an Nx Cloud organization based on your GitHub organization. + +![Connect Your VCS Account](/nx-cloud/tutorial/connect-vcs-account.png) + +After that, connect you repository. + +![Connect Your Repository](/nx-cloud/tutorial/connect-repository.png) + +This will send a pull request to your repository that will add the `nxCloudAccessToken` property to `nx.json`. + +![Nx Cloud Setup PR](/nx-cloud/tutorial/nx-cloud-setup-pr.png) + +This wires up all the CI for you and configures access. Folks who can see your repository can see your workspace on nx.app. + +## Manually Connect Your Workspace + +If your repository is hosted on a different source control provider, you can also connect to Nx Cloud manually. You'll need to add a source control integration later to enable [Nx Agents](/ci/features/distribute-task-execution). + +Run the following command in your repository: + +```shell +pnpm nx connect +``` + +Click the link in the terminal to claim your workspace on [nx.app](https://nx.app). + +The command generates an `nxCloudAccessToken` property inside of `nx.json`. This is a read-only token that should be committed to the repository. diff --git a/docs/nx-cloud/reference/config.md b/docs/nx-cloud/reference/config.md index c5d668d353cbd..2edd4ff4de9fd 100644 --- a/docs/nx-cloud/reference/config.md +++ b/docs/nx-cloud/reference/config.md @@ -30,7 +30,7 @@ The Nx Cloud runner is configured in `nx.json`. ## Cacheable Operations -Targets can be marked as cacheable either in the `targetDefaults` in `nx.json` or in the project configuration by setting `"cache": true`. With this option enabled they can be cached using Nx Cloud and distributed using distributed task execution (DTE). +Targets can be marked as cacheable either in the `targetDefaults` in `nx.json` or in the project configuration by setting `"cache": true`. With this option enabled they can be cached and distributed using Nx Cloud. ## Timeouts diff --git a/docs/nx-cloud/reference/env-vars.md b/docs/nx-cloud/reference/env-vars.md index b108e80d44806..6b54254b948b6 100644 --- a/docs/nx-cloud/reference/env-vars.md +++ b/docs/nx-cloud/reference/env-vars.md @@ -19,11 +19,6 @@ main jobs (e.g., when running CI on both Linux and Windows or when running the s of Node.js or Java). In this case you can set the `NX_CI_EXECUTION_ENV` env variable on main jobs and agents. The main job where the `NX_CI_EXECUTION_ENV` is set to, say, `macos`, will connect to the agents with the same env name. -### NX_RUN_GROUP - -Older versions of `nx-cloud` used `NX_RUN_GROUP` instead of `NX_CI_EXECUTION_ID` and `NX_CI_EXECUTION_ENV`. It -served the same purpose. - ### NX_CLOUD_ACCESS_TOKEN You can also configure the access token by setting the `NX_CLOUD_ACCESS_TOKEN` environment @@ -31,22 +26,6 @@ variable. `NX_CLOUD_ACCESS_TOKEN` takes precedence over the `accessToken` proper token stored in `nx.json` and a read-write token set via `NX_CLOUD_ACCESS_TOKEN` in CI. If you are using this environment variable with Distributed Task Execution, the value on the main and agent jobs must match. -### NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT - -The Nx Cloud plans distributed task execution based on the available information from the running agents. Due to -asynchronous nature of CI jobs, an agent might not have been created or started at the moment when DTE is initiated. -Setting `NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT` to say 8 will inform Nx Cloud to assume that there will be 8 agents -running. This can have an impact on better distribution of the tasks and allocation of the agents. - -### NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE - -Setting `NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE` to `true` will tell Nx Cloud to stop agents if a command -fails. When set to false (default value), you need to make sure to invoke `nx-cloud stop-all-agents` even if CI fails. - -### NX_CLOUD_DISTRIBUTED_EXECUTION - -Setting `NX_CLOUD_DISTRIBUTED_EXECUTION` to `true` enables distributed task execution. - ### NX_CLOUD_ENCRYPTION_KEY You can set the `encryptionKey` property in `nx.json` or set the `NX_CLOUD_ENCRYPTION_KEY` environment variable to @@ -61,6 +40,22 @@ By default, Nx Cloud requests will time out after 10 seconds. `NX_CLOUD_NO_TIMEO Setting `NX_VERBOSE_LOGGING` to true will output the debug information about agents communicating with the main job. This can be useful for debugging unexpected cache misses and issues with on-prem setups. +## Deprecated + +### NX_RUN_GROUP + +Older versions of `nx-cloud` used `NX_RUN_GROUP` instead of `NX_CI_EXECUTION_ID` and `NX_CI_EXECUTION_ENV`. It +served the same purpose. + +### NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE + +Setting `NX_CLOUD_DISTRIBUTED_EXECUTION_STOP_AGENTS_ON_FAILURE` to `true` will tell Nx Cloud to stop agents if a command +fails. We recommend using `npx nx-cloud start-ci-run --stop-agents-on-failure=true` instead. + +### NX_CLOUD_DISTRIBUTED_EXECUTION + +Setting `NX_CLOUD_DISTRIBUTED_EXECUTION` to `false` disables distributed task execution. We recommend passing `--no-dte` or `--no-agents` instead. + ## See Also - [Nx Environment Variables](/reference/environment-variables) diff --git a/docs/nx-cloud/reference/launch-templates.md b/docs/nx-cloud/reference/launch-templates.md new file mode 100644 index 0000000000000..b1635b9616b1e --- /dev/null +++ b/docs/nx-cloud/reference/launch-templates.md @@ -0,0 +1,66 @@ +# Launch Templates + +You can find built-in launch templates [here](https://github.com/nrwl/nx-cloud-workflows/tree/main/launch-templates). + +The easiest way to create a new custom launch template is to modify one of the built-in ones. To do that, create a file in the +`.nx/workflows` folder and copy one of the built-in templates there. You can name the file any way you want (e.g., `agents.yaml`). + +This is an example of a launch template using all built-in features: + +```yaml +launch-templates: + my-linux-medium-js: + resourceClass: '' + image: 'ubuntu22.04-node20.9-v1' + env: MY_ENV_VAR=shared + init-steps: + - name: Checkout # using a reusable step + uses: 'nrwl/nx-cloud-workflows/v1.1/workflow-steps/checkout/main.yaml' + - name: Restore Node Modules Cache + uses: 'nrwl/nx-cloud-workflows/v1.1/workflow-steps/cache/main.yaml' + env: + KEY: 'package-lock.json|yarn.lock|pnpm-lock.yaml' + PATHS: 'node_modules' + BASE_BRANCH: 'main' + - name: Install Node Modules + uses: 'nrwl/nx-cloud-workflows/v1.1/workflow-steps/install-node-modules/main.yaml' + - name: Run a custom script + git config --global user.email test@test.com + git config --global user.name "Test Test" + - name: Setting env # Redefine PATH for further steps + script: echo "PATH=$HOME/my-folder:$PATH" >> $NX_CLOUD_ENV + - name: Print path + script: echo $PATH # will include my-folder + - name: Define env var for a step + env: MY_ENV_VAR=for-step + script: echo $MY_ENV_VAR # will print for-step +``` + +## Resource Classes + +The following resource classes are available: + +- `docker_linux_amd64/small` +- `docker_linux_amd64/medium` +- `docker_linux_amd64/medium+` +- `docker_linux_amd64/large` +- `docker_linux_amd64/large+` +- `docker_linux_amd64/extra_large` +- `docker_linux_amd64/extra_large+` + +See their detailed description and pricing at [nx.app/pricing](https://nx.app/pricing). + +## Image + +The following images are available: + +- `ubuntu22.04-node20.9-v1` +- `ubuntu22.04-node20.9-withDind-v1` +- `ubuntu22.04-node20.9-v2` +- `ubuntu22.04-node20.9-withDind-v2` + +Enterprise accounts can use custom images. + +## Reusable Steps + +You can find the list of reusable step [here](https://github.com/nrwl/nx-cloud-workflows/tree/main/workflow-steps). diff --git a/docs/nx-cloud/reference/nx-cloud-cli.md b/docs/nx-cloud/reference/nx-cloud-cli.md index 5ea2837dc3960..0770d9b533ff8 100644 --- a/docs/nx-cloud/reference/nx-cloud-cli.md +++ b/docs/nx-cloud/reference/nx-cloud-cli.md @@ -7,6 +7,38 @@ command correspond to the same CI run. You can configure your CI run by passing the following flags: +### --distribute-on + +Tells Nx Cloud how many agents to use (and what launch templates to use) to distribute tasks. E.g., +`npx nx-cloud start-ci-run --distribute-on="8 linux-medium-js"` will distribute CI using 8 agents that are initialized +using the `linux-medium-js` launch template. + +You can use different types of launch templates as follows: +`npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js, 3 linux-large-js"`. + +You can also define the configuration in a file and reference it as follows: +`npx nx-cloud start-ci-run --distribute-on=".nx/workflows/dynamic-changesets.yaml"`. + +```yaml {% fileName=".nx/workflows/dynamic-changesets.yaml" %} +distribute-on: + small-changeset: 1 linux-medium-js + medium-changeset: 6 linux-medium-js + large-changeset: 10 linux-medium-js +``` + +### --with-env-vars + +By default, invoking `npx nx-cloud start-ci-run` will take all env vars prefixed with `NX_` and send them over to agents. +This means that your access token, verbose logging configuration and other NX related env vars will be the same on your +main CI jobs and on agents. + +If you want to pass other env vars from the main job to agents, you can do it as follows: `--with-env-vars="VAR1,VAR2"`. +This will set `VAR1` and `VAR2` on agents to the same values set on the main job before any steps run. + +You can also pass `--with-env-vars="auto"` which will filter out all OS-specific env vars and pass the rest to agents. + +Note: none of the values passed to agents are stored by Nx Cloud. + ### --use-dte-by-default By default, invoking `npx nx-cloud start-ci-run` will configure Nx to distribute all commands by default. You can @@ -26,20 +58,36 @@ run. You can fix it by telling Nx Cloud that it can terminate agents after it sees a certain target: `npx nx-cloud start-ci-run --stop-agents-after=e2e`. -> Earlier versions of `nx-cloud` required you to set the `NX_CLOUD_DISTRIBUTED_EXECUTION` env variable to `true` -> to -> enable DTE, but in the latest version `npx nx-cloud start-ci-run` does it automatically. +### --require-explicit-completion -## Enabling/Disabling DTE +By default, Nx Cloud will monitor the main CI job and once it completes it will complete the associated CIPE object on the +Nx Cloud side. You can disable this by passing `--require-explicit-completion`. In this case, you will have to add +`npx nx-cloud complete-ci-run`. + +## Enabling/Disabling Distribution Invoking `npx nx-cloud start-ci-run` will tell Nx to distribute by default. You can enable/disable distribution for individual commands as follows: -- `nx affected -t build --dte` (explicitly enable distribution, Nx >= 14.7) -- `nx affected -t build --no-dte` (explicitly disable distribution, Nx >= 14.7) -- `NX_CLOUD_DISTRIBUTED_EXECUTION=true nx affected -t build` (explicitly enable distribution) -- `NX_CLOUD_DISTRIBUTED_EXECUTION=false nx affected -t build` (explicitly disable distribution) +{% tabs %} +{% tab label="Nx >= 18" %} + +- `nx affected -t build --agents` (explicitly enable distribution) +- `nx affected -t build --no-agents` (explicitly disable distribution) + +{% /tab %} +{% tab label="Nx >= 14.7" %} + +- `nx affected -t build --dte` (explicitly enable distribution) +- `nx affected -t build --no-dte` (explicitly disable distribution) + +{% /tab %} +{% /tabs %} ## npx nx-cloud stop-all-agents -This command tells Nx Cloud to terminate all agents associated with this CI run. +Same as `npx nx-cloud complete-ci-run` and `npx nx-cloud complete-run-group`. + +This command tells Nx Cloud to terminate all agents associated with this CI pipeline execution. +Invoking this command is not needed anymore. New versions of Nx Cloud can track when the main job terminates +and terminate associated agents automatically. diff --git a/docs/nx-cloud/tutorial/cipe-agents-in-progress.png b/docs/nx-cloud/tutorial/cipe-agents-in-progress.png new file mode 100644 index 0000000000000..93a31e0058b77 Binary files /dev/null and b/docs/nx-cloud/tutorial/cipe-agents-in-progress.png differ diff --git a/docs/nx-cloud/tutorial/circle.md b/docs/nx-cloud/tutorial/circle.md index 97a7ab64019ac..465381cefde4c 100644 --- a/docs/nx-cloud/tutorial/circle.md +++ b/docs/nx-cloud/tutorial/circle.md @@ -49,10 +49,10 @@ To get started: 4. Finally, make sure all task are working on your machine, by running lint, test, build and e2e on all projects of the workspace ```shell - pnpm nx run-many -t lint,test,build,e2e + pnpm nx run-many -t lint test build e2e-ci ``` -## Set-up Circle CI +## Set Up Circle CI In order to use Circle CI, you need to [sign up and create an organization](https://circleci.com/docs/first-steps/#sign-up-and-create-an-org). Follow the steps in the Circle CI documentation to connect to your GitHub repository. When you are asked to configure a pipeline, choose any option, since we'll overwrite it in the next step. @@ -195,7 +195,7 @@ workflows: - main ``` -The `restore_cache` and `save_cache` steps are using a hash key that is created from the contents of the `pnpm-lock.yaml` file. This way if the `pnpm-lock.yaml` file remains the same, the next CI pipeline can pull from the cache instead of downloading `node_modules` again. This is similar to the way [Nx hashes input files to cache the results of tasks](/core-features/cache-task-results). +The `restore_cache` and `save_cache` steps are using a hash key that is created from the contents of the `pnpm-lock.yaml` file. This way if the `pnpm-lock.yaml` file remains the same, the next CI pipeline can pull from the cache instead of downloading `node_modules` again. This is similar to the way [Nx hashes input files to cache the results of tasks](/features/cache-task-results). Create a new branch with these changes and submit a PR to your repo to test them. Merge your PR into the `main` branch when you're ready to move to the next section. @@ -241,7 +241,7 @@ Nx comes with a dedicated ["affected" command](/ci/features/affected) to help wi ### Configuring the Comparison Range for Affected Commands -To understand which projects are affected, Nx uses the Git history and the [project graph](/core-features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. +To understand which projects are affected, Nx uses the Git history and the [project graph](/features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. The affected command takes a `base` and `head` commit. The default `base` is your `main` branch and the default `head` is your current file system. This is generally what you want when developing locally, but in CI, you need to customize these values. @@ -279,8 +279,8 @@ jobs: - ~/.cache/Cypress - nx/set-shas - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=3 --configuration=ci - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t e2e --parallel=1 + - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build --parallel=3 + - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t e2e-ci --parallel=1 workflows: build: jobs: @@ -308,154 +308,122 @@ When you check the CI logs for this PR, you'll notice that no tasks were run by Merge your PR into the `main` branch when you're ready to move to the next section. -## Enable Remote Caching on Circle CI +## Enable Remote Caching And Distributed Task Execution Using Nx Cloud -Reducing the number of tasks to run via [affected commands](/ci/features/affected) (as seen in the previous section) is helpful, but might not be enough. By default [Nx caches the results of tasks](/core-features/cache-task-results) on your local machine. But CI and local developer machines are still performing the same tasks on the same code - wasting time and money. The [Nx Cloud remote cache](/ci/features/remote-cache) can eliminate that waste for you. +Only running necessary tasks via [affected commands](/ci/features/affected) (as seen in the previous section) is helpful, but might not be enough. By default [Nx caches the results of tasks](/features/cache-task-results) on your local machine. But CI and other developer machines will still perform the same tasks on the same code - wasting time and money. Also, as your repository grows, running all the tasks on a single agent will cause the CI pipeline to take too long. The only way to decrease the CI pipeline time is to distribute your CI across many machines. Let's solve both of these problems using Nx Cloud. -```shell -pnpm nx connect -``` +### Connect Your Workspace to Nx Cloud + +Create an account on [nx.app](https://nx.app). There are several ways to connect your repository to Nx Cloud. + +#### Connect Directly Through GitHub + +The easiest way is to create an Nx Cloud organization based on your GitHub organization. -Click the link in the terminal to claim your workspace on [nx.app](https://nx.app). Once your workspace is successfully connected you should see an empty dashboard. +![Connect Your VCS Account](/nx-cloud/tutorial/connect-vcs-account.png) -![Empty Nx Cloud Dashboard](/nx-cloud/tutorial/nx-cloud-empty-workspace.png) +After that, connect you repository. -Once your workspace is connected to Nx Cloud, run some tasks locally to prime the cache: +![Connect Your Repository](/nx-cloud/tutorial/connect-repository.png) + +This will send a pull request to your repository that will add the `nxCloudAccessToken` property to `nx.json`. + +![Nx Cloud Setup PR](/nx-cloud/tutorial/nx-cloud-setup-pr.png) + +This wires up all the CI for you and configures access. Folks who can see your repository can see your workspace on nx.app. + +#### Manually Connect Your Workspace + +To manually connect your workspace to Nx Cloud, run the following command in your repository: ```shell -pnpm nx run-many -t lint,test,build,e2e +pnpm nx connect ``` -Now let's commit the changes to a new `ci-caching` branch and create a PR. The only change to the source code is adding an `nxCloudAccessToken` property to `nx.json`. +Click the link in the terminal to claim your workspace on [nx.app](https://nx.app). -```json {% fileName="nx.json" %} -{ - ... - "nxCloudAccessToken": "MWM4NTU..." -} -``` +The command generates an `nxCloudAccessToken` property inside of `nx.json`. This is a read-only token that should be committed to the repository. + +### Enable Remote Caching using Nx Replay + +[Nx Cloud](https://nx.app) provides [Nx Replay](/ci/features/remote-cache), which is a powerful, scalable and, very importantly, secure way to share task artifacts across machines. It lets you configure permissions and guarantees the cached artifacts cannot be tempered with. + +[Nx Replay](/ci/features/remote-cache) is enabled by default. To see it in action, rerun the CI for the PR opened by Nx Cloud. When Circle CI now processes our tasks they'll only take a fraction of the usual time. If you inspect the logs a little closer you'll see a note saying `[remote cache]`, indicating that the output has been pulled from the remote cache rather than running it. The full log of each command will still be printed since Nx restores that from the cache as well. ![Circle CI after enabling remote caching](/nx-cloud/tutorial/circle-ci-remote-cache.png) -The commands could be restored from the remote cache because we had run them locally before pushing the changes, thus priming the cache with the results. You can **configure** whether local runs should be read-only or read/write. [Our docs page has more details on security settings for your remote cache](/ci/concepts/cache-security). +![Run Details with remote cache hits](/nx-cloud/tutorial/nx-cloud-run-details.png) -You might also want to learn more about [how to fine-tune caching](/recipes/running-tasks/customizing-inputs) to get even better results. +What is more, if you run tasks locally, you will also get cache hits: + +```{% command="nx run-many -t build" %} +... + ✔ nx run express-legacy:build [remote cache] + ✔ nx run nx-plugin-legacy:build [remote cache] + ✔ nx run esbuild-legacy:build [remote cache] + ✔ nx run react-native-legacy:build [remote cache] + ✔ nx run angular-legacy:build [remote cache] + ✔ nx run remix-legacy:build [remote cache] + + ———————————————————————————————————————————————— + + > NX Successfully ran target build for 58 projects and 62 tasks they depend on (1m) + + Nx read the output from the cache instead of running the command for 116 out of 120 tasks. +``` + +You might also want to learn more about [how to fine-tune caching](/recipes/running-tasks/configure-inputs) to get even better results. Merge your PR into the `main` branch when you're ready to move to the next section. -## Parallelize Tasks across Multiple Machines +### Parallelize Tasks Across Multiple Machines Using Nx Agents -The affected command and remote caching help speed up the average CI time, but there will be some PRs that affect everything in the repository. The only way to speed up that worst case scenario is through efficient parallelization. The best way to parallelize CI with Nx is to use [distributed task execution (DTE)](/ci/features/distribute-task-execution). +The affected command and Nx Replay help speed up the average CI time, but there will be some PRs that affect everything in the repository. The only way to speed up that worst case scenario is through efficient parallelization. The best way to parallelize CI with Nx is to use Nx Agents. -Nx Cloud's DTE feature +The Nx Agents feature -- takes a command (e.g. `run-many -t build,lint,test,e2e`) and splits it into individual tasks which it then distributes across multiple agents -- distributes tasks by considering the dependencies between them; e.g. if `e2e` depends on `build`, Nx Cloud will make sure that `build` is executed before `e2e`; it does this across machines +- takes a command (e.g. `run-many -t build lint test e2e-ci`) and splits it into individual tasks which it then distributes across multiple agents +- distributes tasks by considering the dependencies between them; e.g. if `e2e-ci` depends on `build`, Nx Cloud will make sure that `build` is executed before `e2e-ci`; it does this across machines - distributes tasks to optimize for CPU processing time and reduce idle time by taking into account historical data about how long each task takes to run - collects the results and logs of all the tasks and presents them in a single view - automatically shuts down agents when they are no longer needed -Let's enable DTE in our CI pipeline configuration. First let's define the agent which restores the NPM dependencies and then runs the `nx-cloud start-agent` command which notifies Nx Cloud that this machine is waiting to run tasks that are assigned to it. `no_output_timeout: 60m` means that this agent will automatically shut down if it doesn't receive any instructions for 60 minutes. +Let's enable Nx Agents -```yaml {% fileName=".circleci/config.yml" highlightLines=["5-25"] %} -version: 2.1 -orbs: - nx: nrwl/nx@1.5.1 -jobs: - agent: - docker: - - image: cimg/node:lts-browsers - parameters: - ordinal: - type: integer - steps: - - checkout - - restore_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - - run: - name: install dependencies - command: pnpm install --frozen-lockfile - - save_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - paths: - - node_modules - - ~/.cache/Cypress - - run: - command: pnpm nx-cloud start-agent - no_output_timeout: 60m - main: ... +``` +pnpm exec nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" ``` -The `main` job looks very similar to the previous configuration, with the addition of a single line above the `nx affected` commands. +We recommend you add this line right after you check out the repo, before installing node modules. -```yaml {% fileName=".circleci/config.yml" highlightLines=[24,29] %} -version: 2.1 -orbs: - nx: nrwl/nx@1.5.1 -jobs: - agent: - - ... - main: - docker: - - image: cimg/node:lts-browsers - steps: - - checkout - - restore_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - - run: - name: install dependencies - command: pnpm install --frozen-lockfile - - save_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - paths: - - node_modules - - ~/.cache/Cypress - - nx/set-shas +- `nx-cloud start-ci-run --distribute-on="3 linux-medium-j` lets Nx know that all the tasks after this line should using Nx Agents and that Nx Cloud should use 3 instances of the `linux-medium-js` launch template. See below on how to configure a custom launch template. +- `--stop-agents-after="e2e-ci"` lets Nx Cloud know which line is the last command in this pipeline. Once there are no more e2e tasks for an agent to run, Nx Cloud will automatically shut them down. This way you're not wasting money on idle agents while a particularly long e2e task is running on a single agent. - - run: pnpm nx-cloud start-ci-run --stop-agents-after="e2e" +Try it out by creating a new PR with the above changes. - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=3 --configuration=ci - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t e2e --parallel=1 -``` +Once Circle CI starts, you should see multiple agents running in parallel similar to this: -- `nx-cloud start-ci-run` lets Nx know that all the tasks after this line should be orchestrated with Nx Cloud's DTE process -- `--stop-agents-after="e2e"` lets Nx Cloud know which line is the last command in this pipeline. Once there are no more e2e tasks for an agent to run, Nx Cloud will automatically shut them down. This way you're not wasting money on idle agents while a particularly long e2e task is running on a single agent. +![CIPE Agents In Progress](/nx-cloud/tutorial/cipe-agents-in-progress.png) -Finally in the `workflows` section we instantiate the number of agents we want to run. The **full pipeline configuration** looks like this: +With this pipeline configuration in place, no matter how large the repository scales, Nx Cloud will adjust and distribute tasks across agents in the optimal way. If CI pipelines start to slow down, just add some agents. One of the main advantages is that this pipeline definition is declarative. We tell Nx what commands to run, but not how to distribute them. That way even if our monorepo structure changes and evolves over time, the distribution will be taken care of by Nx Cloud. -```yaml {% fileName=".circleci/config.yml" %} +### Running Commands Without Distribution + +Sometimes you want to distribute most of your commands, but run some of them in Circle CI. You can do this with the `--no-agents` flag as follows: + +```yaml {% fileName=".circleci/config.yml" highlightLines=[25] %} version: 2.1 orbs: nx: nrwl/nx@1.5.1 jobs: - agent: - docker: - - image: cimg/node:lts-browsers - parameters: - ordinal: - type: integer - steps: - - checkout - - restore_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - - run: - name: install dependencies - command: pnpm install --frozen-lockfile - - save_cache: - key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - paths: - - node_modules - - ~/.cache/Cypress - - run: - command: pnpm nx-cloud start-agent - no_output_timeout: 60m main: docker: - image: cimg/node:lts-browsers steps: - checkout + - run: pnpm exec nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" - restore_cache: key: npm-dependencies-{{ checksum "pnpm-lock.yaml" }} - run: @@ -468,36 +436,19 @@ jobs: - ~/.cache/Cypress - nx/set-shas - - run: pnpm nx-cloud start-ci-run --stop-agents-after="e2e" - - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=3 --configuration=ci - - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t e2e --parallel=1 + - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build --parallel=3 + - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t e2e-ci --parallel=1 + - run: pnpm nx affected --base=$NX_BASE --head=$NX_HEAD -t deploy --no-agents # run without distribution workflows: build: jobs: - - agent: - matrix: - parameters: - ordinal: [1, 2, 3] - main ``` -Try it out by creating a new PR with the above changes. - -Once Circle CI starts, you should see multiple agents running in parallel: - -![Circle CI showing multiple DTE agents](/nx-cloud/tutorial/circle-dte-multiple-agents.png) - -If you open your Nx Cloud dashboard, you'll get a better view of the individual tasks and their corresponding logs. - -![Nx Cloud run details](/nx-cloud/tutorial/nx-cloud-run-details.png) - -With this pipeline configuration in place, no matter how large the repository scales, Nx Cloud will adjust and distribute tasks across agents in the optimal way. If CI pipelines start to slow down, just add some agents to the `ordinal: [1, 2, 3]` array. One of the main advantages is that such a pipeline definition is declarative. We just give instructions what commands to run, but not how to distribute them. As such even if our monorepo structure changes and evolves over time, the distribution will be taken care of by Nx Cloud. - ## Next Steps You now have a highly optimized CI configuration that will scale as your repository scales. See what else you can do with Nx Cloud. -- Set up [GitHub PR integration](/ci/recipes/source-control-integration/github) to view Nx Cloud results directly in your PR -- Choose the [security settings](/ci/concepts/cache-security) that make sense for your organization -- [Record non-Nx commands](/ci/recipes/other/record-commands) and view the results in the Nx Cloud interface +- Configure [dynamic agent allocation](/ci/features/dynamic-agents) +- Learn about [automatically splitting e2e tasks](/ci/features/split-e2e-tasks) +- Identify and re-run [flaky tasks](/ci/features/flaky-tasks) diff --git a/docs/nx-cloud/tutorial/connect-repository.png b/docs/nx-cloud/tutorial/connect-repository.png new file mode 100644 index 0000000000000..019bd4f555914 Binary files /dev/null and b/docs/nx-cloud/tutorial/connect-repository.png differ diff --git a/docs/nx-cloud/tutorial/connect-vcs-account.png b/docs/nx-cloud/tutorial/connect-vcs-account.png new file mode 100644 index 0000000000000..441d991b3701d Binary files /dev/null and b/docs/nx-cloud/tutorial/connect-vcs-account.png differ diff --git a/docs/nx-cloud/tutorial/github-actions.md b/docs/nx-cloud/tutorial/github-actions.md index 9e5312b591a31..0ea90355e4a2b 100644 --- a/docs/nx-cloud/tutorial/github-actions.md +++ b/docs/nx-cloud/tutorial/github-actions.md @@ -49,10 +49,10 @@ To get started: 4. Finally, make sure all task are working on your machine, by running lint, test, build and e2e on all projects of the workspace ```shell - pnpm nx run-many -t lint,test,build,e2e + pnpm nx run-many -t lint test build e2e ``` -## Set-up GitHub Actions +## Set Up GitHub Actions To get started with GitHub Actions, we'll create a pipeline that just logs a message. First, checkout a new branch: @@ -190,7 +190,7 @@ jobs: - run: pnpm nx build cart ``` -The `restore_cache` and `save_cache` steps are using a hash key that is created from the contents of the `pnpm-lock.yaml` file. This way if the `pnpm-lock.yaml` file remains the same, the next CI pipeline can pull from the cache instead of downloading `node_modules` again. This is similar to the way [Nx hashes input files to cache the results of tasks](/core-features/cache-task-results). +The `restore_cache` and `save_cache` steps are using a hash key that is created from the contents of the `pnpm-lock.yaml` file. This way if the `pnpm-lock.yaml` file remains the same, the next CI pipeline can pull from the cache instead of downloading `node_modules` again. This is similar to the way [Nx hashes input files to cache the results of tasks](/features/cache-task-results). Create a new branch with these changes and submit a PR to your repo to test them. Merge your PR into the `main` branch when you're ready to move to the next section. @@ -236,7 +236,7 @@ Nx comes with a dedicated ["affected" command](/ci/features/affected) to help wi ### Configuring the Comparison Range for Affected Commands -To understand which projects are affected, Nx uses the Git history and the [project graph](/core-features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. +To understand which projects are affected, Nx uses the Git history and the [project graph](/features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. The affected command takes a `base` and `head` commit. The default `base` is your `main` branch and the default `head` is your current file system. This is generally what you want when developing locally, but in CI, you need to customize these values. @@ -286,7 +286,7 @@ jobs: - uses: nrwl/nx-set-shas@v3 # This line is needed for nx affected to work when CI is running on a PR - run: git branch --track main origin/main - - run: pnpm nx affected -t lint,test,build --parallel=3 --configuration=ci + - run: pnpm nx affected -t lint test build --parallel=3 - run: pnpm nx affected -t e2e --parallel=1 ``` @@ -309,40 +309,57 @@ When you check the CI logs for this PR, you'll notice that no tasks were run by Merge your PR into the `main` branch when you're ready to move to the next section. -## Enable Remote Caching on GitHub Actions +## Enable Remote Caching and Distributed Task Execution Using Nx Cloud -Reducing the number of tasks to run via [affected commands](/ci/features/affected) (as seen in the previous section) is helpful, but might not be enough. By default [Nx caches the results of tasks](/core-features/cache-task-results) on your local machine. But CI and local developer machines are still performing the same tasks on the same code - wasting time and money. The [Nx Cloud remote cache](/ci/features/remote-cache) can eliminate that waste for you. +Only running necessary tasks via [affected commands](/ci/features/affected) (as seen in the previous section) is helpful, but might not be enough. By default [Nx caches the results of tasks](/features/cache-task-results) on your local machine. But CI and other developer machines will still perform the same tasks on the same code - wasting time and money. Also, as your repository grows, running all the tasks on a single agent will cause the CI pipeline to take too long. The only way to decrease the CI pipeline time is to distribute your CI across many machines. Let's solve both of these problems using Nx Cloud. -```shell -pnpm nx connect -``` +### Connect Your Workspace to Nx Cloud -Click the link in the terminal to claim your workspace on [nx.app](https://nx.app). Once your workspace is successfully connected you should see an empty dashboard. +Create an account on [nx.app](https://nx.app). The easiest way to connect your repository to Nx Cloud is to create an Nx Cloud organization based on your GitHub organization. -![Empty Nx Cloud Dashboard](/nx-cloud/tutorial/nx-cloud-empty-workspace.png) +![Connect Your VCS Account](/nx-cloud/tutorial/connect-vcs-account.png) -Once your workspace is connected to Nx Cloud, run some tasks locally to prime the cache: +After that, connect you repository. -```shell -pnpm nx run-many -t lint,test,build,e2e -``` +![Connect Your Repository](/nx-cloud/tutorial/connect-repository.png) -Now let's commit the changes to a new `ci-caching` branch and create a PR. The only change to the source code is adding an `nxCloudAccessToken` property to `nx.json`. +This will send a pull request to your repository that will add the `nxCloudAccessToken` property to `nx.json`. -```json {% fileName="nx.json" %} -{ - ... - "nxCloudAccessToken": "MWM4NTU..." -} -``` +![Nx Cloud Setup PR](/nx-cloud/tutorial/nx-cloud-setup-pr.png) + +This wires up all the CI for you and configures access. Folks who can see your repository can see your workspace on nx.app. + +### Enable Remote Caching using Nx Replay + +[Nx Cloud](https://nx.app) provides [Nx Replay](/ci/features/remote-cache), which is a powerful, scalable and, very importantly, secure way to share task artifacts across machines. It lets you configure permissions and guarantees the cached artifacts cannot be tempered with. + +[Nx Replay](/ci/features/remote-cache) is enabled by default. To see it in action, rerun the CI for the PR opened by Nx Cloud. When GitHub Actions now processes our tasks they'll only take a fraction of the usual time. If you inspect the logs a little closer you'll see a note saying `[remote cache]`, indicating that the output has been pulled from the remote cache rather than running it. The full log of each command will still be printed since Nx restores that from the cache as well. ![GitHub Actions after enabling remote caching](/nx-cloud/tutorial/gh-ci-remote-cache.png) -The commands could be restored from the remote cache because we had run them locally before pushing the changes, thus priming the cache with the results. You can **configure** whether local runs should be read-only or read/write. [Our docs page has more details on security settings for your remote cache](/ci/concepts/cache-security). +![Run Details with remote cache hits](/nx-cloud/tutorial/nx-cloud-run-details.png) + +What is more, if you run tasks locally, you will also get cache hits: + +```{% command="nx run-many -t build" %} +... + ✔ nx run express-legacy:build [remote cache] + ✔ nx run nx-plugin-legacy:build [remote cache] + ✔ nx run esbuild-legacy:build [remote cache] + ✔ nx run react-native-legacy:build [remote cache] + ✔ nx run angular-legacy:build [remote cache] + ✔ nx run remix-legacy:build [remote cache] + + ———————————————————————————————————————————————— + + > NX Successfully ran target build for 58 projects and 62 tasks they depend on (1m) + + Nx read the output from the cache instead of running the command for 116 out of 120 tasks. +``` -You might also want to learn more about [how to fine-tune caching](/recipes/running-tasks/customizing-inputs) to get even better results. +You might also want to learn more about [how to fine-tune caching](/recipes/running-tasks/configure-inputs) to get even better results. Merge your PR into the `main` branch when you're ready to move to the next section. @@ -369,45 +386,28 @@ This will verify that Nx Cloud can connect to your repo. Upon a successful test, Now any new PRs in your repo should have a comment automatically added that links directly to Nx Cloud. For other ways of setting up PR integration, read the [Enable GitHub PR Integration recipe](/ci/recipes/source-control-integration/github). -## Parallelize Tasks across Multiple Machines +### Parallelize Tasks Across Multiple Machines Using Nx Agents -The affected command and remote caching help speed up the average CI time, but there will be some PRs that affect everything in the repository. The only way to speed up that worst case scenario is through efficient parallelization. The best way to parallelize CI with Nx is to use [distributed task execution (DTE)](/ci/features/distribute-task-execution). +The affected command and Nx Replay help speed up the average CI time, but there will be some PRs that affect everything in the repository. The only way to speed up that worst case scenario is through efficient parallelization. The best way to parallelize CI with Nx is to use Nx Agents. -Nx Cloud's DTE feature +The Nx Agents feature -- takes a command (e.g. `run-many -t build,lint,test,e2e`) and splits it into individual tasks which it then distributes across multiple agents -- distributes tasks by considering the dependencies between them; e.g. if `e2e` depends on `build`, Nx Cloud will make sure that `build` is executed before `e2e`; it does this across machines +- takes a command (e.g. `run-many -t build lint test e2e-ci`) and splits it into individual tasks which it then distributes across multiple agents +- distributes tasks by considering the dependencies between them; e.g. if `e2e-ci` depends on `build`, Nx Cloud will make sure that `build` is executed before `e2e-ci`; it does this across machines - distributes tasks to optimize for CPU processing time and reduce idle time by taking into account historical data about how long each task takes to run - collects the results and logs of all the tasks and presents them in a single view - automatically shuts down agents when they are no longer needed -Let's enable DTE in our CI pipeline configuration. We'll use two reusable workflows from the `nrwl/ci` repository. You can check out the full [API](https://github.com/nrwl/ci) for those workflows. +Let's enable Nx Agents -```yaml {% fileName=".github/workflows/ci.yml" highlightLines=["9-21"] %} -name: CI -on: - push: - branches: - - main - pull_request: - -jobs: - main: - name: Nx Cloud - Main Job - uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.13.0 - with: - number-of-agents: 3 - parallel-commands-on-agents: | - npx nx affected -t lint,test,build,e2e --parallel=2 - - agents: - name: Nx Cloud - Agents - uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.13.0 - with: - number-of-agents: 3 +```shell +pnpm exec nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" ``` -This workflow runs all the affected tasks on 3 agents, with 2 tasks running in parallel on each agent. +We recommend you add this line right after you check out the repo, before installing node modules. + +- `nx-cloud start-ci-run --distribute-on="3 linux-medium-j` lets Nx know that all the tasks after this line should using Nx Agents and that Nx Cloud should use 3 instances of the `linux-medium-js` launch template. See below on how to configure a custom launch template. +- `--stop-agents-after="e2e-ci"` lets Nx Cloud know which line is the last command in this pipeline. Once there are no more e2e tasks for an agent to run, Nx Cloud will automatically shut them down. This way you're not wasting money on idle agents while a particularly long e2e task is running on a single agent. Try it out by creating a new PR with the above changes. @@ -415,16 +415,63 @@ Once GitHub Actions starts, you should see multiple agents running in parallel: ![GitHub Actions showing multiple DTE agents](/nx-cloud/tutorial/gh-dte-multiple-agents.png) -If you open your Nx Cloud dashboard, you'll get a better view of the individual tasks and their corresponding logs. +With this pipeline configuration in place, no matter how large the repository scales, Nx Cloud will adjust and distribute tasks across agents in the optimal way. If CI pipelines start to slow down, just add some agents. One of the main advantages is that this pipeline definition is declarative. We tell Nx what commands to run, but not how to distribute them. That way even if our monorepo structure changes and evolves over time, the distribution will be taken care of by Nx Cloud. + +### Running Commands Without Distribution -![Nx Cloud run details](/nx-cloud/tutorial/nx-cloud-run-details.png) +Sometimes you want to distribute most of your commands, but run some of them in Github Actions. You can do this with the `--no-agents` flag as follows: + +```yaml {% fileName=".github/workflows/ci.yml" highlightLines=["18-21","44"] %} +name: CI +on: + push: + branches: + - main + pull_request: -With this pipeline configuration in place, no matter how large the repository scales, Nx Cloud will adjust and distribute tasks across agents in the optimal way. If CI pipelines start to slow down, just add some agents to the `number-of-agents: 3` properties. One of the main advantages is that such a pipeline definition is declarative. We just give instructions what commands to run, but not how to distribute them. As such even if our monorepo structure changes and evolves over time, the distribution will be taken care of by Nx Cloud. +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: pnpm/action-setup@v2 + with: + version: 8 + - run: | + pnpm exec nx-cloud start-ci-run \ + --distribute-on="3 linux-medium-js" \ + --stop-agents-after="e2e-ci" + - name: Restore cached npm dependencies + id: cache-dependencies-restore + uses: actions/cache/restore@v3 + with: + path: | + node_modules + ~/.cache/Cypress # needed for the Cypress binary + key: npm-dependencies-${{ hashFiles('pnpm-lock.yaml') }} + - run: pnpm install --frozen-lockfile + - name: Cache npm dependencies + id: cache-dependencies-save + uses: actions/cache/save@v3 + with: + path: | + node_modules + ~/.cache/Cypress # needed for the Cypress binary + key: ${{ steps.cache-dependencies-restore.outputs.cache-primary-key }} + - uses: nrwl/nx-set-shas@v3 + # This line is needed for nx affected to work when CI is running on a PR + - run: git branch --track main origin/main + - run: pnpm nx affected -t lint test build --parallel=3 + - run: pnpm nx affected -t e2e-ci --parallel=1 + - run: pnpm nx affected -t deploy --no-agents +``` ## Next Steps You now have a highly optimized CI configuration that will scale as your repository scales. See what else you can do with Nx Cloud. -- Set up [GitHub PR integration](/ci/recipes/source-control-integration/github) to view Nx Cloud results directly in your PR -- Choose the [security settings](/ci/concepts/cache-security) that make sense for your organization -- [Record non-Nx commands](/ci/recipes/other/record-commands) and view the results in the Nx Cloud interface +- Configure [dynamic agent allocation](/ci/features/dynamic-agents) +- Learn about [automatically splitting e2e tasks](/ci/features/split-e2e-tasks) +- Identify and re-run [flaky tasks](/ci/features/flaky-tasks) diff --git a/docs/nx-cloud/tutorial/nx-cloud-setup-pr.png b/docs/nx-cloud/tutorial/nx-cloud-setup-pr.png new file mode 100644 index 0000000000000..1a306231cd30a Binary files /dev/null and b/docs/nx-cloud/tutorial/nx-cloud-setup-pr.png differ diff --git a/docs/shared/angular-standalone-tutorial/1-code-generation.md b/docs/shared/angular-standalone-tutorial/1-code-generation.md deleted file mode 100644 index 3b76c14994999..0000000000000 --- a/docs/shared/angular-standalone-tutorial/1-code-generation.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: 'Angular Standalone Tutorial - Part 1: Code Generation' -description: In this tutorial you'll create a frontend-focused workspace with Nx. ---- - -{% callout type="check" title="Looking for Angular monorepos?" %} -This tutorial sets up a repo with a single application at the root level that breaks out its code into libraries to add structure. If you are looking for a Angular monorepo setup then check out our [Angular monorepo tutorial](/getting-started/tutorials/angular-monorepo-tutorial). -{% /callout %} - -{% youtube -src="https://www.youtube.com/embed/LYPVrWQNnEc" -title="Tutorial: Standalone Angular Application" -/%} - -{% github-repository url="https://github.com/nrwl/nx-recipes/tree/main/angular-standalone" /%} - -# Angular Standalone Tutorial - Part 1: Code Generation - -## Contents - -- [1 - Code Generation](/angular-standalone-tutorial/1-code-generation) -- [2 - Project Graph](/angular-standalone-tutorial/2-project-graph) -- [3 - Task Running](/angular-standalone-tutorial/3-task-running) -- [4 - Task Pipelines](/angular-standalone-tutorial/4-task-pipelines) -- [5 - Summary](/angular-standalone-tutorial/5-summary) - -## Creating a New Workspace - -Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses: - -```{% command="npx create-nx-workspace@latest" path="~" %} - - > NX Let's create a new workspace [https://nx.dev/getting-started/intro] - -✔ Where would you like to create your workspace? · store -✔ Which stack do you want to use? · angular -✔ Standalone project or integrated monorepo? · standalone -✔ Default stylesheet format · css -✔ Would you like to use Standalone Components in your application? · No -✔ Would you like to add routing? · Yes -✔ Do you want Nx Cloud to make your CI fast? · Yes -``` - -{% card title="Opting into Nx Cloud" description="You will also be prompted whether to add Nx Cloud to your workspace. We won't address this in this tutorial, but you can see the introduction to Nx Cloud for more details." url="/ci/intro/ci-with-nx" /%} - -Once the command completes, the file structure should look like this: - -```treeview -store/ -├── e2e/ -├── src/ -├── tools/ -├── nx.json -├── package.json -├── project.json -├── README.md -├── tsconfig.base.json -└── tsconfig.json -``` - -There are two projects that have been created for you: - -- An Angular application (`store`) with its configuration files at the root of the repo and source code in `src`. -- A project for Cypress e2e tests for our `store` application in `e2e`. - -As far as Nx is concerned, the root-level `store` app owns every file that doesn't belong to a different project. So files in the `e2e` folder belong to the `e2e` project, everything else belongs to `store`. - -{% card title="Nx Cypress Support" description="While we see the Cypress project here, we won't go deeper on Cypress in this tutorial. You can find more materials on Nx Cypress support on the @nx/cypress package page." url="/nx-api/cypress" /%} - -## Generating a component for the store - -```{% command="npx nx g @nx/angular:component shop --project=store" path="~/store" %} - -> NX Generating @nx/angular:component - -CREATE src/app/shop/shop.component.css -CREATE src/app/shop/shop.component.html -CREATE src/app/shop/shop.component.spec.ts -CREATE src/app/shop/shop.component.ts -UPDATE src/app/app.module.ts -``` - -![Nx Generator Syntax](/shared/angular-standalone-tutorial/generator-syntax.svg) - -## Generating Libraries - -To create the `cart` and `shared/ui` libraries, use the nx/angular:lib` generator: - -```{% command="npx nx g @nx/angular:library cart" path="~/store" %} - -> NX Generating @nx/angular:library - -CREATE cart/README.md -CREATE cart/tsconfig.lib.json -CREATE cart/tsconfig.spec.json -CREATE cart/src/index.ts -CREATE cart/src/lib/cart.module.ts -CREATE cart/project.json -CREATE cart/tsconfig.json -UPDATE tsconfig.base.json -CREATE cart/jest.config.ts -CREATE cart/src/test-setup.ts -CREATE cart/.eslintrc.json -``` - -```{% command="npx nx g @nx/angular:lib shared/ui --buildable" path="~/store" %} - -> NX Generating @nx/angular:library - -UPDATE jest.config.ts -CREATE jest.config.app.ts -UPDATE project.json -CREATE shared/ui/README.md -CREATE shared/ui/ng-package.json -CREATE shared/ui/package.json -CREATE shared/ui/tsconfig.lib.json -CREATE shared/ui/tsconfig.lib.prod.json -CREATE shared/ui/tsconfig.spec.json -CREATE shared/ui/src/index.ts -CREATE shared/ui/src/lib/shared-ui.module.ts -CREATE shared/ui/project.json -CREATE shared/ui/tsconfig.json -UPDATE tsconfig.base.json -CREATE shared/ui/jest.config.ts -CREATE shared/ui/src/test-setup.ts -CREATE shared/ui/.eslintrc.json -UPDATE package.json - -added 89 packages, removed 17 packages, changed 2 packages, and audited 1515 packages in 27s - -201 packages are looking for funding - run `npm fund` for details - -8 low severity vulnerabilities - -To address all issues (including breaking changes), run: - npm audit fix --force - -Run `npm audit` for details. -``` - -You should now be able to see all three projects of our design: - -- `store` in the root -- `cart` in `cart` -- `shared-ui` in `shared/ui` - -## What's Next - -- Continue to [2: Project Graph](/angular-standalone-tutorial/2-project-graph) diff --git a/docs/shared/angular-standalone-tutorial/2-project-graph.md b/docs/shared/angular-standalone-tutorial/2-project-graph.md deleted file mode 100644 index 1837ae5d39476..0000000000000 --- a/docs/shared/angular-standalone-tutorial/2-project-graph.md +++ /dev/null @@ -1,254 +0,0 @@ -# Angular Standalone Tutorial - Part 2: Project Graph - -Run the command: `npx nx graph`. A browser should open up with the following contents: - -{% graph height="450px" %} - -```json -{ - "hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59", - "projects": [ - { - "name": "cart", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "shared-ui", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "e2e", - "type": "e2e", - "data": { - "tags": [] - } - }, - { - "name": "store", - "type": "app", - "data": { - "tags": [] - } - } - ], - "dependencies": { - "cart": [], - "shared-ui": [], - "e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }], - "store": [] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false, - "exclude": [] -} -``` - -{% /graph %} - -Nx creates the graph based on the source code. The projects are not linked in this diagram because we haven't actually finished our application. Once we use the shared components in another project, Nx will create the dependency in the graph. Let's do that now. - -### Set Up the Router - -Configure the routes: - -```javascript {% fileName="src/app/app.module.ts" %} -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouterModule } from '@angular/router'; -import { SharedUiModule } from '@store/shared/ui'; - -import { AppComponent } from './app.component'; -import { NxWelcomeComponent } from './nx-welcome.component'; -import { ShopComponent } from './shop/shop.component'; - -@NgModule({ - declarations: [AppComponent, NxWelcomeComponent, ShopComponent], - imports: [ - BrowserModule, - SharedUiModule, - RouterModule.forRoot([ - { - path: 'cart', - loadChildren: () => import('@store/cart').then((m) => m.CartModule), - }, - { - path: '**', - component: ShopComponent, - }, - ]), - ], - providers: [], - bootstrap: [AppComponent], -}) -export class AppModule {} -``` - -```javascript {% fileName="src/app/app.component.html" %} - -``` - -{% callout type="note" title="Typescript Paths" %} -When a library is created, Nx adds a new Typescript path to the `tsconfig.base.json` file. The running Typescript server process inside of your editor sometimes doesn't pick up these changes and you have to restart the server to remove inline errors on your import statements. This can be done in VS Code from the command palette when viewing a typescript file (Command-Shift-P) "Typescript: Restart TS server" -{% /callout %} - -### `shared-ui` - -Run the `@nx/angular:component` generator with the command: - -```{% command="npx nx g @nx/angular:component banner --project=shared-ui --export" path="~/store" %} - -> NX Generating @nx/angular:component - -CREATE shared/ui/src/lib/banner/banner.component.css -CREATE shared/ui/src/lib/banner/banner.component.html -CREATE shared/ui/src/lib/banner/banner.component.spec.ts -CREATE shared/ui/src/lib/banner/banner.component.ts -UPDATE shared/ui/src/lib/shared-ui.module.ts -UPDATE shared/ui/src/index.ts -``` - -Then create a simple `Banner` component in the generated file: - -```javascript {% fileName="shared/ui/src/lib/banner/banner.component.ts" %} -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'store-banner', - standalone: true, - templateUrl: './banner.component.html', - styleUrls: ['./banner.component.css'], -}) -export class BannerComponent { - @Input() text = ''; -} -``` - -```javascript {% fileName="shared/ui/src/lib/banner/banner.component.html" %} -
{{ text }}
-``` - -### `cart` - -Create a cart-route component: - -```{% command="npx nx g @nx/angular:component cart-route --project=cart" path="~/store" %} - -> NX Generating @nx/angular:component - -CREATE cart/src/lib/cart-route/cart-route.component.css -CREATE cart/src/lib/cart-route/cart-route.component.html -CREATE cart/src/lib/cart-route/cart-route.component.spec.ts -CREATE cart/src/lib/cart-route/cart-route.component.ts -UPDATE cart/src/lib/cart.module.ts -``` - -Add the `Banner` component to the cart route and link back to the main page: - -```javascript {% fileName="cart/src/lib/cart.module.ts" %} -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { RouterModule } from '@angular/router'; -import { CartRouteComponent } from './cart-route/cart-route.component'; -import { SharedUiModule } from '@store/shared/ui'; - -@NgModule({ - declarations: [CartRouteComponent], - imports: [ - CommonModule, - SharedUiModule, - RouterModule.forChild([ - { - path: '', - component: CartRouteComponent, - }, - ]), - ], -}) -export class CartModule {} -``` - -```javascript {% fileName="cart/src/lib/cart-route/cart-route.component.html" %} - -Continue Shopping -``` - -### `store` - -Update the `shop` component to use the `Banner` component and link to the cart. - -```javascript {% fileName="src/app/shop/shop.component.html" %} - -View Cart -``` - -Now run `npx nx graph` again: - -{% graph height="450px" %} - -```json -{ - "hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59", - "projects": [ - { - "name": "cart", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "shared-ui", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "e2e", - "type": "e2e", - "data": { - "tags": [] - } - }, - { - "name": "store", - "type": "app", - "data": { - "tags": [] - } - } - ], - "dependencies": { - "cart": [{ "source": "cart", "target": "shared-ui", "type": "static" }], - "shared-ui": [], - "e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }], - "store": [ - { "source": "store", "target": "cart", "type": "dynamic" }, - { "source": "store", "target": "shared-ui", "type": "static" } - ] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false, - "exclude": [] -} -``` - -{% /graph %} - -Your graph now shows the dependency lines we expected. - -The Project Graph is more than just a visualization - Nx provides tooling to optimize your task-running and even automate your CI based on this graph. This will be covered in more detail in: [4: Task Pipelines](/angular-standalone-tutorial/4-task-pipelines). - -## What's Next - -- Continue to [3: Task Running](/angular-standalone-tutorial/3-task-running) diff --git a/docs/shared/angular-standalone-tutorial/3-task-running.md b/docs/shared/angular-standalone-tutorial/3-task-running.md deleted file mode 100644 index 89126ea47f712..0000000000000 --- a/docs/shared/angular-standalone-tutorial/3-task-running.md +++ /dev/null @@ -1,144 +0,0 @@ -# Angular Standalone Tutorial - 3: Task-Running - -Common tasks include: - -- Building an application -- Serving a local web server with the built project -- Running your unit tests -- Linting your code -- Running e2e tests - -When you ran your generators in Part 1, you already set up these common tasks for each project. - -## Defining Targets - -Here's the `project.json` file for your `shared-ui` project: - -```json {% fileName="shared/ui/project.json" %} -{ - "name": "shared-ui", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "shared/ui/src", - "prefix": "store", - "targets": { - "build": { - "executor": "@nx/angular:ng-packagr-lite", - "outputs": ["{workspaceRoot}/dist/{projectRoot}"], - "options": { - "project": "shared/ui/ng-package.json" - }, - "configurations": { - "production": { - "tsConfig": "shared/ui/tsconfig.lib.prod.json" - }, - "development": { - "tsConfig": "shared/ui/tsconfig.lib.json" - } - }, - "defaultConfiguration": "production" - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "shared/ui/jest.config.ts", - "passWithNoTests": true - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": ["shared/ui/**/*.ts", "shared/ui/**/*.html"] - } - } - }, - "tags": [] -} -``` - -You can see that three targets are defined here: `build`, `test` and `lint`. - -The properties inside each of these these targets is defined as follows: - -- `executor` - which Nx executor to run. The syntax here is: `:` -- `outputs` - this is an array of files that would be created by running this target. (This informs Nx on what to save - for it's caching mechanisms you'll learn about in [4 - Task Pipelines](/angular-standalone-tutorial/4-task-pipelines)) - . -- `options` - this is an object defining which executor options to use for the given target. Every Nx executor allows - for options as a way to parameterize it's functionality. - -## Running Tasks - -![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) - -Run the `test` target for your `shared-ui` project: - -```{% command="npx nx test shared-ui" path="~/store" %} - -> nx run shared-ui:test - - PASS shared-ui shared/ui/src/lib/banner/banner.component.spec.ts - BannerComponent - ✓ should create (19 ms) - -Test Suites: 1 passed, 1 total -Tests: 1 passed, 1 total -Snapshots: 0 total -Time: 1.561 s -Ran all test suites. - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target test for project shared-ui (3s) -``` - -Next, run a lint check on your `shared-ui` project: - -```{% command="npx nx lint shared-ui" path="~/store" %} - -> nx run shared-ui:lint - - -Linting "shared-ui"... - -All files pass linting. - - -——————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target lint for project shared-ui (2s) -``` - -Also, by running the `serve` target for your `store` application, you can run local web server during development that -will allow you to manually check the changes you've made: - -```{% command="npx nx serve store" path="~/store" %} - -> nx run store:serve:development - -✔ Browser application bundle generation complete. - -Initial Chunk Files | Names | Raw Size -vendor.js | vendor | 2.04 MB | -polyfills.js | polyfills | 316.06 kB | -styles.css, styles.js | styles | 211.31 kB | -main.js | main | 47.60 kB | -runtime.js | runtime | 12.61 kB | - - | Initial Total | 2.62 MB - -Lazy Chunk Files | Names | Raw Size -cart_src_index_ts.js | store-cart | 4.93 kB | - -Build at: 2023-03-24T10:13:24.014Z - Hash: e52a884fc7a311e1 - Time: 8609ms - -** Angular Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ ** - - -✔ Compiled successfully. -``` - -## What's Next - -- Continue to [4: Workspace Optimization](/angular-standalone-tutorial/4-task-pipelines) diff --git a/docs/shared/angular-standalone-tutorial/4-task-pipelines.md b/docs/shared/angular-standalone-tutorial/4-task-pipelines.md deleted file mode 100644 index 9723a5494d832..0000000000000 --- a/docs/shared/angular-standalone-tutorial/4-task-pipelines.md +++ /dev/null @@ -1,269 +0,0 @@ -# Angular Standalone Tutorial - Part 4: Task Pipelines - -## Running Dependent Tasks - -Let's build the `store` application: - -```{% command="npx nx build store" path="~/store" %} - - ✔ 1/1 dependent project tasks succeeded [0 read from cache] - - Hint: you can run the command with --verbose to see the full dependent project outputs - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - -> nx run store:build:production - -✔ Browser application bundle generation complete. -✔ Copying assets complete. -✔ Index html generation complete. - -Initial Chunk Files | Names | Raw Size | Estimated Transfer Size -main.dc68f58360ec52f7.js | main | 203.69 kB | 55.81 kB -polyfills.19459ef8805e51da.js | polyfills | 33.04 kB | 10.64 kB -runtime.639feb9584ec9047.js | runtime | 2.62 kB | 1.23 kB -styles.ef46db3751d8e999.css | styles | 0 bytes | - - - | Initial Total | 239.35 kB | 67.68 kB - -Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size -967.25ab9a0a8950995f.js | store-cart | 719 bytes | 395 bytes - -Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project store and 1 task(s) they depend on (9s) - -``` - -Notice this line: - -```shell - ✔ 1/1 dependent project tasks succeeded [0 read from cache] -``` - -When you run a task, Nx will run all the task's dependencies before running the task you specified. This ensures all the needed artifacts are in place before the task is run. - -## Configuring Task Pipelines - -Nx can infer how projects depend on each other by examining the source code, but Nx doesn't know which tasks depend on each other. - -In the `nx.json` file you can see the default set up: - -```json -{ - "targetDefaults": { - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"] - } - } -} -``` - -The `"dependsOn": ["^build"]` line says that every `build` task depends on the `build` tasks for its project dependencies. You can override the `dependsOn` setting for individual projects in the `project.json` files. - -{% card title="More On The Task Pipeline Configuration" description="See the Task Pipeline Configuration Guide for more details on how to configure your Task Graph." url="/concepts/task-pipeline-configuration" /%} - -## Skip Repeated Tasks - -Why does Nx always run the dependent tasks? Doesn't that waste time repeating the same work? - -It would, if Nx didn't have a robust caching mechanism to take care of that problem for you. Let's build the `store` app again. - -```{% command="npx nx build store" path="~/store" %} - - ✔ 1/1 dependent project tasks succeeded [1 read from cache] - - Hint: you can run the command with --verbose to see the full dependent project outputs - - ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - -> nx run store:build:production [existing outputs match the cache, left as is] - - -Initial Chunk Files | Names | Raw Size | Estimated Transfer Size -main.dc68f58360ec52f7.js | main | 203.69 kB | 55.81 kB -polyfills.19459ef8805e51da.js | polyfills | 33.04 kB | 10.64 kB -runtime.639feb9584ec9047.js | runtime | 2.62 kB | 1.23 kB -styles.ef46db3751d8e999.css | styles | 0 bytes | - - - | Initial Total | 239.35 kB | 67.68 kB - -Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size -967.25ab9a0a8950995f.js | store-cart | 719 bytes | 395 bytes - -Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms - - ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project store and 1 task(s) they depend on (13ms) - - Nx read the output from the cache instead of running the command for 2 out of 2 tasks. -``` - -This time the build only took 13 ms. Also, if you delete the `dist` folder and run the command again, the build output will be recreated. - -{% card title="More Task Caching Details" description="See the documentation for more information on caching." url="/core-features/cache-task-results" /%} - -## Cache Inputs and Outputs - -How does Nx know when to replace a cached task result? And how does Nx know what should be cached? - -Nx determines if a project has been modified by looking at the task's defined `inputs`. And then when the task is completed, it caches the terminal output and all the defined file `outputs`. - -### Inputs - -When you run a task, Nx uses the inputs for your task to create a hash that is used as an index for the task results. If the task has already been run with the same inputs, Nx replays the results stored in the cache. - -If this index does not exist, Nx runs the command and if the command succeeds, it stores the result in the cache. - -{% card title="More On Customizing Inputs" description="See the Customizing Inputs Guide for more details on how to set inputs for your tasks." url="/recipes/running-tasks/customizing-inputs" /%} - -### Outputs - -Outputs of the cache include the terminal output created by the task, as well as any files created by the task - for example: the artifact created by running a `build` task. - -Here are the outputs defined for the `shared-ui` project: - -```json {% fileName="shared/ui/project.json" %} -{ - "name": "shared-ui", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "projectType": "library", - "sourceRoot": "shared/ui/src", - "prefix": "store", - "targets": { - "build": { - "executor": "@nx/angular:ng-packagr-lite", - "outputs": ["{workspaceRoot}/dist/{projectRoot}"], - "options": { - "project": "shared/ui/ng-package.json" - }, - "configurations": { - "production": { - "tsConfig": "shared/ui/tsconfig.lib.prod.json" - }, - "development": { - "tsConfig": "shared/ui/tsconfig.lib.json" - } - }, - "defaultConfiguration": "production" - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "shared/ui/jest.config.ts", - "passWithNoTests": true - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "options": { - "lintFilePatterns": ["shared/ui/**/*.ts", "shared/ui/**/*.html"] - } - } - }, - "tags": [] -} -``` - -Outputs are stored in the cache so that terminal output can be replayed, and any created files can be pulled from your cache, and placed where they were created the original time the task was run. - -## Testing Affected Projects - -Another way that Nx saves you from unnecessary work is the `affected` command. `affected` is a mechanism that relies on your git metadata to determine the projects in your workspace that were affected by a given commit. - -Run the command: - -```shell -git add . ; git commit -m "commiting to test affected" -``` - -Then make a change to the styles of your `cart` project: - -```css {% fileName="cart/src/lib/cart-route/cart-route.component.css" %} -a { - color: blue; -} -``` - -You can visualize how our workspace is affected by this change using the command: - -```shell -npx nx affected:graph -``` - -{% graph height="450px" %} - -```json -{ - "hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59", - "projects": [ - { - "name": "cart", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "shared-ui", - "type": "lib", - "data": { - "tags": [] - } - }, - { - "name": "e2e", - "type": "e2e", - "data": { - "tags": [] - } - }, - { - "name": "store", - "type": "app", - "data": { - "tags": [] - } - } - ], - "dependencies": { - "cart": [{ "source": "cart", "target": "shared-ui", "type": "static" }], - "shared-ui": [], - "e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }], - "store": [ - { "source": "store", "target": "cart", "type": "dynamic" }, - { "source": "store", "target": "shared-ui", "type": "static" } - ] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": ["cart", "store", "e2e"], - "focus": null, - "groupByFolder": false, - "exclude": [] -} -``` - -{% /graph %} - -The change made to the `cart` project is also affecting the `store` project. This can be leveraged to run tasks only on the projects that were affected by this commit. - -To run the `test` targets only for affected projects, run the command: - -```shell -npx nx affected -t test -``` - -This can be particularly helpful in CI pipelines for larger repos, where most commits only affect a small subset of the entire workspace. - -{% card title="Affected Documentation" description="Checkout Affected documentation for more details" url="/nx-api/nx/documents/affected" /%} - -## What's Next - -- Continue to [5: Summary](/angular-standalone-tutorial/5-summary) diff --git a/docs/shared/angular-standalone-tutorial/5-summary.md b/docs/shared/angular-standalone-tutorial/5-summary.md deleted file mode 100644 index cdc8b6d3591a8..0000000000000 --- a/docs/shared/angular-standalone-tutorial/5-summary.md +++ /dev/null @@ -1,22 +0,0 @@ -# Angular Standalone Tutorial - Part 5: Summary - -In this tutorial you: - -- Learned how to use Nx's Generators to generate code for your workspace. -- Learned how Nx determines a graph of your workspace -- Learned how to configure and run tasks in your workspace -- Learned how Nx's built-in optimizations work, and how to apply those to your own workspace - -## Learn More - -{% cards %} - -{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%} - -{% card title="Plugin Features" description="Read about the plugin features of Nx." url="/core-features/plugin-features" /%} - -{% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%} - -{% card title="Adopting Nx" description="Learn how to add Nx to your existing repo." url="/recipes/adopting-nx" /%} - -{% /cards %} diff --git a/docs/shared/angular-standalone-tutorial/angular-standalone.md b/docs/shared/angular-standalone-tutorial/angular-standalone.md index f12938b218b10..774609e23bbbb 100644 --- a/docs/shared/angular-standalone-tutorial/angular-standalone.md +++ b/docs/shared/angular-standalone-tutorial/angular-standalone.md @@ -40,13 +40,13 @@ Create a new Angular application with the following command: ✔ Default stylesheet format · css ✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? · No ✔ Test runner to use for end to end (E2E) tests · cypress -✔ Do you want Nx Cloud to make your CI fast? · Yes +✔ Set up CI with caching, distribution and test deflaking · github ``` You get asked a few questions that help Nx preconfigure your new Angular application. These include - Angular specific questions, such as which bundler to use, whether to enable server-side rendering and which stylesheet format to use -- General Nx questions, such as whether to enable remote caching with Nx Cloud. Nx comes with built-in [local caching](/core-features/cache-task-results). If you want to benefit from this cache in CI, you can enable [remote caching](/ci/features/remote-cache) which will set up [Nx Cloud](https://nx.app). This is also a prerequisite for enabling [distributed task execution](/ci/features/distribute-task-execution). +- General Nx questions, such as whether to enable remote caching with Nx Cloud. Nx comes with built-in [local caching](/features/cache-task-results). If you want to benefit from this cache in CI, you can enable [remote caching](/ci/features/remote-cache) which will set up [Nx Cloud](https://nx.app). This is also a prerequisite for enabling [distributed task execution](/ci/features/distribute-task-execution). For the sake of this tutorial, let's respond to all the questions with the default response. @@ -104,7 +104,7 @@ Compared to the Angular CLI, you might notice the addition of an `nx.json` file | File | Description | | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `nx.json` | This is where we can fine-tune how Nx works, define the [cacheable operations](/core-features/cache-task-results), our [task pipelines](/concepts/task-pipeline-configuration) as well as defaults for the Nx generators. Find more details in [the reference docs](/reference/nx-json). | +| `nx.json` | This is where we can fine-tune how Nx works, define the [cacheable operations](/features/cache-task-results), our [task pipelines](/concepts/task-pipeline-configuration) as well as defaults for the Nx generators. Find more details in [the reference docs](/reference/nx-json). | | `project.json` | Nx uses this file to define targets that can be run, similar to how the Angular CLI uses the `angular.json` file. If you're familiar with the Angular CLI you should have no difficulty navigating the `project.json` file. If you're curious how the two compare, you can learn more in [the Nx and Angular CLI comparision article](/concepts/more-concepts/nx-and-angular). The [project-configuration documentation page](/reference/project-configuration) has more details on how to use the `project.json` file. | ## Serving the App @@ -137,7 +137,276 @@ Nx uses the following syntax to run tasks: ![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) -All targets, such as `serve`, `build`, `test` or your custom ones, are defined in the `project.json` file. +### Inferred Tasks + +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/features/integrate-with-editors) project detail view or run: + +```shell +nx show project myngapp --web +``` + +{% project-details title="Project Details View" height="100px" %} + +```json +{ + "project": { + "name": "myngapp", + "data": { + "root": ".", + "includedScripts": [], + "name": "myngapp", + "targets": { + "lint": { + "cache": true, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.json", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "options": { + "cwd": ".", + "command": "eslint ./src" + }, + "configurations": {} + }, + "test": { + "options": { + "cwd": ".", + "command": "jest" + }, + "cache": true, + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["jest"] + } + ], + "outputs": ["{projectRoot}/coverage/myngapp"], + "executor": "nx:run-commands", + "configurations": {} + }, + "build": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"], + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/myngapp", + "index": "./src/index.html", + "browser": "./src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "./tsconfig.app.json", + "assets": ["./src/favicon.ico", "./src/assets"], + "styles": ["./src/styles.css"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "myngapp:build:production" + }, + "development": { + "buildTarget": "myngapp:build:development" + } + }, + "defaultConfiguration": "development", + "options": {} + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "myngapp:build" + }, + "configurations": {} + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "myngapp:build", + "staticFilePath": "dist/myngapp/browser" + }, + "configurations": {} + } + }, + "sourceRoot": "./src", + "projectType": "application", + "$schema": "node_modules/nx/schemas/project-schema.json", + "prefix": "myngapp", + "tags": [], + "implicitDependencies": [] + } + }, + "sourceMap": { + "root": ["project.json", "nx/core/project-json"], + "includedScripts": ["package.json", "nx/core/package-json-workspaces"], + "name": ["project.json", "nx/core/project-json"], + "targets": ["project.json", "nx/core/project-json"], + "targets.lint": ["project.json", "@nx/eslint/plugin"], + "targets.lint.cache": ["project.json", "@nx/eslint/plugin"], + "targets.lint.options": ["project.json", "@nx/eslint/plugin"], + "targets.lint.inputs": ["project.json", "@nx/eslint/plugin"], + "targets.lint.executor": ["project.json", "@nx/eslint/plugin"], + "targets.lint.options.cwd": ["project.json", "@nx/eslint/plugin"], + "targets.lint.options.command": ["project.json", "@nx/eslint/plugin"], + "targets.test": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.options": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.cache": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.inputs": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.outputs": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.executor": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.options.cwd": ["jest.config.ts", "@nx/jest/plugin"], + "targets.test.options.command": ["jest.config.ts", "@nx/jest/plugin"], + "targets.build": ["project.json", "nx/core/project-json"], + "targets.build.cache": ["project.json", "nx/core/target-defaults"], + "targets.build.dependsOn": ["project.json", "nx/core/target-defaults"], + "targets.build.inputs": ["project.json", "nx/core/target-defaults"], + "sourceRoot": ["project.json", "nx/core/project-json"], + "projectType": ["project.json", "nx/core/project-json"], + "$schema": ["project.json", "nx/core/project-json"], + "prefix": ["project.json", "nx/core/project-json"], + "tags": ["project.json", "nx/core/project-json"], + "targets.build.executor": ["project.json", "nx/core/project-json"], + "targets.build.outputs": ["project.json", "nx/core/project-json"], + "targets.build.options": ["project.json", "nx/core/project-json"], + "targets.build.configurations": ["project.json", "nx/core/project-json"], + "targets.build.defaultConfiguration": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.options.outputPath": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.options.index": ["project.json", "nx/core/project-json"], + "targets.build.options.browser": ["project.json", "nx/core/project-json"], + "targets.build.options.polyfills": ["project.json", "nx/core/project-json"], + "targets.build.options.tsConfig": ["project.json", "nx/core/project-json"], + "targets.build.options.assets": ["project.json", "nx/core/project-json"], + "targets.build.options.styles": ["project.json", "nx/core/project-json"], + "targets.build.options.scripts": ["project.json", "nx/core/project-json"], + "targets.build.configurations.production": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.production.budgets": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.production.outputHashing": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.optimization": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.extractLicenses": [ + "project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.sourceMap": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve": ["project.json", "nx/core/project-json"], + "targets.serve.executor": ["project.json", "nx/core/project-json"], + "targets.serve.configurations": ["project.json", "nx/core/project-json"], + "targets.serve.defaultConfiguration": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.production": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.production.buildTarget": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.development": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.development.buildTarget": [ + "project.json", + "nx/core/project-json" + ], + "targets.extract-i18n": ["project.json", "nx/core/project-json"], + "targets.extract-i18n.executor": ["project.json", "nx/core/project-json"], + "targets.extract-i18n.options": ["project.json", "nx/core/project-json"], + "targets.extract-i18n.options.buildTarget": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve-static": ["project.json", "nx/core/project-json"], + "targets.serve-static.executor": ["project.json", "nx/core/project-json"], + "targets.serve-static.options": ["project.json", "nx/core/project-json"], + "targets.serve-static.options.buildTarget": [ + "project.json", + "nx/core/project-json" + ], + "targets.serve-static.options.staticFilePath": [ + "project.json", + "nx/core/project-json" + ] + } +} +``` + +{% /project-details %} + +If you expand the `test` task, you can see that it was created by the `@nx/jest` plugin by analyzing your `jest.config.ts` file. Notice the outputs are defined as `{projectRoot}/coverage/myngapp`. This value is being read from the `coverageDirectory` defined in your `jest.config.ts` file. Let's change that value in your `jest.config.ts` file: + +```ts {% fileName="jest.config.ts" %} +export default { + // ... + coverageDirectory: './coverage/myngapp-changed', + // ... +}; +``` + +Now if you look at the project details view, the outputs for the `test` target will say `{projectRoot}/coverage/angular-store-changed`. This feature ensures that Nx will always cache the correct files. + +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. + +### Manually Defined Tasks + +The `serve` and `build` tasks are defined in the `project.json` file. ```json {% fileName="project.json"} { @@ -183,7 +452,7 @@ The most critical parts are: - `executor` - This corresponds to the `builder` property in an Angular CLI workspace. You can use Angular builders or executors from [Nx plugins](/extending-nx/intro/getting-started). - `options` - these are additional properties and flags passed to the executor function to customize it -Learn more about how to [run tasks with Nx](/core-features/run-tasks). +Learn more about how to [run tasks with Nx](/features/run-tasks). ## Testing and Linting - Running Multiple Tasks @@ -215,7 +484,7 @@ More conveniently, we can also run them in parallel using the following syntax: {% video-link link="https://youtu.be/ZAO0yXupIIE?t=443" /%} -One thing to highlight is that Nx is able to [cache the tasks you run](/core-features/cache-task-results). +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. @@ -233,7 +502,7 @@ Note that all of these targets are automatically cached by Nx. If you re-run a s Nx read the output from the cache instead of running the command for 4 out of 4 tasks. ``` -Not all tasks might be cacheable though. You can configure the `cache` properties in the targets under `targetDefaults` in the `nx.json` file. You can also [learn more about how caching works](/core-features/cache-task-results). +Not all tasks might be cacheable though. You can configure the `cache` properties in the targets under `targetDefaults` in the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). ## Creating New Components @@ -289,7 +558,7 @@ Generators allow you to easily scaffold code, configuration or entire projects. If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. -More info can be found in [the integrate with editors article](/core-features/integrate-with-editors). +More info can be found in [the integrate with editors article](/features/integrate-with-editors). {% /callout %} @@ -499,7 +768,7 @@ import { CommonModule } from '@angular/common'; standalone: true, imports: [CommonModule], templateUrl: './products.component.html', - styleUrls: ['./products.component.css'], + styleUrl: './products.component.css', }) export class ProductsComponent {} ``` @@ -578,7 +847,7 @@ A couple of notes: {% video-link link="https://youtu.be/ZAO0yXupIIE?t=958" /%} -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/core-features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/core-features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: @@ -812,7 +1081,7 @@ If you have the ESLint plugin installed in your IDE you should immediately see a ![ESLint module boundary error](/shared/images/tutorial-angular-standalone/boundary-rule-violation-vscode.png) -Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries). +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Migrating to a Monorepo @@ -829,7 +1098,7 @@ Here's some more things you can dive into next: - Learn more about the [underlying mental model of Nx](/concepts/mental-model) - Learn about popular generators such as [how to setup Tailwind](/recipes/angular/using-tailwind-css-with-angular-projects) or [add Storybook to your UI library](/recipes/storybook/overview-angular) - Learn how to [migrate your existing Angular CLI repo to Nx](/recipes/angular/migration/angular) -- [Speed up CI: Run only tasks for project that got changed](/core-features/run-tasks#run-tasks-affected-by-a-pr) +- [Speed up CI: Run only tasks for project that got changed](/features/run-tasks#run-tasks-affected-by-a-pr) - [Speed up CI: Share your cache](/ci/features/remote-cache) - [Speed up CI: Distribute your tasks across machines](/ci/features/distribute-task-execution) diff --git a/docs/shared/angular-tutorial/angular-monorepo.md b/docs/shared/angular-tutorial/angular-monorepo.md index f3f0461111cca..dcdf99f61dc1e 100644 --- a/docs/shared/angular-tutorial/angular-monorepo.md +++ b/docs/shared/angular-tutorial/angular-monorepo.md @@ -24,7 +24,7 @@ Nx evolved from being an extension of the Angular CLI to a [fully standalone CLI Advantages of Nx over the Angular CLI: -- [Cache any target](/core-features/cache-task-results) +- [Cache any target](/features/cache-task-results) - [Run only tasks affected by a code change](/ci/features/affected) - [Split a large angular.json into multiple project.json files](/concepts/more-concepts/nx-and-angular#projectjson-vs-angularjson) - [Integrate with modern tools](/concepts/more-concepts/nx-and-angular#integrating-with-modern-tools) @@ -125,7 +125,389 @@ Nx uses the following syntax to run tasks: ![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) -All targets, such as `serve`, `build`, `test` or your custom ones, are defined in the `project.json` file. +### Inferred Tasks + +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/features/integrate-with-editors) project detail view or run: + +```shell +nx show project angular-store --web +``` + +{% project-details title="Project Details View" height="100px" %} + +```json +{ + "project": { + "name": "angular-store", + "data": { + "root": "apps/angular-store", + "targets": { + "lint": { + "cache": true, + "options": { + "cwd": "apps/angular-store", + "command": "eslint ." + }, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.json", + "{workspaceRoot}/apps/angular-store/.eslintrc.json", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "configurations": {} + }, + "test": { + "options": { + "cwd": "apps/angular-store", + "command": "jest" + }, + "cache": true, + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["jest"] + } + ], + "outputs": ["{workspaceRoot}/coverage/apps/angular-store"], + "executor": "nx:run-commands", + "configurations": {} + }, + "build": { + "cache": true, + "dependsOn": ["^build"], + "inputs": ["production", "^production"], + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/angular-store", + "index": "apps/angular-store/src/index.html", + "browser": "apps/angular-store/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/angular-store/tsconfig.app.json", + "assets": [ + "apps/angular-store/src/favicon.ico", + "apps/angular-store/src/assets" + ], + "styles": ["apps/angular-store/src/styles.css"], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "angular-store:build:production" + }, + "development": { + "buildTarget": "angular-store:build:development" + } + }, + "defaultConfiguration": "development", + "options": {} + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "angular-store:build" + }, + "configurations": {} + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "angular-store:build", + "staticFilePath": "dist/apps/angular-store/browser" + }, + "configurations": {} + } + }, + "name": "angular-store", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "angular-monorepo", + "sourceRoot": "apps/angular-store/src", + "tags": [], + "implicitDependencies": [] + } + }, + "sourceMap": { + "root": ["apps/angular-store/project.json", "nx/core/project-json"], + "targets": ["apps/angular-store/project.json", "nx/core/project-json"], + "targets.lint": ["apps/angular-store/project.json", "@nx/eslint/plugin"], + "targets.lint.cache": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.options": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.inputs": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.executor": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.options.cwd": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.options.command": [ + "apps/angular-store/project.json", + "@nx/eslint/plugin" + ], + "targets.test": ["apps/angular-store/jest.config.ts", "@nx/jest/plugin"], + "targets.test.options": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.cache": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.inputs": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.outputs": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.executor": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.options.cwd": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.test.options.command": [ + "apps/angular-store/jest.config.ts", + "@nx/jest/plugin" + ], + "targets.build": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.cache": [ + "apps/angular-store/project.json", + "nx/core/target-defaults" + ], + "targets.build.dependsOn": [ + "apps/angular-store/project.json", + "nx/core/target-defaults" + ], + "targets.build.inputs": [ + "apps/angular-store/project.json", + "nx/core/target-defaults" + ], + "name": ["apps/angular-store/project.json", "nx/core/project-json"], + "$schema": ["apps/angular-store/project.json", "nx/core/project-json"], + "projectType": ["apps/angular-store/project.json", "nx/core/project-json"], + "prefix": ["apps/angular-store/project.json", "nx/core/project-json"], + "sourceRoot": ["apps/angular-store/project.json", "nx/core/project-json"], + "tags": ["apps/angular-store/project.json", "nx/core/project-json"], + "targets.build.executor": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.outputs": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.defaultConfiguration": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.outputPath": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.index": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.browser": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.polyfills": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.tsConfig": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.assets": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.styles": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.options.scripts": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.production": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.production.budgets": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.production.outputHashing": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.optimization": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.extractLicenses": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.build.configurations.development.sourceMap": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.executor": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.configurations": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.defaultConfiguration": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.production": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.production.buildTarget": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.development": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve.configurations.development.buildTarget": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.extract-i18n": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.extract-i18n.executor": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.extract-i18n.options": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.extract-i18n.options.buildTarget": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve-static": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve-static.executor": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve-static.options": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve-static.options.buildTarget": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ], + "targets.serve-static.options.staticFilePath": [ + "apps/angular-store/project.json", + "nx/core/project-json" + ] + } +} +``` + +{% /project-details %} + +If you expand the `test` task, you can see that it was created by the `@nx/jest` plugin by analyzing your `jest.config.ts` file. Notice the outputs are defined as `{workspaceRoot}/coverage/apps/angular-store`. This value is being read from the `coverageDirectory` defined in your `jest.config.ts` file. Let's change that value in your `jest.config.ts` file: + +```ts {% fileName="apps/angular-store/jest.config.ts" %} +export default { + // ... + coverageDirectory: '../../coverage/apps/angular-store-changed', + // ... +}; +``` + +Now if you look at the project details view, the outputs for the `test` target will say `{workspaceRoot}/coverage/apps/angular-store-changed`. This feature ensures that Nx will always cache the correct files. + +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. + +### Manually Defined Tasks + +The `serve` and `build` tasks are defined in the `project.json` file. ```json {% fileName="apps/angular-store/project.json"} { @@ -135,8 +517,6 @@ All targets, such as `serve`, `build`, `test` or your custom ones, are defined i "build": { ... }, "serve": { ... }, "extract-i18n": { ... }, - "lint": { ... }, - "test": { ... }, "serve-static": { ... }, }, } @@ -176,13 +556,13 @@ The most critical parts are: - `executor` - this is of the syntax `:`, where the `plugin` is an NPM package containing an [Nx Plugin](/extending-nx/intro/getting-started) and `` points to a function that runs the task. - `options` - these are additional properties and flags passed to the executor function to customize it -Learn more about how to [run tasks with Nx](/core-features/run-tasks). We'll [revisit running tasks](#testing-and-linting-running-multiple-tasks) later in this tutorial. +Learn more about how to [run tasks with Nx](/features/run-tasks). We'll [revisit running tasks](#testing-and-linting-running-multiple-tasks) later in this tutorial. ## Adding Another Application -Nx plugins usually provide [generators](/core-features/plugin-features/use-code-generators) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/angular` plugin provides, run the following command and inspect the output: +Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/angular` plugin provides, run the following command and inspect the output: ```{% command="npx nx list @nx/angular" path="angular-monorepo" %} @@ -221,7 +601,7 @@ This executor is similar to the `@angular-devkit/build-angular:ng-packagr` with If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. -More info can be found in [the integrate with editors article](/core-features/integrate-with-editors). +More info can be found in [the integrate with editors article](/features/integrate-with-editors). {% /callout %} @@ -385,7 +765,7 @@ All libraries that we generate automatically have aliases created in the root-le Hence we can easily import them into other libraries and our Angular application. As an example, let's create and expose a `ProductListComponent` component from our `libs/products` library. Either create it by hand or run ```shell -nx g @nx/angular:component product-list --directory=libs/products/src/lib/product-list --nameAndDirectoryFormat=as-provided --standalone --export +nx g @nx/angular:component product-list --directory=libs/products/src/lib/product-list --standalone --export ``` We don't need to implement anything fancy as we just want to learn how to import it into our main Angular application. @@ -503,7 +883,7 @@ export class AppComponent { -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/core-features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/core-features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: @@ -624,7 +1004,7 @@ nx run-many -t test lint e2e ### Caching -One thing to highlight is that Nx is able to [cache the tasks you run](/core-features/cache-task-results). +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. @@ -642,7 +1022,7 @@ Note that all of these targets are automatically cached by Nx. If you re-run a s Nx read the output from the cache instead of running the command for 10 out of 10 tasks. ``` -Not all tasks might be cacheable though. You can configure `cacheableOperations` in the `nx.json` file. You can also [learn more about how caching works](/core-features/cache-task-results). +Not all tasks might be cacheable though. You can configure `cacheableOperations` in the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). ### Testing Affected Projects @@ -835,7 +1215,7 @@ Nx comes with a generic mechanism that allows you to assign "tags" to projects. ```json {% fileName="libs/orders/project.json" %} { ... - "tags": ["type:feature", "scope:orders"] + "tags": ["type:feature", "scope:orders"], } ``` @@ -844,7 +1224,7 @@ Then go to the `project.json` of your `products` library and assign the tags `ty ```json {% fileName="libs/products/project.json" %} { ... - "tags": ["type:feature", "scope:products"] + "tags": ["type:feature", "scope:products"], } ``` @@ -853,7 +1233,7 @@ Finally, go to the `project.json` of the `shared-ui` library and assign the tags ```json {% fileName="libs/shared/ui/project.json" %} { ... - "tags": ["type:ui", "scope:shared"] + "tags": ["type:ui", "scope:shared"], } ``` @@ -977,7 +1357,7 @@ If you have the ESLint plugin installed in your IDE you should immediately see a ![ESLint module boundary error](/shared/angular-tutorial/module-boundary-lint-rule.png) -Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries). +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Setting Up CI @@ -1012,7 +1392,7 @@ Here's some more things you can dive into next: - Learn about popular generators such as [how to setup Tailwind](/recipes/angular/using-tailwind-css-with-angular-projects) - Learn how to [migrate your existing Angular CLI repo to Nx](/recipes/angular/migration/angular) - [Setup Storybook for our shared UI library](/recipes/storybook/overview-angular) -- [Speed up CI: Run only tasks for project that got changed](/core-features/run-tasks#run-tasks-affected-by-a-pr) +- [Speed up CI: Run only tasks for project that got changed](/features/run-tasks#run-tasks-affected-by-a-pr) - [Speed up CI: Share your cache](/ci/features/remote-cache) - [Speed up CI: Distribute your tasks across machines](/ci/features/distribute-task-execution) diff --git a/docs/shared/concepts/how-caching-works.md b/docs/shared/concepts/how-caching-works.md index d44933239b3d3..8e10bda175895 100644 --- a/docs/shared/concepts/how-caching-works.md +++ b/docs/shared/concepts/how-caching-works.md @@ -1,6 +1,6 @@ # How Caching Works -Before running any task, Nx computes its computation hash. As long as the computation hash is the same, the output of +Before running any cacheable task, Nx computes its computation hash. As long as the computation hash is the same, the output of running the task is the same. By default, the computation hash for something like `nx test remixapp` includes: @@ -40,13 +40,25 @@ As your workspace grows, the task graph looks more like this: All of these optimizations are crucial for making Nx usable for any non-trivial workspace. Only the minimum amount of work happens. The rest is either left as is or restored from the cache. +## Fine-tuning Nx's Cache + +Each cacheable task defines a set of inputs and outputs. Inputs are factors Nx considers when calculating the computation hash. +Outputs are files that will be cached and restored when the computation hash matches. +For more information on how to fine-tune caching, see the [Fine-tuning Caching with Inputs recipe](/recipes/running-tasks/configure-inputs). + +### Inputs + +Inputs are factors Nx considers when calculating the computation hash for a task. + +For more information on the different types of inputs and how to configure inputs for your tasks, read the [Fine-tuning Caching with Inputs recipe](/recipes/running-tasks/configure-inputs) + ## What is Cached Nx works on the process level. Regardless of the tools used to build/test/lint/etc.. your project, the results are cached. -It sets up hooks to collect stdout/stderr before running the command. All the output is cached and then replayed during a cache hit. +It collects terminal output when running tasks. All the terminal output is cached and then replayed during a cache hit. -Nx also caches the files generated by a command. The list of files/folders is listed in the `outputs` property of the project's `package.json` or `project.json`: +Nx can also cache the files generated by a task. The list of files/folders is listed in the `outputs` property of the project's `package.json` or `project.json`: {% tabs %} {% tab label="package.json" %} @@ -162,7 +174,7 @@ Inputs may include - runtime inputs - command line arguments -Learn more about fine tuning caching in the [Fine-tuning Caching with Inputs page](/recipes/running-tasks/customizing-inputs). +Learn more about fine tuning caching in the [Fine-tuning Caching with Inputs page](/recipes/running-tasks/configure-inputs). ## Args Hash Inputs @@ -199,4 +211,4 @@ npx nx build footer Learn more about how to configure caching, where the cache is stored, how to reset it and more. -- [Cache Task Results](/core-features/cache-task-results) +- [Cache Task Results](/features/cache-task-results) diff --git a/docs/shared/concepts/illustrated-dte-guide.md b/docs/shared/concepts/illustrated-dte-guide.md index 5363a90767781..a1d5d1374ebc1 100644 --- a/docs/shared/concepts/illustrated-dte-guide.md +++ b/docs/shared/concepts/illustrated-dte-guide.md @@ -8,7 +8,7 @@ The illustrations in this guide are created by Nrwlian [Nicole Oliver](https://t ![what's a task? project + target (i.e. shared-product-ui + test). each run contains many tasks. affected:test contains shared-product-ui:test, product-page:test, shared-e2e-util:test and shared-ui:test](/shared/images/dte/whats-a-task.jpeg) -A task, from Nx's perspective, is a target running on a project. i.e. The target `test` running on the project `shared-product-ui` is a task. For more information about tasks, see the [Run Tasks article](/core-features/run-tasks). +A task, from Nx's perspective, is a target running on a project. i.e. The target `test` running on the project `shared-product-ui` is a task. For more information about tasks, see the [Run Tasks article](/features/run-tasks). ## Nx Cloud Schedules Your CI Tasks Automatically @@ -28,7 +28,7 @@ When you set up DTE, you define (1) the tasks that you want to run and (2) the n ![but don't some tasks depend on others' results? Yep! Nx knows about your dependency tree, so it will execute tasks in the right order and make sure the results are available where they're needed.](/shared/images/dte/task-dependencies.jpeg) -There are some tasks that need to be executed before other tasks, but Nx Cloud takes that into account when it assigns tasks to agents. For a more detailed look at defining those dependencies, read the [Run Tasks article](/core-features/run-tasks). +There are some tasks that need to be executed before other tasks, but Nx Cloud takes that into account when it assigns tasks to agents. For a more detailed look at defining those dependencies, read the [Run Tasks article](/features/run-tasks). ## Why Distribute Tasks? diff --git a/docs/shared/concepts/inferred-target-config.png b/docs/shared/concepts/inferred-target-config.png new file mode 100644 index 0000000000000..715ab62b55b71 Binary files /dev/null and b/docs/shared/concepts/inferred-target-config.png differ diff --git a/docs/shared/concepts/inferred-tasks.md b/docs/shared/concepts/inferred-tasks.md new file mode 100644 index 0000000000000..98135d3080dfe --- /dev/null +++ b/docs/shared/concepts/inferred-tasks.md @@ -0,0 +1,67 @@ +# Inferred Tasks + +In Nx version 18, many Nx plugins will automatically infer tasks for your projects based on the configuration of different tools. Many tools have configuration files which determine what a tool does. Nx is able to cache the results of running the tool. Nx plugins use the same configuration files to infer how Nx should [run the task](/features/run-tasks). This includes [fine-tuned cache settings](/features/cache-task-results) and automatic [task dependencies](/concepts/task-pipeline-configuration). + +For example, the `@nx/webpack` plugin infers tasks to run webpack through Nx based on your repository's webpack configuration. This configuration already defines the destination of your build files, so Nx reads that value and caches the correct output files. + +## How Does a Plugin Infer Tasks? + +Every plugin has its own custom logic, but in order to infer tasks, they all go through the following steps. + +### 1. Detect Tooling Configuration in Workspace + +The plugin will search the workspace for configuration files of the tool. For each configuration file found, the plugin will infer tasks. i.e. The `@nx/webpack` plugin searches for `webpack.config.js` files to infer tasks that run webpack. + +### 2. Create an Inferred Task + +The plugin then configures tasks with a name that you specified in the plugin's configuration in `nx.json`. The settings for the task are determined by the tool configuration. + +The `@nx/webpack` plugin creates tasks named `build`, `serve` and `preview` by default and it automatically sets the task caching settings based on the values in the webpack configuration files. + +## What Is Inferred + +Nx plugins infer the following properties by analyzing the tool configuration. + +- Command - How is the tool invoked +- [Cacheability](/concepts/how-caching-works) - Whether the task will be cached by Nx. When the Inputs have not changed the Outputs will be restored from the cache. +- [Inputs](/recipes/running-tasks/configure-inputs) - Inputs are used by the task to produce Outputs. Inputs are used to determine when the Outputs of a task can be restored from the cache. +- [Outputs](/recipes/running-tasks/configure-outputs) - Outputs are the results of a task. Outputs are restored from the cache when the Inputs are the same as a previous run. +- [Task Dependencies](/concepts/task-pipeline-configuration) - The list of other tasks which must be completed before running this task. + +## Nx Uses Plugins to Build the Graph + +A typical workspace will have many plugins inferring tasks. Nx processes all the plugins registered in `nx.json` to create project configuration for individual projects and a project and task graph that shows the connections between them all. + +### Plugin Order Matters + +Plugins are processed in the order that they appear in the `plugins` array in `nx.json`. So, if multiple plugins create a task with the same name, the plugin listed last will win. If, for some reason, you have a project with both a `vite.config.js` file and a `webpack.config.js` file, both the `@nx/vite` plugin and the `@nx/webpack` plugin will try to create a `build` task. The `build` task that is executed will be the task that belongs to the plugin listed lower in the `plugins` array. + +## View Inferred Tasks + +To view the task settings for projects in your workspace, [show the project details](/features/explore-graph) either from the command line or using Nx Console. + +```shell +nx show project my-project --web +``` + +{% project-details jsonFile="shared/concepts/myreactapp.json"%} +{% /project-details %} + +## Overriding Inferred Task Configuration + +You can override the task configuration inferred by plugins in several ways. +If you want to overwrite the task configuration for multiple projects, [use the `targetDefaults` object](/reference/nx-json#target-defaults) in the `nx.json` file. +If you only want to override the task configuration for a specific project, [update that project's configuration](/reference/project-configuration) in `package.json` or `project.json`. +This configuration is more specific so it will override both the inferred configuration and the `targetDefaults`. + +The order of precedence for task configuration is: + +1. Inferred Task Configurations from plugins in `nx.json`. +2. `targetDefaults` in `nx.json`. +3. Project Configuration in `package.json` or `project.json`. + +More details about how to override task configuration is available in these recipes: + +- [Configure Inputs for Task Caching](/recipes/running-tasks/configure-inputs) +- [Configure Outputs for Task Caching](/recipes/running-tasks/configure-outputs) +- [Defining a Task Pipeline](/recipes/running-tasks/defining-task-pipeline) diff --git a/docs/shared/concepts/integrated-vs-package-based.md b/docs/shared/concepts/integrated-vs-package-based.md index 0636818ba0423..540e31036f066 100644 --- a/docs/shared/concepts/integrated-vs-package-based.md +++ b/docs/shared/concepts/integrated-vs-package-based.md @@ -1,9 +1,12 @@ # Integrated Repos vs. Package-Based Repos vs. Standalone Apps -There are two styles of monorepos that you can build with Nx: integrated repos and package-based repos. At the most basic level, package-based repos utilize Nx's core features while integrated repos also use the plugin features. But the difference is more about the mindset than the features used and the style choice is on a spectrum - not a boolean. +There are many different ways to structure a repository and Nx is designed to support them all. To better discuss how Nx can improve a repository, it is helpful to define some terms. -- Package-based repos focus on flexibility and ease of adoption. -- Integrated repos focus on efficiency and ease of maintenance. +- Standalone Application - A repository with a single application +- Package-Based Repository - A repository with multiple projects that depend on each other via `package.json` and often have nested `node_modules` +- Integrated Repository - A repository with multiple projects that depend on each other via typescript imports and often employ a single version policy + +Nx's features can be enabled in each of these types of repositories. Just as each repository is unique and may not exactly fit in one of these categories, the way Nx is used will vary between repositories. {% cards %} {% card title="Packaged based vs Integrated Style - Use Nx however it works best for you" description="Choose your style and what works best for you!" type="video" url="https://youtu.be/ArmERpNvC8Y" /%} @@ -15,7 +18,13 @@ There are two styles of monorepos that you can build with Nx: integrated repos a A package-based repo is a collection of packages that depend on each other via `package.json` files and nested `node_modules`. With this setup, you typically have [different dependencies for each project](/concepts/more-concepts/dependency-management). Build tools like Jest and Webpack work as usual, since everything is resolved as if each package was in a separate repo and all of its dependencies were published to npm. Moving an existing package into a package-based repo is very easy since you generally leave that package's existing build tooling untouched. Creating a new package inside the repo is just as difficult as spinning up a new repo since you have to create all the build tooling from scratch. -Lerna, Yarn, Lage, [Turborepo](/concepts/more-concepts/turbo-and-nx) and Nx (without plugins) support this style. +Lerna, Yarn, Lage, [Turborepo](/concepts/more-concepts/turbo-and-nx) and Nx support this style. + +Someone who appreciates the flexibility of a package-based repository will be most interested in the following features of Nx: + +- Add [caching](/features/cache-task-results) and [task orchestration](/features/run-tasks) without modifying tooling or file structure +- Import existing projects into the repo without modifying their tooling +- Easily create new projects or tools with [code generators](/features/generate-code) {% cards %} {% card title="Tutorial: Getting Started with Package-Based Repos" description="Walkthrough for creating a package-based monorepo with Nx" type="documentation" url="/getting-started/tutorials/package-based-repo-tutorial" /%} @@ -25,7 +34,13 @@ Lerna, Yarn, Lage, [Turborepo](/concepts/more-concepts/turbo-and-nx) and Nx (wit An integrated repo contains projects that depend on each other through standard import statements. There is typically a [single version of every dependency](/concepts/more-concepts/dependency-management) defined at the root. Sometimes build tools like Jest and Webpack need to be wrapped to work correctly. It's harder to add an existing package to this repo style because the build tooling for that package may need to be modified. It's straightforward to add a brand-new project to the repo because all the tooling decisions have already been made. -Bazel and Nx (with plugins) support this style. +Bazel and Nx support this style. + +Someone who appreciates the structure and consistency of an integrated repository will be most interested in the following features of Nx: + +- [Enforce architectural decisions](/features/enforce-module-boundaries) with tagging rules +- Encourage consistency with custom [code generators](/features/generate-code) +- [Automate updating dependencies](/features/automate-updating-dependencies) of the entire toolchain {% cards %} {% card title="Tutorial: Getting Started with Integrated Repos" description="Walkthrough for creating an integrated monorepo with Nx" type="documentation" url="/getting-started/tutorials/integrated-repo-tutorial" /%} @@ -33,7 +48,12 @@ Bazel and Nx (with plugins) support this style. ## Standalone Applications -Nx plugins, especially the [generators](/core-features/plugin-features/use-code-generators), [executors](/core-features/plugin-features/use-task-executors) and [migrations](/core-features/automate-updating-dependencies) that come with them, are not only valuable for a monorepo scenario. In fact, many developers use Nx not primarily for its monorepo support, but for its tooling support, particularly its ability to modularize a codebase and, thus, better scale it. In v15.3, Nx introduced support for Standalone Applications. It is like an integrated monorepo setup, but with just a single, root-level application. Think of it as an advanced, more capable Create-React-App or Angular CLI. And obviously, you can still leverage all the generators and executors and structure your application into libraries or submodules. +Nx plugins, especially the [generators](/features/generate-code), [executors](/concepts/executors-and-configurations) and [migrations](/features/automate-updating-dependencies) that come with them, are not only valuable for a monorepo scenario. In fact, many developers use Nx not primarily for its monorepo support, but for its tooling support, particularly its ability to modularize a codebase and, thus, better scale it. In v15.3, Nx introduced support for Standalone Applications. It is like an integrated monorepo setup, but with just a single, root-level application. Think of it as an advanced, more capable Create-React-App or Angular CLI. And obviously, you can still leverage all the generators and executors and structure your application into libraries or submodules. + +Someone whose main focus is on improving their single application will be most interested in the following features of Nx: + +- Set up a [fast CI system](/ci/intro/ci-with-nx) without CI expertise +- Easily [add new tooling](/plugin-registry) {% cards %} {% card title="Standalone Applications with Nx" description="Learn what Standlone Apps are and how Nx can be useful" type="video" url="https://youtu.be/qEaVzh-oBBc" /%} @@ -43,7 +63,7 @@ Nx plugins, especially the [generators](/core-features/plugin-features/use-code- ## How to Choose -Nx itself doesn't care which style you choose. You can have a package-based repo setup and still host projects that use Nx plugins from the integrated repo setup. Hence you end up with a "hybrid" approach. Similarly, a Standalone App workspace setup is none other than an integrated Nx monorepo, but with only one application using a different folder layout. +Nx itself doesn't care which style you choose. You can use all the features of Nx whether you are in a package based repo or integrated repo. Certain Nx features will be more or less valuable for a standalone app, but all the features of Nx are still available to be put in place as soon as that repo grows to include more apps. You can be successful working in any style, and there are ways to transition between them. At a high level diff --git a/docs/shared/concepts/myreactapp.json b/docs/shared/concepts/myreactapp.json new file mode 100644 index 0000000000000..f0bcd388cf867 --- /dev/null +++ b/docs/shared/concepts/myreactapp.json @@ -0,0 +1,213 @@ +{ + "project": { + "name": "myreactapp", + "type": "app", + "data": { + "root": "apps/myreactapp", + "targets": { + "build": { + "options": { + "cwd": "apps/apps/myreactapp", + "command": "vite build" + }, + "cache": true, + "dependsOn": ["^build"], + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["vite"] + } + ], + "outputs": ["{workspaceRoot}/dist/apps/app1"], + "executor": "nx:run-commands", + "configurations": {} + }, + "serve": { + "options": { + "cwd": "apps/apps/myreactapp", + "command": "vite serve" + }, + "executor": "nx:run-commands", + "configurations": {} + }, + "preview": { + "options": { + "cwd": "apps/apps/myreactapp", + "command": "vite preview" + }, + "executor": "nx:run-commands", + "configurations": {} + }, + "serve-static": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "build" + }, + "configurations": {} + }, + "test": { + "options": { + "cwd": "apps/apps/myreactapp", + "command": "vitest run" + }, + "cache": true, + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["vitest"] + } + ], + "outputs": ["{workspaceRoot}/coverage/apps/app1"], + "executor": "nx:run-commands", + "configurations": {} + }, + "lint": { + "cache": true, + "options": { + "cwd": "apps/myreactapp", + "command": "eslint ." + }, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.json", + "{workspaceRoot}/apps/myreactapp/.eslintrc.json", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "configurations": {} + } + }, + "name": "myreactapp", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/apps/myreactapp/src", + "projectType": "application", + "tags": [], + "implicitDependencies": [] + } + }, + "sourceMap": { + "root": ["apps/myreactapp/project.json", "nx/core/project-json"], + "targets": ["apps/myreactapp/project.json", "nx/core/project-json"], + "targets.build": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"], + "targets.build.command": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.cache": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.dependsOn": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.inputs": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.outputs": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options.cwd": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"], + "targets.serve.command": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve.options": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve.options.cwd": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.preview": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"], + "targets.preview.command": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.preview.options": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.preview.options.cwd": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve-static": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve-static.executor": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve-static.options": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.serve-static.options.buildTarget": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.test": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"], + "targets.test.command": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.test.options": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.test.cache": ["apps/myreactapp/vite.config.ts", "@nx/vite/plugin"], + "targets.test.inputs": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.test.outputs": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.test.options.cwd": [ + "apps/myreactapp/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.lint": ["apps/myreactapp/project.json", "@nx/eslint/plugin"], + "targets.lint.command": [ + "apps/myreactapp/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.cache": ["apps/myreactapp/project.json", "@nx/eslint/plugin"], + "targets.lint.options": [ + "apps/myreactapp/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.inputs": [ + "apps/myreactapp/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.options.cwd": [ + "apps/myreactapp/project.json", + "@nx/eslint/plugin" + ], + "name": ["apps/myreactapp/project.json", "nx/core/project-json"], + "$schema": ["apps/myreactapp/project.json", "nx/core/project-json"], + "sourceRoot": ["apps/myreactapp/project.json", "nx/core/project-json"], + "projectType": ["apps/myreactapp/project.json", "nx/core/project-json"], + "tags": ["apps/myreactapp/project.json", "nx/core/project-json"] + } +} diff --git a/docs/shared/concepts/nx-plugins.md b/docs/shared/concepts/nx-plugins.md new file mode 100644 index 0000000000000..ba51340c91308 --- /dev/null +++ b/docs/shared/concepts/nx-plugins.md @@ -0,0 +1,27 @@ +# What Are Nx Plugins? + +Nx plugins help developers use a tool or framework with Nx. They allow the plugin author who knows the best way to use a tool with Nx to codify their expertise and allow the whole community to reuse those solutions. + +For example, plugins can accomplish the following: + +- [Configure Nx cache settings](/concepts/inferred-tasks) for a tool. The [`@nx/webpack`](/nx-api/webpack) plugin can automatically configure the [inputs](/recipes/running-tasks/configure-inputs) and [outputs](/recipes/running-tasks/configure-outputs) for a `build` task based on the settings in the `webpack.config.js` file it uses. +- [Update tooling configuration](/features/automate-updating-dependencies) when upgrading the tool version. When Storybook 7 introduced a [new format](https://storybook.js.org/blog/storybook-csf3-is-here) for their configuration files, anyone using the [`@nx/storybook`](/nx-api/storybook) plugin could automatically apply those changes to their repository when upgrading. +- [Set up a tool](/features/generate-code) for the first time. With the [`@nx/playwright`](/nx-api/playwright) plugin installed, you can use the `@nx/playwright:configuration` code generator to set up Playwright tests in an existing project. +- [Run a tool in an advanced way](/concepts/executors-and-configurations). The [`@nx/js`](/nx-api/js) plugin's [`@nx/js:tsc` executor](/nx-api/js/executors/tsc) combines Nx's understanding of your repository with Typescript's native batch mode feature to make your builds [even more performant](/recipes/tips-n-tricks/enable-tsc-batch-mode). + +## Plugin Features + +{% cards %} +{% card title="Infer tasks" description="Automatically configure Nx settings for tasks based on tooling configuration" type="documentation" url="/concepts/inferred-tasks" /%} +{% card title="Generate Code" description="Generate and modify code to set up and use the tool or framework" type="documentation" url="/features/generate-code" /%} +{% card title="Maintain Dependencies" description="Automatically update package versions and tooling configuration" type="documentation" url="/features/generate-code" /%} +{% card title="Enhance Tooling with Executors" description="Run a tool in an advanced way that may not be possible from the command line" type="documentation" url="/concepts/executors-and-configurations" /%} +{% /cards %} + +## Types of Plugins + +{% cards %} +{% card title="Official Plugins" description="The API documentation for Nx Plugins maintained by the Nx core team" type="documentation" url="/nx-api" /%} +{% card title="Community Plugins" description="Browse the plugin registry to discover plugins created by the community" type="documentation" url="/plugin-registry" /%} +{% card title="Build Your Own Plugin" description="Build your own plugin to use internally or share with the community" type="documentation" url="/extending-nx/tutorials/create-plugin" /%} +{% /cards %} diff --git a/docs/shared/core-features/distribute-task-execution.md b/docs/shared/core-features/distribute-task-execution.md deleted file mode 100644 index 75a17ee7cf16c..0000000000000 --- a/docs/shared/core-features/distribute-task-execution.md +++ /dev/null @@ -1,163 +0,0 @@ -# Distribute Task Execution (DTE) - -Nx speeds up your average CI time with [caching](/core-features/cache-task-results) and -the [affected command](/ci/features/affected). But neither of these features help with the worst case scenario. When -something at the core of your repo has been modified and every task needs to be run in CI, the only way to improve the -performance is by adding more agent jobs and efficiently parallelizing the tasks. - -The most obvious way to parallelize tasks is to split tasks up by type: running all tests on one job, all builds on -another and all lint tasks on a third. This strategy is called binning. This can be made difficult if some test tasks -have build tasks as prerequisites, but assuming you figure out some way to handle that, a typical set up can look like -the diagram below. Here the test tasks are delayed until all necessary build artifacts are ready, but the build and lint -tasks can start right away. - -![CI using binning](/shared/images/dte/binning.svg) - -The problem with the binning approach is you'll end up with some idle time on one or more jobs. Nx's distributed task -execution reduces that idle time to the minimum possible by assigning each individual task to agent jobs based on the -task's average run time. Nx also guarantees that tasks are executed in the correct order and uses remote caching to -make sure that build artifacts from previous tasks are present on every agent job that needs them. - -When you set up Nx's distributed task execution, your task graph will look more like this: - -![CI using DTE](/shared/images/dte/3agents.svg) - -And not only will CI finish faster, but the debugging experience is the same as if you ran all of your CI on a single -job. That's because Nx uses remote caching to recreate all of the logs and build artifacts on the main job. - -Find more information in this [guide to parallelization and distribution in CI](/ci/concepts/parallelization-distribution). - -## Set up - -To distribute your task execution, you need to (1) connect to Nx Cloud and (2) enable DTE in your CI workflow. Each of -these steps can be enabled with a single command: - -```shell title="1. Connect to Nx Cloud" -nx connect -``` - -{% callout type="note" title="Use the latest version of Nx Cloud" %} -This command installs the latest version of `nx-cloud`. The latest version works with any version of Nx >= 13.0. -{% /callout %} - -If you have a new workspace, you can generate the CI configuration as follows: - -```shell title="2. Enable DTE in CI" -nx generate @nx/workspace:ci-workflow --ci=github -``` - -The `--ci` flag can be `github`, `circleci`, `azure`, `gitlab`, or `bitbucket`. - -For existing workspaces you would probably want to adjust your configuration by hand. See below for examples. - -## CI Execution Flow - -Distributed task execution can work on any CI provider. You are responsible for launching jobs in your CI system. Nx -Cloud then coordinates the way those jobs work together. There are two different kinds of jobs that you'll need to -create in your CI system. If you would like Nx Cloud to dynamically provision agents for you, check out [Nx Agents](/ci/features/nx-agents) - -1. Main job that controls what is going to be executed -2. Multiple agent jobs that actually execute the tasks - -![Diagram showing Nx Cloud distributing tasks to multiple agents](/shared/images/dte/distributed-caching-and-task-execution.svg) - -The main CI job execution flow looks like this: - -```yaml -# Coordinate the agents to run the tasks -- npx nx-cloud start-ci-run --stop-agents-after="build" # makes all nx commands distributed by default -# Run any commands you want here -- nx affected -t test lint build # run on agents in a distributed fashion -- nx affected -t deploy --no-dte # run the main job -``` - -The agent job execution flow is simple: - -```yaml -# Wait for tasks to execute -- npx nx-cloud start-agent -``` - -Depending on your CI setup, you might want to stop the agents explicitly. You can do it as follows - -```yam -# Stop any run away agents -- npx nx-cloud stop-all-agents -``` - -> For most CI providers, Nx Cloud is able to able to match the main and the agents automatically but for some you might -> need to provision the `NX_BRANCH` and `NX_CI_EXECUTION_ID` env variables ( -> see [Environment Variables](/ci/reference/env-vars) for more info). - -The main job looks more or less the same way as if you haven't used any distribution. The only thing you need to do is -to invoke `npx nx-cloud start-ci-run` at the beginning and, optionally, invoke `npx nx-cloud stop-all-agents` at the -end. - -The agent jobs run long-running `start-agent` processes that execute all the tasks associated with a given CI run. The -only thing you need to do to set them up is to invoke `npx nx-cloud start-agent`. This process will keep running until -Nx Cloud tells it to terminate. - -> Note it's important that the main job and the agent jobs have the same environment and the same source code. They -> start -> around the same time. And, once the main job completes, all the agents -> will be stopped. - -It's also important to note that an Nx Cloud agent isn't a machine but rather a long-running process that runs on a -machine. I.e., Nx Cloud doesn't manage your agents--you need to do it in your CI config (check out CI examples below). - -Nx Cloud is an orchestrator. The main job tells Nx Cloud what you want to run, and Nx Cloud will distribute those tasks -across the agents. Nx Cloud will automatically move files from one agent to another, from the agents to the main job. - -The end result is that when say `nx affected -t build` completes on the main job, all the file artifacts created -on agents are copied over to the main job, as if the main job had built everything locally. - -## Running Things in Parallel - -`--parallel` is propagated to the agents. E.g., `npx nx affected -t build --parallel=3` tells Nx Cloud to -run -up to 3 build targets in parallel on each agent. So if you have say 10 agents, you will run up to 30 builds in parallel -across all of them. - -You also want to run as many commands in parallel as you can. For instance, - -```yaml -- nx affected -t build -- nx affected -t test -- nx affected -t lint -``` - -is worse than - -```yaml -- nx affected -t build & nx affected -t test & nx affected -t lint -``` - -or - -```yaml -- nx affected -t build test lint -``` - -The latter two are going to schedule all the three commands at the same time, so if an agent cannot find anything to -build, they will start running tests and lints. The result is better agent utilization and shorter CI time. - -## CI/CD Examples - -The examples below show how to set up CI using Nx and Nx Cloud using distributed task execution and remote caching. - -Every organization manages their CI/CD pipelines differently, so the examples don't cover org-specific aspects of -CI/CD (e.g., deployment). They mainly focus on configuring Nx correctly. - -Read the guides for more information on how to configure them in CI. - -- [Azure Pipelines](/ci/recipes/set-up/monorepo-ci-azure#distributed-ci-with-nx-cloud) -- [Circle CI](/ci/recipes/set-up/monorepo-ci-circle-ci#distributed-ci-with-nx-cloud) -- [GitHub Actions](/ci/recipes/set-up/monorepo-ci-github-actions#distributed-ci-with-nx-cloud) -- [Jenkins](/ci/recipes/set-up/monorepo-ci-jenkins#distributed-ci-with-nx-cloud) - -Note that only cacheable operations can be distributed because they have to be replayed on the main job. - -## Relevant Repositories and Examples - -- [Nx: On how to make your CI 16 times faster with a small config change](https://github.com/vsavkin/interstellar) -- ["Lerna & Distributed Task Execution" Example](https://github.com/vsavkin/lerna-dte) diff --git a/docs/shared/core-features/explore-graph.md b/docs/shared/core-features/explore-graph.md deleted file mode 100644 index ca6b24b5495d2..0000000000000 --- a/docs/shared/core-features/explore-graph.md +++ /dev/null @@ -1,144 +0,0 @@ -# Explore the Graph - -For Nx to run tasks quickly and correctly, it creates a graph of the dependencies between all the projects in the -repository. Exploring this graph visually can be useful -to understand why Nx is behaving in a certain way and to get a -high level view of your code architecture. - -To launch the project graph visualization run: - -```shell -npx nx graph -``` - -This will open a browser window with an interactive representation of the project graph of your current codebase. -Viewing the entire graph can be unmanageable even for smaller repositories, so there are several ways to narrow the -focus of the visualization down to the most useful part of the graph at the moment. - -1. Focus on a specific project and then use the proximity and group by folder controls to modify the graph around that - project. -2. Use the search bar to find all projects with names that contain a certain string. -3. Manually hide or show projects in the sidebar - -Once the graph is displayed, you can click on an individual dependency link to find out what specific file(s) created -that dependency. - -Try playing around with a [fully interactive graph on a sample repo](https://nrwl-nx-examples-dep-graph.netlify.app/?focus=cart) or look at the more limited example below: - -{% graph height="450px" %} - -```json -{ - "hash": "58420bb4002bb9b6914bdeb7808c77a591a089fc82aaee11e656d73b2735e3fa", - "projects": [ - { - "name": "shared-product-state", - "type": "lib", - "data": { - "tags": ["scope:shared", "type:state"] - } - }, - { - "name": "shared-product-types", - "type": "lib", - "data": { - "tags": ["type:types", "scope:shared"] - } - }, - { - "name": "shared-product-data", - "type": "lib", - "data": { - "tags": ["type:data", "scope:shared"] - } - }, - { - "name": "cart-cart-page", - "type": "lib", - "data": { - "tags": ["scope:cart", "type:feature"] - } - }, - { - "name": "shared-styles", - "type": "lib", - "data": { - "tags": ["scope:shared", "type:styles"] - } - }, - { - "name": "cart-e2e", - "type": "e2e", - "data": { - "tags": ["scope:cart", "type:e2e"] - } - }, - { - "name": "cart", - "type": "app", - "data": { - "tags": ["type:app", "scope:cart"] - } - } - ], - "dependencies": { - "shared-product-state": [ - { - "source": "shared-product-state", - "target": "shared-product-data", - "type": "static" - }, - { - "source": "shared-product-state", - "target": "shared-product-types", - "type": "static" - } - ], - "shared-product-types": [], - "shared-product-data": [ - { - "source": "shared-product-data", - "target": "shared-product-types", - "type": "static" - } - ], - "shared-e2e-utils": [], - "cart-cart-page": [ - { - "source": "cart-cart-page", - "target": "shared-product-state", - "type": "static" - } - ], - "shared-styles": [], - "cart-e2e": [ - { "source": "cart-e2e", "target": "cart", "type": "implicit" } - ], - "cart": [ - { "source": "cart", "target": "shared-styles", "type": "implicit" }, - { "source": "cart", "target": "cart-cart-page", "type": "static" } - ] - }, - "workspaceLayout": { - "appsDir": "apps", - "libsDir": "libs" - }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false, - "exclude": [], - "enableTooltips": true -} -``` - -{% /graph %} - -## Export Project Graph to JSON - -If you prefer to analyze the underlying data of the project graph with a script or some other tool, you can run: - -```shell -nx graph --file=output.json -``` - -This will give you all the information that is used to create the project graph visualization. diff --git a/docs/shared/core-features/remote-cache.md b/docs/shared/core-features/remote-cache.md deleted file mode 100644 index a9d35e30cfb08..0000000000000 --- a/docs/shared/core-features/remote-cache.md +++ /dev/null @@ -1,97 +0,0 @@ -# Use Remote Caching - -By default Nx [caches task computations locally](/core-features/cache-task-results). However, to benefit from the cache across your team and in particular on CI, the computation cache can also be distributed across multiple machines. Nx Cloud is an app that provides a fast and zero-config implementation of remote caching. It is a commercial add-on to Nx, is completely free for OSS projects and comes with generous plans for startups and dedicated offerings for enterprise customers ([read more here](https://nx.app/pricing)). - -![Diagram showing Teika sharing his cache with CI, Kimiko and James](/shared/images/dte/distributed-caching.svg) - -In this diagram, Teika runs the build once on his machine, then CI, Kimiko and James can use the cached artifact from Teika instead of re-executing the same work. - -## Setup Remote Caching with Nx Cloud - -To enable remote caching for your Nx workspace run the following command: - -```shell -npx nx connect -``` - -This connects your workspace with Nx Cloud's remote caching service. It will also allow you to benefit from other Nx Cloud features such as [distributed task execution](/ci/features/distribute-task-execution). - -To see the remote cache in action, run: - -```{% command="nx build header && nx reset && nx build header"%} -> nx run header:build - -> header@0.0.0 build -> rimraf dist && rollup --config - -src/index.tsx → dist... -created dist in 786ms - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project header (2s) - - See logs and investigate cache misses at https://cloud.nx.app/runs/k0HDHACpL8 - - - > NX Resetting the Nx workspace cache and stopping the Nx Daemon. - - This might take a few minutes. - - - > NX Daemon Server - Stopped - - - > NX Successfully reset the Nx workspace. - - -> nx run header:build [remote cache] - - -> header@0.0.0 build -> rimraf dist && rollup --config - - -src/index.tsx → dist... -created dist in 786ms - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project header (664ms) - - Nx read the output from the cache instead of running the command for 1 out of 1 tasks. - - Nx Cloud made it possible to reuse header: https://nx.app/runs/P0X6ZGTkqZ -``` - -## Claim your Nx Cloud Workspace - -During the setup process you might have seen a link to claim your Nx Cloud connected workspace. - -```plaintext -> NX NOTE Nx Cloud has been enabled - - Your workspace is currently public. Anybody with code access - can view the workspace on nx.app. - - You can connect the workspace to your Nx Cloud account at - https://nx.app/orgs/workspace-setup?accessToken=N2Y3NzcyO... - (You can do this later.) -``` - -Click on this link to associate the workspace with your Nx Cloud account. If you don't have an Nx Cloud account, you can create one on the spot. - -![Nx Cloud Workspace Dashboard](/shared/images/nx-cloud/nx-cloud-workspace-overview.png) - -Claiming your workspace allows you to - -- see stats about your CI runs, cache hits number of agents used for distributing tasks -- enable [source control integrations](/ci/recipes/source-control-integration) to get information embedded in your GitHub, Bitbucket or GitLab PRs -- manage and create access tokens and [adjust access and permission](/ci/concepts/cache-security) -- manage your organization & user permissions for your Nx Cloud workspace - -**If you lose this link, you can still connect your workspace to Nx Cloud**. Go to [nx.app](https://nx.app), create an account, and connect your workspace using the access token from `nx.json`. - -## Skipping Cloud Cache - -Similar to how `--skip-nx-cache` will instruct Nx not to use the local cache, passing `--no-cloud` will tell Nx not to use the remote cache from Nx Cloud. diff --git a/docs/shared/core-tutorial/01-create-blog.md b/docs/shared/core-tutorial/01-create-blog.md index 440a9c45118c2..b6c941dc08578 100644 --- a/docs/shared/core-tutorial/01-create-blog.md +++ b/docs/shared/core-tutorial/01-create-blog.md @@ -3,7 +3,7 @@ In this tutorial you create multiple projects in a monorepo and take advantage of the core Nx features with a minimum of configuration. {% callout type="check" title="Package-Based Repo" %} -This tutorial sets up a [package-based repo](/concepts/integrated-vs-package-based). If you prefer an [integrated repo](/concepts/integrated-vs-package-based), check out the [React](/getting-started/tutorials/react-monorepo-tutorial), [Angular](/getting-started/tutorials/angular-monorepo-tutorial) or [Node](/getting-started/tutorials/node-server-tutorial) tutorials. +This tutorial sets up a [package-based repo](/concepts/integrated-vs-package-based). If you prefer an [integrated repo](/concepts/integrated-vs-package-based), check out the [React](/getting-started/tutorials/react-monorepo-tutorial) or [Angular](/getting-started/tutorials/angular-monorepo-tutorial) tutorials. {% /callout %} ## Contents: diff --git a/docs/shared/deprecated/as-provided-vs-derived.md b/docs/shared/deprecated/as-provided-vs-derived.md index 19990ef077352..62e8350ef816c 100644 --- a/docs/shared/deprecated/as-provided-vs-derived.md +++ b/docs/shared/deprecated/as-provided-vs-derived.md @@ -12,7 +12,7 @@ Here are some of the issues with the `derived` behavior that are addressed with ## Using Nx Console -You can use [Nx Console](/core-features/integrate-with-editors) for an intuitive experience running generators. +You can use [Nx Console](/features/integrate-with-editors) for an intuitive experience running generators. 1. If you right-click a folder and choose `Nx generate`, the code generation will be run from that folder. 2. As you fill out the generate form, Nx Console will show you a preview of where the new files will be generated. diff --git a/docs/shared/deprecated/cacheable-operations.md b/docs/shared/deprecated/cacheable-operations.md new file mode 100644 index 0000000000000..3278f2eec4e53 --- /dev/null +++ b/docs/shared/deprecated/cacheable-operations.md @@ -0,0 +1,5 @@ +# cacheableOperations + +In Nx < 17, the way to define which tasks were cacheable was to add the task name to the `cacheableOperations` array in `nx.json`. This way of defining cacheable tasks required all tasks named `test` to be either cacheable or not cacheable. + +In Nx 17, use the `cache` property in `targetDefaults` or individual target definitions in the project level configuration. diff --git a/docs/shared/deprecated/global-implicit-dependencies.md b/docs/shared/deprecated/global-implicit-dependencies.md index 5de88ce121dee..e7e7c3efb918b 100644 --- a/docs/shared/deprecated/global-implicit-dependencies.md +++ b/docs/shared/deprecated/global-implicit-dependencies.md @@ -1,6 +1,6 @@ # Global Implicit Dependencies -Since v14.4, Nx supports [`inputs` and `namedInputs`](/recipes/running-tasks/customizing-inputs) for setting up implicit dependencies. As of Nx v16, the `implicitDependencies` defined in `nx.json` are ignored and do not influence the affected graph. This field will be removed in v17. The [`implicitDependencies` in the project configuration](/reference/project-configuration#implicitdependencies) are still the best way to manually set up a dependency between two projects that Nx is not able to detect automatically. +Since v14.4, Nx supports [`inputs` and `namedInputs`](/recipes/running-tasks/configure-inputs) for setting up implicit dependencies. As of Nx v16, the `implicitDependencies` defined in `nx.json` are ignored and do not influence the affected graph. This field will be removed in v17. The [`implicitDependencies` in the project configuration](/reference/project-configuration#implicitdependencies) are still the best way to manually set up a dependency between two projects that Nx is not able to detect automatically. ## Projects Depending on Global Files @@ -34,7 +34,7 @@ To express the same dependencies with `inputs` and `namedInputs`, modify the def The `sharedGlobals` are included in the `default` named input, so most targets will be set up to depend on them. -For a more detailed explanation, read the [Customizing Inputs and Named Inputs guide](/recipes/running-tasks/customizing-inputs) +For a more detailed explanation, read the [Customizing Inputs and Named Inputs guide](/recipes/running-tasks/configure-inputs) ### Dependencies on Sections of the Root `package.json` File diff --git a/docs/shared/deprecated/npm-scope.md b/docs/shared/deprecated/npm-scope.md new file mode 100644 index 0000000000000..50e4d18451178 --- /dev/null +++ b/docs/shared/deprecated/npm-scope.md @@ -0,0 +1,7 @@ +# NPM Scope + +The `npmScope` property of the `nx.json` file is deprecated as of version 16.2.0. `npmScope` was used as a prefix for the names of newly created projects. The new recommended way to define the organization prefix is to set the `name` property in the root `package.json` file to `@my-org/root`. Then `@my-org/` will be used as a prefix for all newly created projects. + +In Nx 16, if the `npmScope` property is present, it will be used as a prefix. If the `npmScope` property is not present, the `name` property of the root `package.json` file will be used to infer the prefix. + +In Nx 17+, the `npmScope` property is ignored. diff --git a/docs/shared/deprecated/v1-nx-plugin-api.md b/docs/shared/deprecated/v1-nx-plugin-api.md index 3bf0c86514a72..8e32be7dfe86e 100644 --- a/docs/shared/deprecated/v1-nx-plugin-api.md +++ b/docs/shared/deprecated/v1-nx-plugin-api.md @@ -234,7 +234,7 @@ builder.addDynamicDependency( ### Visualizing the Project Graph -You can then visualize the project graph as described [here](/core-features/explore-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`. +You can then visualize the project graph as described [here](/features/explore-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`. It might also be a good idea to ensure that the dep graph is not running on the nx daemon by setting `NX_DAEMON=false`, as this will ensure you will be able to see any `console.log` statements you add as you're developing. diff --git a/docs/shared/deprecated/workspace-executors.md b/docs/shared/deprecated/workspace-executors.md index bce0270ee43fc..bccf589c1f221 100644 --- a/docs/shared/deprecated/workspace-executors.md +++ b/docs/shared/deprecated/workspace-executors.md @@ -7,8 +7,7 @@ In Nx 13.10+, local nx plugins can contain executors that are used in the worksp - If you don't already have a local plugin, use Nx to generate one: ```shell -# replace `latest` with the version that matches your Nx version -npm install @nx/plugin@latest +npm add -D @nx/plugin nx g @nx/plugin:plugin my-plugin ``` diff --git a/docs/shared/deprecated/workspace-generators.md b/docs/shared/deprecated/workspace-generators.md index c8ca4149ac30d..70bb9bd140b54 100644 --- a/docs/shared/deprecated/workspace-generators.md +++ b/docs/shared/deprecated/workspace-generators.md @@ -15,8 +15,7 @@ When migrating to Nx 16, a new workspace plugin is automatically generated in th - If you don't already have a local plugin, use Nx to generate one: ```shell -# replace `latest` with the version that matches your Nx version -npm install @nx/plugin@latest +npm add -D @nx/plugin nx g @nx/plugin:plugin my-plugin ``` diff --git a/docs/shared/core-features/automate-updating-dependencies.md b/docs/shared/features/automate-updating-dependencies.md similarity index 96% rename from docs/shared/core-features/automate-updating-dependencies.md rename to docs/shared/features/automate-updating-dependencies.md index 0e3f70dae8bb7..b36351655c81e 100644 --- a/docs/shared/core-features/automate-updating-dependencies.md +++ b/docs/shared/features/automate-updating-dependencies.md @@ -68,7 +68,7 @@ Note: You may want to keep the `migrations.json` until every branch that was cre ## Keep Nx Packages on the Same Version -When you run `nx migrate`, the `nx` package and all the `@nx/` packages get updated to the same version. It is important to [keep these versions in sync](/recipes/tips-n-tricks/keep-nx-versions-in-sync), or you can encounter some difficult to debug errors. As long as you run `nx migrate` instead of manually changing the version numbers, you shouldn't have to worry about it. +When you run `nx migrate`, the `nx` package and all the `@nx/` packages get updated to the same version. It is important to [keep these versions in sync](/recipes/tips-n-tricks/keep-nx-versions-in-sync), or you can encounter some difficult to debug errors. As long as you run `nx migrate` instead of manually changing the version numbers, you shouldn't have to worry about it. Also, when you add a new plugin, use `nx add ` to automatically install the version that matches your repository's version of Nx. {% callout type="note" title="Use the latest nx-cloud version" %} The `nx-cloud` package does not need to be in sync with the other Nx packages. For best results, stay on the latest version of `nx-cloud`. The latest `nx-cloud` version supports the most recent 2 major versions of `nx`, although earlier versions of `nx` may also be compatible. diff --git a/docs/shared/core-features/cache-task-results.md b/docs/shared/features/cache-task-results.md similarity index 90% rename from docs/shared/core-features/cache-task-results.md rename to docs/shared/features/cache-task-results.md index 6861e1aaadd1c..64c320c85ba60 100644 --- a/docs/shared/core-features/cache-task-results.md +++ b/docs/shared/features/cache-task-results.md @@ -64,6 +64,10 @@ Keep reading to learn how to fine-tune what gets cached. ## Fine-tune Caching with Inputs and Outputs +{% callout type="note" title="Detect Inputs and Outputs" %} +Nx can automatically set inputs and outputs for you based on your tooling configuration settings when you use [inferred tasks](/concepts/inferred-tasks) +{% /callout %} + Nx's caching feature starts with sensible defaults, but you can also fine-tune the defaults to control exactly what gets cached and when. There are two main options that control caching: - **Inputs -** define what gets included as part of the calculated hash (e.g. files, environment variables, etc.) @@ -111,7 +115,7 @@ To achieve this, we can add an `inputs` and `outputs` definition globally for al Note, you only need to define output locations if they differ from the usual `dist` or `build` directory which Nx automatically recognizes. -Learn more [about configuring inputs including `namedInputs`](/recipes/running-tasks/customizing-inputs). +Learn more [about configuring inputs including `namedInputs`](/recipes/running-tasks/configure-inputs). ## Where is the Cache Stored? @@ -135,7 +139,7 @@ If you want to ignore the cache (both reads and writes), use the `--skip-nx-cach nx build header --skip-nx-cache ``` -Alternatively if you want to disable caching for a particular task, just make sure it is not part [of the cached targets](/core-features/cache-task-results#define-cacheable-tasks). If [you're using Nx Cloud](/ci/features/remote-cache#skipping-cloud-cache), you might want to use `--no-cloud` to skip remote caching. +Alternatively if you want to disable caching for a particular task, just make sure it is not part [of the cached tasks](/features/cache-task-results#define-cacheable-tasks). If [you're using Nx Cloud](/ci/features/remote-cache#skipping-cloud-cache), you might want to use `--no-cloud` to skip remote caching. ## Clear the Local Cache diff --git a/docs/shared/features/distribute-task-execution.md b/docs/shared/features/distribute-task-execution.md new file mode 100644 index 0000000000000..c489a4da1243c --- /dev/null +++ b/docs/shared/features/distribute-task-execution.md @@ -0,0 +1,82 @@ +# Distribute Task Execution (Nx Agents) + +{% youtube +src="https://youtu.be/XLOUFZeqRpM" +title="Nx Agents in action splitting e2e tests at a file level" + /%} + +**Nx Agents** lets you distribute your CI across many machines with minimal configuration. It comes with features such as dynamically allocating agents based on the size of the PR, flaky task re-running, and intelligent task splitting and distribution. Keep reading to learn more. + +![Distribute Task Execution with Nx Agents](/shared/images/dte/nx-agents-orchestration-diagram.svg) + +For a more thorough explanation of how Nx Agents optimizes your CI pipeline, read this [guide to parallelization and distribution in CI](/ci/concepts/parallelization-distribution). + +## Enabling Nx Agents + +To enable task distribution with Nx Agents, there are two requirements: + +1. Enable version control system integration. The integrations currently available are [GitHub](/ci/recipes/source-control-integration/github), [GitLab](/ci/recipes/source-control-integration/gitlab) and [Bitbucket](/ci/recipes/source-control-integration/bitbucket-cloud). These integrations can be enabled from your [Nx Cloud dashboard](https://nx.app). +2. Add a single line to your CI pipeline configuration. + +Add the `start-ci-run` command to your CI pipeline configuration after checking out the repository and before installing `node_modules`: + +```yaml {% fileName=".github/workflows/main.yaml" %} +# After checkout repository +- name: Start CI run + run: 'npx nx-cloud start-ci-run --distribute-on="8 linux-medium-js" --stop-agents-after="e2e-ci"' +# Before install node_modules +# Run any nx commands as if running on a single machine +``` + +The `--distribute-on` flag instructs Nx Cloud to distribute tasks across 8 agents of type `linux-medium-js`. `linux-medium-js` is the name of the launch template that will be used to provision the agent. The default launch templates [can be found here](https://github.com/nrwl/nx-cloud-workflows/blob/main/launch-templates/linux.yaml) + +## Launch Templates + +You can also define your own "launch templates" (here's an [example from the Nx repo](https://github.com/nrwl/nx/blob/master/.nx/workflows/agents.yaml)): + +```yaml {% fileName=".nx/workflows/agents.yaml" %} +launch-templates: + linux-medium: + resource-class: 'docker_linux_amd64/medium+' + init-steps: + - name: Pnpm Install + script: | + pnpm install --frozen-lockfile + + - name: Install Cypress + script: pnpm exec cypress install + + - name: Install Rust + - ... +``` + +Here are the [available resource classes](https://nx.app/pricing#resource-classes). + +## Related Features + +{% cards %} + +{% card title="Dynamically Allocate Agents" description="Assign a different number of agents to a pipeline based on the size of the PR" type="documentation" url="/ci/features/dynamic-agents" /%} + +{% card title="Automatically Split E2E Tasks" description="Split large e2e tasks into separate tasks for each spec file" type="documentation" url="/ci/features/split-e2e-tasks" /%} + +{% card title="Identify and Re-run Flaky Tasks" description="Re-run flaky tasks in CI whenever they fail" url="/ci/features/flaky-tasks" /%} + +{% /cards %} + +## CI/CD Guides + +Every organization manages their CI/CD pipelines differently, so the guides don't cover org-specific aspects of +CI/CD (e.g., deployment). They mainly focus on configuring Nx correctly using Nx Agents and [Nx Replay](/ci/features/remote-cache). + +- [Azure Pipelines](/ci/recipes/set-up/monorepo-ci-azure#distributed-ci-with-nx-cloud) +- [Circle CI](/ci/recipes/set-up/monorepo-ci-circle-ci#distributed-ci-with-nx-cloud) +- [GitHub Actions](/ci/recipes/set-up/monorepo-ci-github-actions#distributed-ci-with-nx-cloud) +- [Jenkins](/ci/recipes/set-up/monorepo-ci-jenkins#distributed-ci-with-nx-cloud) + +Note that only cacheable operations can be distributed because they have to be replayed on the main job. + +## Relevant Repositories and Examples + +- [Nx: On how to make your CI 16 times faster with a small config change](https://github.com/vsavkin/interstellar) +- ["Lerna & Distributed Task Execution" Example](https://github.com/vsavkin/lerna-dte) diff --git a/docs/shared/core-features/enforce-module-boundaries.md b/docs/shared/features/enforce-module-boundaries.md similarity index 95% rename from docs/shared/core-features/enforce-module-boundaries.md rename to docs/shared/features/enforce-module-boundaries.md index b17cdf85a319f..d4f4779d2de27 100644 --- a/docs/shared/core-features/enforce-module-boundaries.md +++ b/docs/shared/features/enforce-module-boundaries.md @@ -15,30 +15,10 @@ Nx provides an `enforce-module-boundaries` eslint rule that enforces the public To set up the lint rule, install these dependencies: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add @nx/eslint-plugin @nx/devkit -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add @nx/eslint-plugin @nx/devkit +nx add @nx/eslint-plugin @nx/devkit ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add @nx/eslint-plugin @nx/devkit -``` - -{% /tab %} -{% /tabs %} - And configure the rule in your root `.eslintrc.json` file: ```jsonc {% fileName=".eslintrc.json" %} diff --git a/docs/shared/features/explore-graph.md b/docs/shared/features/explore-graph.md new file mode 100644 index 0000000000000..4b5c2263a7d36 --- /dev/null +++ b/docs/shared/features/explore-graph.md @@ -0,0 +1,215 @@ +--- +title: Explore your Workspace +description: 'Learn how Nx helps you understand your workspace by viewing project details, the project graph, and the task graph.' +--- + +# Explore your Workspace + +Nx understands your workspace as a collection of projects. +Each project can be explored to view the different tasks which can be run. + +The projects in the workspace have dependencies between them and form a graph known as the **Project Graph**. +Nx uses this project graph in many ways to make informed decisions such as which tasks to run, when the results of a task can be restored from cache, and more. + +In addition to the project graph, Nx also runs your tasks as a **Task Graph**. +This is a separate graph of tasks and their dependencies which is based on the project graph and determines the way in which the tasks are executed. + +Nx allows you to interactively explore your workspace through a UI which shows the information above. +Using this tool is _vital_ to understanding both your workspace as well as how Nx behaves. + +This guide will teach you to use this tool to explore projects, the project graph, and the task graphs for your workspace. + +## Explore Projects in your Workspace + +Projects in Nx are the different parts of the monorepo which can have tasks run for them. + +The best way to see what projects are in your workspace is to view the [project graph](#explore-the-project-graph) which will be covered in the next section. +Another way is to look at the **Projects** pane in [Nx Console](/features/integrate-with-editors) or run `nx show projects` to show a list of projects in your terminal. + +You can see more details about a specific project in Nx Console or by running `nx show project --web`. Both methods will show something like the example below: + +{% project-details jsonFile="shared/concepts/myreactapp.json"%} +{% /project-details %} + +The view shows a list of targets which can be [run by Nx](/features/run-tasks). +Each target has different options which determine how Nx runs the task. + +## Explore the Project Graph + +Nx understands the projects in your workspace as a graph and uses this understanding to behave intelligently. +Exploring this graph visually is vital to understanding how your code is structured and how Nx behaves. +It always stays up to date without having to actively maintain a document as it is [calculated by analyzing your source code](/concepts/more-concepts/how-project-graph-is-built#how-the-project-graph-is-built) + +### Launching the Project Graph + +To launch the project graph visualization for your workspace, use [Nx Console](/features/integrate-with-editors) or run: + +```shell +npx nx graph +``` + +This will open a browser window with an interactive view of the project graph of your workspace. + +### Focusing on Valuable Projects + +Viewing the entire graph can be unmanageable even for smaller repositories, so there are several ways to narrow the +focus of the visualization down to the most useful part of the graph at the moment. + +1. Focus on a specific project and then use the proximity and group by folder controls in the sidebar to modify the graph around that + project. You can also start the graph with a project focused by running `nx graph --focus `. +2. Use the search bar to find all projects with names that contain a certain string. +3. Manually hide or show projects in the sidebar. + +Once the graph is displayed, you can explore deeper by clicking on nodes and edges in the graph. +Click on a node to show a tooltip which also has a link to view more details about the project. +You can trace the dependency chain between two projects by choosing a **Start** and **End** point in the project tooltips. +Click on any dependency line to find which file(s) created the dependency. + +Try playing around with a [fully interactive graph on a sample repo](https://nrwl-nx-examples-dep-graph.netlify.app/?focus=cart) or look at the more limited example below: + +{% graph height="450px" %} + +```json +{ + "hash": "58420bb4002bb9b6914bdeb7808c77a591a089fc82aaee11e656d73b2735e3fa", + "projects": [ + { + "name": "shared-product-state", + "type": "lib", + "data": { + "tags": ["scope:shared", "type:state"] + } + }, + { + "name": "shared-product-types", + "type": "lib", + "data": { + "tags": ["type:types", "scope:shared"] + } + }, + { + "name": "shared-product-data", + "type": "lib", + "data": { + "tags": ["type:data", "scope:shared"] + } + }, + { + "name": "cart-cart-page", + "type": "lib", + "data": { + "tags": ["scope:cart", "type:feature"] + } + }, + { + "name": "shared-styles", + "type": "lib", + "data": { + "tags": ["scope:shared", "type:styles"] + } + }, + { + "name": "cart-e2e", + "type": "e2e", + "data": { + "tags": ["scope:cart", "type:e2e"] + } + }, + { + "name": "cart", + "type": "app", + "data": { + "tags": ["type:app", "scope:cart"] + } + } + ], + "dependencies": { + "shared-product-state": [ + { + "source": "shared-product-state", + "target": "shared-product-data", + "type": "static" + }, + { + "source": "shared-product-state", + "target": "shared-product-types", + "type": "static" + } + ], + "shared-product-types": [], + "shared-product-data": [ + { + "source": "shared-product-data", + "target": "shared-product-types", + "type": "static" + } + ], + "shared-e2e-utils": [], + "cart-cart-page": [ + { + "source": "cart-cart-page", + "target": "shared-product-state", + "type": "static" + } + ], + "shared-styles": [], + "cart-e2e": [ + { "source": "cart-e2e", "target": "cart", "type": "implicit" } + ], + "cart": [ + { "source": "cart", "target": "shared-styles", "type": "implicit" }, + { "source": "cart", "target": "cart-cart-page", "type": "static" } + ] + }, + "workspaceLayout": { + "appsDir": "apps", + "libsDir": "libs" + }, + "affectedProjectIds": [], + "focus": null, + "groupByFolder": false, + "exclude": [], + "enableTooltips": true +} +``` + +{% /graph %} + +### Export Project Graph to JSON + +If you prefer to analyze the underlying data of the project graph with a script or some other tool, you can run: + +```shell +nx graph --file=output.json +``` + +This will give you all the information that is used to create the project graph visualization. + +### Export the Project Graph as an Image + +There is a floating action button in the bottom right of the project graph view which will save the graph as a `.png` file. +Sharing this image with other developers is a great way to express how a project fits into the workspace. +Some moments which you may want to share these images are: + +- When providing a high-level overview of the workspace +- When introducing new project(s) into the workspace +- When changing how project(s) are related +- To share which other projects are directly affected by changes you are making + +## Explore the Task Graph + +Nx uses the project graph of your workspace to determine the order in which to [run tasks](/features/run-tasks). Pass the `--graph` flag to view the **task graph** which is executed by Nx when running a command. + +```shell +nx build myreactapp --graph # View the graph for building myreactapp +nx run-many -targets build --graph # View the graph for building all projects +nx affected --targets build --graph # View the graph for building the affected projects +``` + +Click on the nodes of this graph to see more information about the task such as: + +- Which executor was used to run the command +- Which [inputs](/recipes/running-tasks/configure-inputs) are used to calculate the computation hash. +- A link to see more details about the project which the task belongs to + +Dependencies in this graph mean that Nx will need to wait for all task dependencies to complete successfully before running the task. diff --git a/docs/shared/plugin-features/use-code-generators.md b/docs/shared/features/generate-code.md similarity index 98% rename from docs/shared/plugin-features/use-code-generators.md rename to docs/shared/features/generate-code.md index 919483436d5a2..b66a44e6a1c2d 100644 --- a/docs/shared/plugin-features/use-code-generators.md +++ b/docs/shared/features/generate-code.md @@ -1,4 +1,4 @@ -# Use Code Generators +# Generate Code Generators provide a way to automate many tasks you regularly perform as part of your development workflow. Whether it is scaffolding out components, features, ensuring libraries are generated and structured in a certain way, or updating your configuration files, generators help you standardize these tasks in a consistent, and predictable manner. diff --git a/docs/shared/core-features/integrate-with-editors.md b/docs/shared/features/integrate-with-editors.md similarity index 100% rename from docs/shared/core-features/integrate-with-editors.md rename to docs/shared/features/integrate-with-editors.md diff --git a/docs/shared/core-features/manage-releases.md b/docs/shared/features/manage-releases.md similarity index 100% rename from docs/shared/core-features/manage-releases.md rename to docs/shared/features/manage-releases.md diff --git a/docs/shared/features/remote-cache.md b/docs/shared/features/remote-cache.md new file mode 100644 index 0000000000000..298e3a0d64aa1 --- /dev/null +++ b/docs/shared/features/remote-cache.md @@ -0,0 +1,67 @@ +# Use Remote Caching (Nx Replay) + +By default Nx [caches task computations locally](/features/cache-task-results). However, to benefit from the cache across your team and in particular on CI, the computation cache can also be distributed across multiple machines. + +The **Nx Replay** feature of Nx Cloud is a fast, secure and zero-config implementation of remote caching. + +![Diagram showing Teika sharing his cache with CI, Kimiko and James](/shared/images/dte/distributed-caching.svg) + +In this diagram, Teika runs the build once on his machine, then CI, Kimiko and James can use the cached artifact from Teika instead of re-executing the same work. + +## Setting Up Nx Cloud + +To use **Nx Replay** you need to connect your workspace to Nx Cloud. See the [connect to Nx Cloud recipe](/ci/recipes/set-up/connect-to-cloud). + +## See Remote Caching in Action + +To see the remote cache in action, run: + +```{% command="nx build header && nx reset && nx build header"%} +> nx run header:build + +> header@0.0.0 build +> rimraf dist && rollup --config + +src/index.tsx → dist... +created dist in 786ms + + ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for project header (2s) + + See logs and investigate cache misses at https://cloud.nx.app/runs/k0HDHACpL8 + + + > NX Resetting the Nx workspace cache and stopping the Nx Daemon. + + This might take a few minutes. + + + > NX Daemon Server - Stopped + + + > NX Successfully reset the Nx workspace. + + +> nx run header:build [remote cache] + + +> header@0.0.0 build +> rimraf dist && rollup --config + + +src/index.tsx → dist... +created dist in 786ms + + ————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + > NX Successfully ran target build for project header (664ms) + + Nx read the output from the cache instead of running the command for 1 out of 1 tasks. + + Nx Cloud made it possible to reuse header: https://nx.app/runs/P0X6ZGTkqZ +``` + +## Skipping Cloud Cache + +Similar to how `--skip-nx-cache` will instruct Nx not to use the local cache, passing `--no-cloud` will tell Nx not to use the remote cache from Nx Cloud. diff --git a/docs/shared/core-features/run-tasks.md b/docs/shared/features/run-tasks.md similarity index 74% rename from docs/shared/core-features/run-tasks.md rename to docs/shared/features/run-tasks.md index e4f2a7eb6bb96..6ff2bd96ad9e2 100644 --- a/docs/shared/core-features/run-tasks.md +++ b/docs/shared/features/run-tasks.md @@ -2,51 +2,11 @@ Monorepos can have hundreds or even thousands of projects, so being able to run actions against all (or some) of them is a key feature of a tool like Nx. -## Definitions +## Types of Tasks -- **Command -** anything the developer types into the terminal (e.g., `nx run header:build`). -- **Target -** the name of an action taken on a project (e.g., `build`) -- **Task -** an invocation of a target on a specific project (e.g., `header:build`). +Nx tasks can be created from existing `package.json` scripts, [inferred from tooling configuration files](/concepts/inferred-tasks), or defined in a `project.json` file. Nx will merge all three sources together to determine the tasks for a particular project. -## Define Tasks - -For these examples, we'll imagine a repo that has three projects: `myapp`, `header` and `footer`. `myapp` is a deployable app and uses the `header` and `footer` libraries. - -Each project has the `test` and `build` targets defined. Tasks can be defined as npm scripts in a project's `package.json` file or as targets in a `project.json` file: - -{% tabs %} -{% tab label="package.json" %} - -```json {% fileName="package.json" %} -{ - "scripts": { - "build": "webpack -c webpack.conf.js", - "test": "jest --coverage" - } -} -``` - -{% /tab %} -{% tab label="project.json" %} - -```json {% fileName="project.json" %} -{ - "targets": { - "build": { - "command": "webpack -c webpack.conf.js" - }, - "test": { - "executor": "@nx/jest:jest", - "options": { - "codeCoverage": true - } - } - } -} -``` - -{% /tab %} -{% /tabs %} +Read the [Project Configuration docs](/reference/project-configuration) to see all the configuration options for a task. ## Running Tasks @@ -56,7 +16,7 @@ Nx uses the following syntax: ### Run a Single Task -To run the `test` target on the `header` project run this command: +To run the `test` task for the `header` project run this command: ```shell npx nx test header @@ -66,19 +26,19 @@ npx nx test header You can use the `run-many` command to run a task for multiple projects. Here are a couple of examples. -Run the `build` target for all projects in the repo: +Run the `build` task for all projects in the repo: ```shell npx nx run-many -t build ``` -Run the `build`, `lint` and `test` target for all projects in the repo: +Run the `build`, `lint` and `test` task for all projects in the repo: ```shell npx nx run-many -t build lint test ``` -Run the `build`, `lint` and `test` target just on the `header` and `footer` projects: +Run the `build`, `lint` and `test` task just on the `header` and `footer` projects: ```shell npx nx run-many -t build lint test -p header footer @@ -102,7 +62,7 @@ Learn more about the affected command [here](/ci/features/affected). It is pretty common to have dependencies between tasks, requiring one task to be run before another. For example, you might want to run the `build` target on the `header` project before running the `build` target on the `app` project. -Nx is already able to automatically understand the dependencies between projects (see [project graph](/core-features/explore-graph)). +Nx is already able to automatically understand the dependencies between projects (see [project graph](/features/explore-graph)). {% graph height="450px" %} diff --git a/docs/shared/getting-started/installation.md b/docs/shared/getting-started/installation.md index d97c52faf9d70..9a106d544ab94 100644 --- a/docs/shared/getting-started/installation.md +++ b/docs/shared/getting-started/installation.md @@ -48,7 +48,7 @@ Once you've created your workspace, you can Run `npx nx run-many -t build` twice to see how Nx's powerful caching speeds up your build. -Learn more about [running tasks](/core-features/run-tasks). +Learn more about [running tasks](/features/run-tasks). ## Installing Nx Into an Existing Repository diff --git a/docs/shared/getting-started/intro.md b/docs/shared/getting-started/intro.md index d9d6defa2c43c..1e80faa4715d4 100644 --- a/docs/shared/getting-started/intro.md +++ b/docs/shared/getting-started/intro.md @@ -4,14 +4,14 @@ Nx is a powerful open-source build system that provides tools and techniques for ## Core Features -- **Run Tasks Efficiently**: Nx [runs tasks in parallel](/core-features/run-tasks) and orders the tasks based on the dependencies between them. -- **Cache Locally & Remotely**: With [local](/core-features/cache-task-results) and [remote caching](/ci/features/remote-cache), Nx prevents unnecessary re-runs of tasks, saving you valuable dev time. -- **Automate Dependency Updates**: if you leverage Nx plugins you gain additional features such as [code generation](/core-features/plugin-features/use-code-generators) and tools to [automatically upgrade](core-features/automate-updating-dependencies) your codebase and dependencies. +- **Run Tasks Efficiently**: Nx [runs tasks in parallel](/features/run-tasks) and orders the tasks based on the dependencies between them. +- **Cache Locally & Remotely**: With [local](/features/cache-task-results) and [remote caching](/ci/features/remote-cache), Nx prevents unnecessary re-runs of tasks, saving you valuable dev time. +- **Automate Dependency Updates**: if you leverage Nx plugins you gain additional features such as [code generation](/features/generate-code) and tools to [automatically upgrade](features/automate-updating-dependencies) your codebase and dependencies. - **Make it Your Own**: Nx is highly customizable and extensible. Fine-tune it by [creating your own plugins](/extending-nx/intro/getting-started) and optionally [share them with the community](/extending-nx/tutorials/publish-plugin#publish-your-nx-plugin). -Find out more about [why you should use Nx](/getting-started/why-nx) or browse our [core features](/core-features). +Find out more about [why you should use Nx](/getting-started/why-nx) or browse our [features](/features). ## Try Nx Yourself! @@ -47,9 +47,7 @@ npx create-nx-workspace@latest +{% link-card title="Angular Monorepo" type="tutorial" url="/getting-started/tutorials/angular-standalone-tutorial" icon="angularMono" /%}--> {% /cards %} diff --git a/docs/shared/getting-started/why-nx.md b/docs/shared/getting-started/why-nx.md index 639f3dbc6bb58..823a312282acc 100644 --- a/docs/shared/getting-started/why-nx.md +++ b/docs/shared/getting-started/why-nx.md @@ -27,11 +27,11 @@ Nx is built in a modular fashion to let you only use the features you need. ![High-level Nx architecture](/shared/images/nx-architecture.svg) -- The **Nx** package provides fundamental technology-agnostic capabilities such as: [workspace analysis](/core-features/explore-graph), [task running](/core-features/run-tasks), [caching](/core-features/cache-task-results), [distribution](/ci/features/distribute-task-execution), [code generation](/core-features/plugin-features/use-code-generators) and [automated code migrations](/core-features/automate-updating-dependencies). -- **Plugins** are NPM packages that built on top of the fundamental capabilities provided by the Nx package. Nx plugins contain [code generators](/core-features/plugin-features/use-code-generators), [executors](/core-features/plugin-features/use-task-executors) (to abstract lower-level build tooling) and automated code migrations for keeping your tools up to date. Contrary to the Nx package, which works the same way with any JS or non-JS project, plugins are usually technology specific. For instance, `@nx/react` adds support for building React apps and libs, `@nx/cypress` adds e2e testing capabilities with Cypress. Plugins make developers more productive by removing any friction of integrating different tools with each other and by providing utilities to keep them up to date. The Nx team maintains plugins for React, Next, Remix, Angular, Jest, Cypress, Storybook and more. You can use the `@nx/plugin` package to easily [scaffold a new plugin](/extending-nx/intro/getting-started) or even just [automate your local workspace](/extending-nx/recipes/local-generators). There are also more than 80 [community plugins](/plugin-registry). +- The **Nx** package provides fundamental technology-agnostic capabilities such as: [workspace analysis](/features/explore-graph), [task running](/features/run-tasks), [caching](/features/cache-task-results), [distribution](/ci/features/distribute-task-execution), [code generation](/features/generate-code) and [automated code migrations](/features/automate-updating-dependencies). +- **Plugins** are NPM packages that build on top of the fundamental capabilities provided by the Nx package. Nx plugins contain [code generators](/features/generate-code), [executors](/concepts/executors-and-configurations) (to abstract lower-level build tooling) and automated code migrations for keeping your tools up to date. Contrary to the Nx package, which works the same way with any JS or non-JS project, plugins are usually technology specific. For instance, `@nx/react` adds support for building React apps and libs, `@nx/cypress` adds e2e testing capabilities with Cypress. Plugins make developers more productive by removing any friction of integrating different tools with each other and by providing utilities to keep them up to date. The Nx team maintains plugins for React, Next, Remix, Angular, Jest, Cypress, Storybook and more. You can use the `@nx/plugin` package to easily [scaffold a new plugin](/extending-nx/intro/getting-started) or even just [automate your local workspace](/extending-nx/recipes/local-generators). There are also more than 80 [community plugins](/plugin-registry). - **Devkit** is a set of utilities for [building Nx plugins](/extending-nx/intro/getting-started). - **Nx Cloud** helps scale your project on CI by [adding remote caching](/concepts/how-caching-works) and [distributed task execution](/concepts/more-concepts/illustrated-dte). It also improves developer ergonomics by integrating with GitHub, GitLab and BitBucket and providing searchable structured logs. Learn more at [nx.app](https://nx.app). -- **Nx Console** is an extension for **VSCode, IntelliJ and VIM**. It provides code autocompletion, interactive generators, workspace visualizations, powerful refactorings and more. You can [install it here](/core-features/integrate-with-editors). +- **Nx Console** is an extension for **VSCode, IntelliJ and VIM**. It provides code autocompletion, interactive generators, workspace visualizations, powerful refactorings and more. You can [install it here](/features/integrate-with-editors). ## How can I adopt Nx in my existing project? @@ -41,6 +41,6 @@ As shown in the section before, there's a core [nx package](https://www.npmjs.co npx nx@latest init ``` -By adding the `nx` package you can use [Nx commands](/core-features/run-tasks) to run your `package.json` scripts and benefit from running tasks in parallel as well as [caching](/core-features/cache-task-results). Over time you can then also add in Nx Plugins to further enhance your experience when working with specific tech stacks. +By adding the `nx` package you can use [Nx commands](/features/run-tasks) to run your `package.json` scripts and benefit from running tasks in parallel as well as [caching](/features/cache-task-results). Over time you can then also add in Nx Plugins to further enhance your experience when working with specific tech stacks. Check out our [migration guides](/recipes/adopting-nx) for all the details. diff --git a/docs/shared/guides/module-federation/faster-builds.md b/docs/shared/guides/module-federation/faster-builds.md index 7405c8752f6e5..f504bae95386a 100644 --- a/docs/shared/guides/module-federation/faster-builds.md +++ b/docs/shared/guides/module-federation/faster-builds.md @@ -89,42 +89,14 @@ take advantage of remote caching and other features it provides. Then, for React users, install the `@nx/react` plugin; and for Angular users, install the `@nx/angular` plugin. -{% tabs %} -{% tab label="npm" %} - ```shell # If you use React -npm add -D @nx/react +nx add @nx/react # If you use Angular -npm add -D @nx/angular +nx add @nx/angular ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -# If you use React -yarn add -D @nx/react - -# If you use Angular -yarn add -D @nx/angular -``` - -{% /tab %} -{% tab label="pnpm" %} - -```shell -# If you use React -pnpm add -D @nx/react - -# If you use Angular -pnpm add -D @nx/angular -``` - -{% /tab %} -{% /tabs %} - Next, generate the host and remote applications. {% tabs %} diff --git a/docs/shared/guides/nx-and-angular-cli.md b/docs/shared/guides/nx-and-angular-cli.md index e07eb02fbfb6f..b17bd2b29b57b 100644 --- a/docs/shared/guides/nx-and-angular-cli.md +++ b/docs/shared/guides/nx-and-angular-cli.md @@ -23,30 +23,30 @@ Note, the Nx team's focus is on building the best possible developer productivit Here's a quick side-by-side overview comparing the features between the Angular CLI and Nx. _(Kudos to [Daniel Glejzner](https://twitter.com/DanielGlejzner) for helping with this)_ -| Feature/Tool | Angular CLI | Nx | -| ---------------------------------------------------------------------------------------------------------- | --------------- | ------------- | -| Create Angular Apps | ✅ | ✅ | -| Generate Angular Components, Services, etc. | ✅ | ✅ | -| Building & Bundling | ✅ | ✅ | -| Local Development Server | ✅ | ✅ | -| Code Schematics | ✅ | ✅ | -| Automated Update with Migrations | ✅ | ✅ (Enhanced) | -| Generators | ✅ (Schematics) | ✅ | -| Executors | ✅ (Builders) | ✅ | -| Advanced Generators (e.g. Module Federation, Tailwind,...) | ❌ | ✅ | -| Integrated Tooling (Jest, Cypress, Playwright etc.) | ❌ | ✅ | -| Support for [single-project Workspaces](/getting-started/tutorials/angular-standalone-tutorial) | ✅ | ✅ | -| First-Class [Monorepo Support](/getting-started/tutorials/angular-monorepo-tutorial) | ❌\* | ✅ | -| [Enforced Module Boundaries](/core-features/enforce-module-boundaries) | ❌ | ✅ | -| Interactive [Project Graph](/core-features/explore-graph) | ❌ | ✅ | -| Task Graph | ❌ | ✅ | -| [Running Tasks in Parallel](/recipes/running-tasks/run-tasks-in-parallel) | ❌ | ✅ | -| Building, Testing [Only What is Affected](/core-features/run-tasks#run-tasks-on-projects-affected-by-a-pr) | ❌ | ✅ | -| [Local Caching](/core-features/cache-task-results) | ❌\*\* | ✅ | -| [Remote Caching](/ci/features/remote-cache) | ❌ | ✅ | -| [Distributed Task Execution on CI](/ci/features/distribute-task-execution) | ❌ | ✅ | -| Custom Hashers | ❌ | ✅ | -| [Extensible Plugin System](/extending-nx/intro/getting-started) | ❌ | ✅ | +| Feature/Tool | Angular CLI | Nx | +| ----------------------------------------------------------------------------------------------------- | --------------- | ------------- | +| Create Angular Apps | ✅ | ✅ | +| Generate Angular Components, Services, etc. | ✅ | ✅ | +| Building & Bundling | ✅ | ✅ | +| Local Development Server | ✅ | ✅ | +| Code Schematics | ✅ | ✅ | +| Automated Update with Migrations | ✅ | ✅ (Enhanced) | +| Generators | ✅ (Schematics) | ✅ | +| Executors | ✅ (Builders) | ✅ | +| Advanced Generators (e.g. Module Federation, Tailwind,...) | ❌ | ✅ | +| Integrated Tooling (Jest, Cypress, Playwright etc.) | ❌ | ✅ | +| Support for [single-project Workspaces](/getting-started/tutorials/angular-standalone-tutorial) | ✅ | ✅ | +| First-Class [Monorepo Support](/getting-started/tutorials/angular-monorepo-tutorial) | ❌\* | ✅ | +| [Enforced Module Boundaries](/features/enforce-module-boundaries) | ❌ | ✅ | +| Interactive [Project Graph](/features/explore-graph) | ❌ | ✅ | +| Task Graph | ❌ | ✅ | +| [Running Tasks in Parallel](/recipes/running-tasks/run-tasks-in-parallel) | ❌ | ✅ | +| Building, Testing [Only What is Affected](/features/run-tasks#run-tasks-on-projects-affected-by-a-pr) | ❌ | ✅ | +| [Local Caching](/features/cache-task-results) | ❌\*\* | ✅ | +| [Remote Caching](/ci/features/remote-cache) | ❌ | ✅ | +| [Distributed Task Execution on CI](/ci/features/distribute-task-execution) | ❌ | ✅ | +| Custom Hashers | ❌ | ✅ | +| [Extensible Plugin System](/extending-nx/intro/getting-started) | ❌ | ✅ | {% callout type="info" title="Notes" %} @@ -118,7 +118,7 @@ More details: Nx [project configuration](/reference/project-configuration). Nx comes with slightly different terminology than the Angular CLI for some features. -**Angular Builders** are called [Executors](/core-features/plugin-features/use-task-executors) in Nx but work very much similarly. You use them in your project configuration to define how to build, test, lint, and serve your project. You can use both Nx executors from [Nx Plugins](/plugin-registry) or Angular Builders from the Angular Devkit. +**Angular Builders** are called [Executors](/concepts/executors-and-configurations) in Nx but work very much similarly. You use them in your project configuration to define how to build, test, lint, and serve your project. You can use both Nx executors from [Nx Plugins](/plugin-registry) or Angular Builders from the Angular Devkit. ```json { @@ -134,7 +134,7 @@ Nx comes with slightly different terminology than the Angular CLI for some featu } ``` -**Angular Schematics** are called [Generators](/core-features/plugin-features/use-code-generators) in Nx. You can invoke them in the same way as you would with the Angular CLI, but you use the `nx` command instead of `ng`: +**Angular Schematics** are called [Generators](/features/generate-code) in Nx. You can invoke them in the same way as you would with the Angular CLI, but you use the `nx` command instead of `ng`: ```shell npx nx g @nx/angular:component my-component @@ -154,7 +154,7 @@ Commands are run in the very same way as with the Angular CLI. You just switch ` npx nx serve ``` -Nx has more abilities to run commands in parallel, just for specific projects etc. Find out more [in the docs](/core-features/run-tasks). +Nx has more abilities to run commands in parallel, just for specific projects etc. Find out more [in the docs](/features/run-tasks). ### Integrating with Modern Tools @@ -189,7 +189,7 @@ What's the difference? `nx migrate` does this by splitting the process into two steps. `nx migrate latest` creates a `migrations.json` file with a list of all the migrations needed by Nx, Angular, and other packages. You can then modify that file before running `nx migrate --run-migrations` to execute those migrations. -To reiterate: `nx migrate` runs the migrations written by the Angular team the same way `ng update` runs them. So everything should still work. You just get more control over how it works. You can learn more in our docs about [Automate Updating Dependencies](/core-features/automate-updating-dependencies). +To reiterate: `nx migrate` runs the migrations written by the Angular team the same way `ng update` runs them. So everything should still work. You just get more control over how it works. You can learn more in our docs about [Automate Updating Dependencies](/features/automate-updating-dependencies). ### 'ng add' @@ -210,16 +210,16 @@ Nx is designed to be fast. The Angular CLI leverages Webpack's caching, which Nx Features like - only running tasks on [affected projects](/ci/features/affected) -- running [tasks in parallel](/core-features/run-tasks#run-tasks-for-multiple-projects) -- applying [computation caching](/core-features/cache-task-results) +- running [tasks in parallel](/features/run-tasks#run-tasks-for-multiple-projects) +- applying [computation caching](/features/cache-task-results) - offering [remote caching abilities](/ci/features/remote-cache) on CI -- offering [task distribution across machines (DTE)](/ci/features/distribute-task-execution) +- offering [task distribution across machines (Nx Agents)](/ci/features/distribute-task-execution) And, Nx already uses fast, modern tooling like [ESBuild](/nx-api/esbuild), [Vite](/nx-api/vite), Vitest and [Rspack](/nx-api/rspack) for non-Angular stacks. So once Angular is ready to use these tools, Nx will also be ready. ### Editor Integration -Nx goes beyond being just a CLI and comes with [Nx Console](/core-features/integrate-with-editors), a VSCode and WebStorm extension allowing you to run commands, generate code and visualize your workspace. +Nx goes beyond being just a CLI and comes with [Nx Console](/features/integrate-with-editors), a VSCode and WebStorm extension allowing you to run commands, generate code and visualize your workspace. ![Nx Console screenshot](/shared/images/nx-console/nx-console-screenshot.webp) @@ -228,13 +228,13 @@ Nx goes beyond being just a CLI and comes with [Nx Console](/core-features/integ Nx is really made to scale with you. You can - start small with a single-project workspace -- modularize your application into more fine-grained libraries for better maintainability as your application (and team) grows ([more about that here](/getting-started/tutorials/angular-standalone-tutorial#modularizing-your-angular-app-with-local-libraries)), including mechanisms to make sure [things stay within their boundaries](/core-features/enforce-module-boundaries) +- modularize your application into more fine-grained libraries for better maintainability as your application (and team) grows ([more about that here](/getting-started/tutorials/angular-standalone-tutorial#modularizing-your-angular-app-with-local-libraries)), including mechanisms to make sure [things stay within their boundaries](/features/enforce-module-boundaries) - you can then migrate to a monorepo when you are ready and need one ([more here](/recipes/tips-n-tricks/standalone-to-integrated)) - or even [add Webpack Module Federation support](/recipes/angular/module-federation-with-ssr) ### Visualize your Workspace -As you start modularizing your Angular workspace, Nx can visualize it using the `nx graph` command or via [Nx Console](/core-features/integrate-with-editors) directly in your editor. +As you start modularizing your Angular workspace, Nx can visualize it using the `nx graph` command or via [Nx Console](/features/integrate-with-editors) directly in your editor. {% graph height="450px" %} @@ -344,7 +344,7 @@ As you start modularizing your Angular workspace, Nx can visualize it using the {% /graph %} -Learn more about the [graph features here](/core-features/explore-graph). +Learn more about the [graph features here](/features/explore-graph). ### Extensible and Customizable: Make it fit your own needs diff --git a/docs/shared/guides/react-native.md b/docs/shared/guides/react-native.md index f8004962aa163..32931207ee202 100644 --- a/docs/shared/guides/react-native.md +++ b/docs/shared/guides/react-native.md @@ -134,30 +134,10 @@ When using React Native in Nx, you get the out-of-the-box support for TypeScript For existing Nx workspaces, install the `@nx/react-native` package to add React Native capabilities to it. -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/react-native -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/react-native +nx add @nx/react-native ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/react-native -``` - -{% /tab %} -{% /tabs %} - ## Generating an Application To create additional React Native apps run: diff --git a/docs/shared/guides/remix.md b/docs/shared/guides/remix.md index e9a5e0ce5ac07..e2bf389b3b6b6 100644 --- a/docs/shared/guides/remix.md +++ b/docs/shared/guides/remix.md @@ -31,30 +31,10 @@ In this recipe, we'll show you how to create a [Remix](https://remix.run) applic Make sure to install the `@nx/remix` version that is on the same minor version as the `nx` version in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/remix -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/remix +nx add @nx/remix ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/remix -``` - -{% /tab %} -{% /tabs %} - ## Generate a Remix Application {% callout type="note" title="Directory Flag Behavior Changes" %} diff --git a/docs/shared/guides/turbo-and-nx.md b/docs/shared/guides/turbo-and-nx.md index 07d5d7e130131..cb32d05390f22 100644 --- a/docs/shared/guides/turbo-and-nx.md +++ b/docs/shared/guides/turbo-and-nx.md @@ -32,7 +32,7 @@ The starting point of any non-trivial monorepo management tool is to be able to - Turborepo only analyzes package.json files to understand how projects relate to each other. Built-in Nx plugins also analyze package.json files but in addition they analyze JS/TS files, so you don't have to have bogus package.json files (that you don’t use for the purposes of installing packages or publishing) in your repo. There are plugins for Nx that do that for other languages (e.g., Golang, .Net). - Since the computation of the project graph can take a lot of time for complex workspaces, both Nx and Turborepo have a daemon process to create the graph in the background. -- **Nx has [module boundary rules](/core-features/enforce-module-boundaries), which are essential for any monorepo with multiple teams contributing.** You can say that some things in the monorepo are private to your team so they cannot be depended on by other teams. Turborepo doesn't have project boundary rules. **Project boundary rules prevent the monorepo from becoming a “big ball of mud”.** +- **Nx has [module boundary rules](/features/enforce-module-boundaries), which are essential for any monorepo with multiple teams contributing.** You can say that some things in the monorepo are private to your team so they cannot be depended on by other teams. Turborepo doesn't have project boundary rules. **Project boundary rules prevent the monorepo from becoming a “big ball of mud”.** #### 3. Project graph visualization @@ -89,7 +89,7 @@ If you want to learn more, check out our article on [Distributing CI - Binning a All the available Nx commands can be executed via the command line. But as your monorepo grows, with multiple teams and hundreds of projects, even just finding the project to run a command against can sometimes be difficult. Having a high quality IDE integration can be a time saver there. -- Nx has [VSCode](/core-features/integrate-with-editors) and WebStorm/Intellij plugins. +- Nx has [VSCode](/features/integrate-with-editors) and WebStorm/Intellij plugins. - Turborepo doesn’t have any plugins, and the maintainer has indicated there's no intention to provide editor support. Learn more [by watching this Egghead lesson](https://egghead.io/lessons/javascript-generate-new-projects-for-nx-with-nx-console). diff --git a/docs/shared/guides/using-tailwind-css-in-react.md b/docs/shared/guides/using-tailwind-css-in-react.md index 66abbcab6463b..d55b0785c8206 100644 --- a/docs/shared/guides/using-tailwind-css-in-react.md +++ b/docs/shared/guides/using-tailwind-css-in-react.md @@ -160,7 +160,7 @@ By specifying the `postcssConfig` option, the PostCSS and Tailwind configuration If your libraries have their own `postcss.config.js` and `tailwind.config.js` files then you should not use the `postcssConfig` option. Doing so will ignore the library-specific configuration and apply the application's configuration to everything. {%/ callout %} -{% short-embeds %} + diff --git a/docs/shared/guides/why-monorepos.md b/docs/shared/guides/why-monorepos.md index 9a7fe8c736d6e..d853aa269a370 100644 --- a/docs/shared/guides/why-monorepos.md +++ b/docs/shared/guides/why-monorepos.md @@ -2,10 +2,6 @@ A monorepo is a single git repository that holds the source code for multiple applications and libraries, along with the tooling for them. -{% callout type="note" title="Lerna users" %} -If you are familiar with Lerna or Yarn workspaces, check out [this guide](/recipes/adopting-nx/lerna-and-nx) (with a quick video) showing how to add Nx to a Lerna/Yarn workspace, what the difference is, when to use both and when to use just Nx. -{% /callout %} - ## What are the benefits of a monorepo? - **Shared code and visibility** - [Keeps your code DRY across your entire organization.](/concepts/more-concepts/code-sharing) Reuse validation code, UI components, and types across the codebase. Reuse code between the backend, the frontend, and utility libraries. diff --git a/docs/shared/images/dte/nx-agents-orchestration-diagram.svg b/docs/shared/images/dte/nx-agents-orchestration-diagram.svg new file mode 100644 index 0000000000000..a14627805b3d2 --- /dev/null +++ b/docs/shared/images/dte/nx-agents-orchestration-diagram.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/shared/images/nx-console/console-pdv-example.png b/docs/shared/images/nx-console/console-pdv-example.png new file mode 100644 index 0000000000000..a561fcd8a3d82 Binary files /dev/null and b/docs/shared/images/nx-console/console-pdv-example.png differ diff --git a/docs/shared/mental-model.md b/docs/shared/mental-model.md index b8ea480efa187..0c198af24d214 100644 --- a/docs/shared/mental-model.md +++ b/docs/shared/mental-model.md @@ -206,7 +206,7 @@ terminal outputs. After `nx affected --build` completes, the machine will have the build files and all the terminal outputs as if it ran it locally. -![DTE](/shared/mental-model/dte.svg) +![Distribution](/shared/mental-model/dte.svg) ## In summary diff --git a/docs/shared/mental-model/large-tasks.json b/docs/shared/mental-model/large-tasks.json index 2010d74a49f73..8e0e215e5720a 100644 --- a/docs/shared/mental-model/large-tasks.json +++ b/docs/shared/mental-model/large-tasks.json @@ -25604,35 +25604,35 @@ "hash": "7ddbbe458aa28ac3d300aa3290a008e3b3ce7aa6" }, { - "file": "docs/shared/core-features/automate-updating-dependencies.md", + "file": "docs/shared/features/automate-updating-dependencies.md", "hash": "32f1e2e43f7cf7ef9c2f162e5ad63ccf15f9c658" }, { - "file": "docs/shared/core-features/cache-task-results.md", + "file": "docs/shared/features/cache-task-results.md", "hash": "7e692804ac1e438bf36f214f1284eb5e6c49d660" }, { - "file": "docs/shared/core-features/distribute-task-execution.md", + "file": "docs/shared/features/distribute-task-execution.md", "hash": "2a7d639f85a227a7b4d06f987076a3524b57ddc6" }, { - "file": "docs/shared/core-features/enforce-project-boundaries.md", + "file": "docs/shared/features/enforce-project-boundaries.md", "hash": "abe5cb6c8134b9f86b448ae09dc6626c395caf95" }, { - "file": "docs/shared/core-features/explore-graph.md", + "file": "docs/shared/features/explore-graph.md", "hash": "57082bdf506236cbaea7f156d1ea12645934ece4" }, { - "file": "docs/shared/core-features/integrate-with-editors.md", + "file": "docs/shared/features/integrate-with-editors.md", "hash": "eb249de959b95a89756a17dd6619fcb35a732755" }, { - "file": "docs/shared/core-features/run-tasks.md", + "file": "docs/shared/features/run-tasks.md", "hash": "5bd43a870de93b1f61b70cbb1205e0ed91acc373" }, { - "file": "docs/shared/core-features/share-your-cache.md", + "file": "docs/shared/features/share-your-cache.md", "hash": "ad3cfb6248f290bd318e49e8e1adc5d9642d9fbe" }, { @@ -26304,11 +26304,11 @@ "hash": "a4e80b452e842221db731af4c12a60126b7944a0" }, { - "file": "docs/shared/plugin-features/use-code-generators.md", + "file": "docs/shared/plugin-features/generate-code.md", "hash": "3b17ca24ace1ab26e45bf26274a67142c7c3ddfa" }, { - "file": "docs/shared/plugin-features/use-task-executors.md", + "file": "docs/shared/plugin-features/enhance-tooling.md", "hash": "fd1b51d3ff445b16f65599e7c160e221a1eb7c9a" }, { diff --git a/docs/shared/migration/adding-to-existing-project.md b/docs/shared/migration/adding-to-existing-project.md index 0300dbb72b809..698e5773d19a3 100644 --- a/docs/shared/migration/adding-to-existing-project.md +++ b/docs/shared/migration/adding-to-existing-project.md @@ -1,19 +1,14 @@ # Adding Nx to your Existing Project -{% youtube -src="https://www.youtube.com/embed/VmGCZ77ao_I" -title="Add Nx to any project" -width="100%" /%} - Nx can be added to any type of project, not just monorepos. The main benefit is to get caching abilities for the package scripts. Each project usually has a set of scripts in the `package.json`: ```json {% fileName="package.json" %} { ... "scripts": { - "build": "tsc -p tsconfig.json", - "test": "jest", - "lint": "eslint . --ext .ts", + "build": "next build", + "lint": "eslint ./src", + "test": "node ./run-tests.js" } } ``` @@ -23,7 +18,7 @@ You can make these scripts faster by leveraging Nx's caching capabilities. For e - You change some spec files: in that case the `build` task can be cached and doesn't have to re-run. - You update your docs, changing a couple of markdown files: then there's no need to re-run builds, tests, linting on your CI. All you might want to do is trigger the Docusaurus build. -## Installing Nx on a Non-Monorepo Project +## Install Nx on a Non-Monorepo Project Run the following command: @@ -31,126 +26,233 @@ Run the following command: npx nx@latest init ``` -This will - -- collect all the NPM scripts in the corresponding `package.json` files of your workspace packages -- ask you which of those scripts are cacheable (e.g. build, test, lint) -- ask you which of those scripts might need to be run in a certain order (e.g. if you run the `build` script you might want to first build all the dependent projects) -- ask you for custom output folders that should be captured as part of the caching - -This process adds `nx` to your `package.json` at the root of your workspace: - -```json {% fileName="package.json" %} -{ - "name": "my-workspace", - ... - "devDependencies": { - ... - "nx": "17.2.0" - } -} -``` - -In addition it generates a `nx.json` based on your answers during the setup process. This includes cacheable targets as well as some initial definition of the task pipeline. Here is an example: - -{% tabs %} -{% tab label="Nx >= 17" %} +This will set up Nx for you - updating the `package.json` file and creating a new `nx.json` file with Nx configuration based on your answers during the set up process. The set up process will suggest installing Nx plugins that might be useful based on your existing repository. The example below is using the `@nx/eslint` and `@nx/next` plugins to run ESLint and Next.js tasks with Nx: ```json {% fileName="nx.json" %} { - "targetDefaults": { - "build": { - "cache": true + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } }, - "lint": { - "cache": true + { + "plugin": "@nx/next/plugin", + "options": { + "buildTargetName": "build", + "devTargetName": "dev", + "startTargetName": "start" + } } - } + ] } ``` -{% /tab %} -{% tab label="Nx < 17" %} +When Nx updates your `package.json` scripts, it looks for scripts that can be replaced with an Nx command that has caching automatically enabled. The `package.json` defined above would be updated to look like this: -```json {% fileName="nx.json" %} +```json {% fileName="package.json" %} { - "tasksRunnerOptions": { - "default": { - "runner": "nx/tasks-runners/default", - "options": { - "cacheableOperations": ["build", "lint"] - } - } + "name": "my-workspace", + ... + "scripts": { + "build": "nx build", + "lint": "nx lint", + "test": "node ./run-tests.js" + }, + ... + "nx": { + "includedScripts": [] } } ``` -{% /tab %} -{% /tabs %} +The `@nx/next` plugin can run `next build` for you and set up caching correctly, so it replaces `next build` with `nx build`. Similarly, `@nx/eslint` can set up caching for `eslint ./src`. When you run `npm run build` or `npm run lint` multiple times, you'll see that caching is enabled. You can also call Nx directly from the terminal with `nx build` or `nx lint`. -## Wrapping Cacheable Scripts +The `test` script was not recognized by any Nx plugin, so it was left as is. -Nx also automatically wraps your cacheable scripts with the `nx exec` command. The main advantage here is that you can still keep using `npm start` or `npm run build` (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheble. +The `includedScripts` array allows you to specify `package.json` scripts that can be run with the `nx build` syntax. -Here's an example of a `build` and `lint` script being wrapped by Nx: +## Inferred Tasks -```json {% fileName="package.json" %} +You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `build` task. Those tasks were created by the `@nx/next` plugin from your existing Next.js configuration. To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project details in a browser window. + +```shell +nx show project my-workspace --web +``` + +{% project-details title="Project Details View" height="100px" %} + +```json { - ... - "scripts": { - "build": "nx exec -- vite build", - "lint": "nx exec -- eslint \"src/**/*.ts*\"", - ... - "dev": "vite", - "start": "vite --open", + "project": { + "name": "my-workspace", + "data": { + "root": ".", + "targets": { + "lint": { + "cache": true, + "options": { + "cwd": ".", + "command": "eslint ./src" + }, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "configurations": {} + }, + "build": { + "options": { + "cwd": ".", + "command": "next build" + }, + "dependsOn": ["^build"], + "cache": true, + "inputs": [ + "default", + "^default", + { + "externalDependencies": ["next"] + } + ], + "outputs": ["{projectRoot}/.next", "{projectRoot}/.next/!(cache)"], + "executor": "nx:run-commands", + "configurations": {} + }, + "dev": { + "options": { + "cwd": ".", + "command": "next dev" + }, + "executor": "nx:run-commands", + "configurations": {} + }, + "start": { + "options": { + "cwd": ".", + "command": "next start" + }, + "dependsOn": ["build"], + "executor": "nx:run-commands", + "configurations": {} + } + }, + "sourceRoot": ".", + "name": "my-workspace", + "projectType": "library", + "includedScripts": [], + "implicitDependencies": [], + "tags": [] + } }, - "devDependencies": { - ... - "nx": "17.2.0" + "sourceMap": { + "root": ["package.json", "nx/core/package-json-workspaces"], + "targets": ["package.json", "nx/core/package-json-workspaces"], + "targets.lint": ["package.json", "@nx/eslint/plugin"], + "targets.lint.command": ["package.json", "@nx/eslint/plugin"], + "targets.lint.cache": ["package.json", "@nx/eslint/plugin"], + "targets.lint.options": ["package.json", "@nx/eslint/plugin"], + "targets.lint.inputs": ["package.json", "@nx/eslint/plugin"], + "targets.lint.options.cwd": ["package.json", "@nx/eslint/plugin"], + "targets.build": ["next.config.js", "@nx/next/plugin"], + "targets.build.command": ["next.config.js", "@nx/next/plugin"], + "targets.build.options": ["next.config.js", "@nx/next/plugin"], + "targets.build.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.build.cache": ["next.config.js", "@nx/next/plugin"], + "targets.build.inputs": ["next.config.js", "@nx/next/plugin"], + "targets.build.outputs": ["next.config.js", "@nx/next/plugin"], + "targets.build.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.dev": ["next.config.js", "@nx/next/plugin"], + "targets.dev.command": ["next.config.js", "@nx/next/plugin"], + "targets.dev.options": ["next.config.js", "@nx/next/plugin"], + "targets.dev.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.start": ["next.config.js", "@nx/next/plugin"], + "targets.start.command": ["next.config.js", "@nx/next/plugin"], + "targets.start.options": ["next.config.js", "@nx/next/plugin"], + "targets.start.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.start.options.cwd": ["next.config.js", "@nx/next/plugin"], + "sourceRoot": ["package.json", "nx/core/package-json-workspaces"], + "name": ["package.json", "nx/core/package-json-workspaces"], + "projectType": ["package.json", "nx/core/package-json-workspaces"], + "includedScripts": ["package.json", "nx/core/package-json-workspaces"], + "targets.nx-release-publish": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.dependsOn": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.executor": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.options": [ + "package.json", + "nx/core/package-json-workspaces" + ] } } ``` -{% callout type="note" title="Use Nx commands directly" %} +{% /project-details %} -Alternatively you could obviously also just switch to using `nx` for invoking the commands. Like `nx build` rather than `npm run build`. +The project detail view lists all available tasks, the configuration values for those tasks and where those configuration values are being set. -{% /callout %} +## Configure an Existing Script to Run with Nx -## Fine-tuning caching with Nx Inputs +If you want to run one of your existing scripts with Nx, you need to tell Nx about it. -To get the best caching results, you can customize which inputs should be accounted for when it comes to caching certain commands. This can be done in your `nx.json`. +1. Preface the script with `nx exec -- ` to have `npm run test` invoke the command with Nx. +2. Add the script to `includedScripts`. +3. Define caching settings. -For example, excluding markdown files from the `lint` task cache: +The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script from the example above to run with Nx would look something like this: -```json {% fileName="nx.json" %} +```json {% fileName="package.json" %} { + "name": "my-workspace", ... - "targetDefaults": { - "lint": { - "inputs": ["{projectRoot}/**/*.ts","!**/*.md"] + "scripts": { + "build": "nx build", + "lint": "nx lint", + "test": "nx exec -- node ./run-tests.js" + }, + ... + "nx": { + "includedScripts": ["test"], + "targets": { + "test": { + "cache": "true", + "inputs": ["default", "^default"], + "outputs": [] + } } } } ``` -This includes all TypeScript files, but excludes markdown files. As a result, changing your README won't invalidate your "lint cache". - -Learn more about [Nx Inputs](/recipes/running-tasks/customizing-inputs). +Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in this example are as cautious as possible, so you can significantly improve the value of the cache by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. ## Learn More {% cards %} -{% card title="Customizing Inputs and Named Inputs" description="Learn more about how to fine-tune caching with custom inputs" type="documentation" url="/recipes/running-tasks/customizing-inputs" /%} +{% card title="Customizing Inputs and Named Inputs" description="Learn more about how to fine-tune caching with custom inputs" type="documentation" url="/recipes/running-tasks/configure-inputs" /%} -{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/core-features/cache-task-results" /%} +{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/features/cache-task-results" /%} {% card title="Adding Nx to NPM/Yarn/PNPM Workspace" description="Learn more about how to add Nx to an existing monorepo" type="documentation" url="/recipes/adopting-nx/adding-to-monorepo" /%} {% /cards %} -{% short-embeds %} + diff --git a/docs/shared/migration/adding-to-monorepo.md b/docs/shared/migration/adding-to-monorepo.md index 82bd654fb8ab1..8329bda4c3b74 100644 --- a/docs/shared/migration/adding-to-monorepo.md +++ b/docs/shared/migration/adding-to-monorepo.md @@ -4,13 +4,13 @@ Interested in migrating from [Lerna](https://github.com/lerna/lerna) in particular? In case you missed it, Lerna v6 is powering Nx underneath. As a result, Lerna gets all the modern features such as caching and task pipelines. Read more on [https://lerna.js.org/upgrade](https://lerna.js.org/upgrade). {% /callout %} -Nx has first-class support for [package-based monorepos](/getting-started/tutorials/package-based-repo-tutorial). As a result, if you have an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get +Nx has first-class support for [monorepos](/getting-started/tutorials/package-based-repo-tutorial). As a result, if you have an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get -- fast [task scheduling](/core-features/run-tasks) +- fast [task scheduling](/features/run-tasks) - support for [task pipelines](/concepts/task-pipeline-configuration) -- [caching](/core-features/cache-task-results) -- optionally [remote caching with Nx Cloud](/ci/features/remote-cache) -- optionally [distributed task execution with Nx Cloud](/ci/features/distribute-task-execution) +- [caching](/features/cache-task-results) +- [remote caching with Nx Cloud](/ci/features/remote-cache) +- [distributed task execution with Nx Cloud](/ci/features/distribute-task-execution) This is a low-impact operation because all that needs to be done is to install the `nx` package at the root level and add an `nx.json` for configuring caching and task pipelines. @@ -27,75 +27,223 @@ Run the following command to automatically set up Nx: npx nx@latest init ``` -Running this command will +This will set up Nx for you - updating the `package.json` file and creating a new `nx.json` file with Nx configuration based on your answers during the set up process. The set up process will suggest installing Nx plugins that might be useful based on your existing repository. The example below is using the `@nx/eslint` and `@nx/next` plugins to run ESLint and Next.js tasks with Nx: -- collect all the NPM scripts in the corresponding `package.json` files of your workspace packages -- ask you which of those scripts are cacheable (e.g. build, test, lint) -- ask you which of those scripts might need to be run in a certain order (e.g. if you run the `build` script you might want to first build all the dependent projects) -- ask you for custom output folders that should be captured as part of the caching +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + }, + { + "plugin": "@nx/next/plugin", + "options": { + "buildTargetName": "build", + "devTargetName": "dev", + "startTargetName": "start" + } + } + ] +} +``` -This process adds `nx` to your `package.json` at the root of your workspace: +When Nx updates your `package.json` scripts, it looks for scripts that can be replaced with an Nx command that has caching automatically enabled. The `package.json` defined above would be updated to look like this: ```json {% fileName="package.json" %} { "name": "my-workspace", ... - "devDependencies": { - ... - "nx": "17.2.0" + "scripts": { + "build": "nx build", + "lint": "nx lint", + "test": "node ./run-tests.js" + }, + ... + "nx": { + "includedScripts": [] } } ``` -It also creates a `nx.json` based on the answers given during the setup process. This includes cacheable operations as well as some initial definition of the task pipeline. Here is an example: +The `@nx/next` plugin can run `next build` for you and set up caching correctly, so it replaces `next build` with `nx build`. Similarly, `@nx/eslint` can set up caching for `eslint ./src`. When you run `npm run build` or `npm run lint` multiple times, you'll see that caching is enabled. You can also call Nx directly from the terminal with `nx build` or `nx lint`. -{% tabs %} -{% tab label="Nx >= 17" %} +The `test` script was not recognized by any Nx plugin, so it was left as is. -```json {% fileName="nx.json" %} +The `includedScripts` array allows you to specify `package.json` scripts that can be run with the `nx build` syntax. + +## Inferred Tasks + +You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `build` task. Those tasks were created by the `@nx/next` plugin from your existing Next.js configuration. To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project details in a browser window. + +```shell +nx show project my-workspace --web +``` + +{% project-details title="Project Details View" height="100px" %} + +```json { - "targetDefaults": { - "build": { - "cache": true, - "dependsOn": ["^build"] - }, - "test": { - "cache": true - }, - "lint": { - "cache": true + "project": { + "name": "my-workspace", + "data": { + "root": ".", + "targets": { + "lint": { + "cache": true, + "options": { + "cwd": ".", + "command": "eslint ./src" + }, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "configurations": {} + }, + "build": { + "options": { + "cwd": ".", + "command": "next build" + }, + "dependsOn": ["^build"], + "cache": true, + "inputs": [ + "default", + "^default", + { + "externalDependencies": ["next"] + } + ], + "outputs": ["{projectRoot}/.next", "{projectRoot}/.next/!(cache)"], + "executor": "nx:run-commands", + "configurations": {} + }, + "dev": { + "options": { + "cwd": ".", + "command": "next dev" + }, + "executor": "nx:run-commands", + "configurations": {} + }, + "start": { + "options": { + "cwd": ".", + "command": "next start" + }, + "dependsOn": ["build"], + "executor": "nx:run-commands", + "configurations": {} + } + }, + "sourceRoot": ".", + "name": "my-workspace", + "projectType": "library", + "includedScripts": [], + "implicitDependencies": [], + "tags": [] } + }, + "sourceMap": { + "root": ["package.json", "nx/core/package-json-workspaces"], + "targets": ["package.json", "nx/core/package-json-workspaces"], + "targets.lint": ["package.json", "@nx/eslint/plugin"], + "targets.lint.command": ["package.json", "@nx/eslint/plugin"], + "targets.lint.cache": ["package.json", "@nx/eslint/plugin"], + "targets.lint.options": ["package.json", "@nx/eslint/plugin"], + "targets.lint.inputs": ["package.json", "@nx/eslint/plugin"], + "targets.lint.options.cwd": ["package.json", "@nx/eslint/plugin"], + "targets.build": ["next.config.js", "@nx/next/plugin"], + "targets.build.command": ["next.config.js", "@nx/next/plugin"], + "targets.build.options": ["next.config.js", "@nx/next/plugin"], + "targets.build.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.build.cache": ["next.config.js", "@nx/next/plugin"], + "targets.build.inputs": ["next.config.js", "@nx/next/plugin"], + "targets.build.outputs": ["next.config.js", "@nx/next/plugin"], + "targets.build.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.dev": ["next.config.js", "@nx/next/plugin"], + "targets.dev.command": ["next.config.js", "@nx/next/plugin"], + "targets.dev.options": ["next.config.js", "@nx/next/plugin"], + "targets.dev.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.start": ["next.config.js", "@nx/next/plugin"], + "targets.start.command": ["next.config.js", "@nx/next/plugin"], + "targets.start.options": ["next.config.js", "@nx/next/plugin"], + "targets.start.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.start.options.cwd": ["next.config.js", "@nx/next/plugin"], + "sourceRoot": ["package.json", "nx/core/package-json-workspaces"], + "name": ["package.json", "nx/core/package-json-workspaces"], + "projectType": ["package.json", "nx/core/package-json-workspaces"], + "includedScripts": ["package.json", "nx/core/package-json-workspaces"], + "targets.nx-release-publish": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.dependsOn": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.executor": [ + "package.json", + "nx/core/package-json-workspaces" + ], + "targets.nx-release-publish.options": [ + "package.json", + "nx/core/package-json-workspaces" + ] } } ``` -{% /tab %} -{% tab label="Nx < 17" %} +{% /project-details %} -```json {% fileName="nx.json" %} +The project detail view lists all available tasks, the configuration values for those tasks and where those configuration values are being set. + +## Configure an Existing Script to Run with Nx + +If you want to run one of your existing scripts with Nx, you need to tell Nx about it. + +1. Preface the script with `nx exec -- ` to have `npm run test` invoke the command with Nx. +2. Add the script to `includedScripts`. +3. Define caching settings. + +The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script from the example above to run with Nx would look something like this: + +```json {% fileName="package.json" %} { - "tasksRunnerOptions": { - "default": { - "runner": "nx/tasks-runners/default", - "options": { - "cacheableOperations": ["build", "test", "lint"] - } - } + "name": "my-workspace", + ... + "scripts": { + "build": "nx build", + "lint": "nx lint", + "test": "nx exec -- node ./run-tests.js" }, - "targetDefaults": { - "build": { - "dependsOn": ["^build"] + ... + "nx": { + "includedScripts": ["test"], + "targets": { + "test": { + "cache": "true", + "inputs": ["default", "^default"], + "outputs": [] + } } } } ``` -{% /tab %} -{% /tabs %} +Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in this example are as cautious as possible, so you can significantly improve the value of the cache by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. ## Incrementally Adopting Nx -In a package-based monorepo, Nx only manages the scheduling and caching of your npm scripts. Hence, it can easily be adopted incrementally by initially using Nx just for a subset of your scripts and then gradually adding more. +All the features of Nx can be enabled independently of each other. Hence, Nx can easily be adopted incrementally by initially using Nx just for a subset of your scripts and then gradually adding more. For example, use Nx to run your builds: @@ -115,7 +263,7 @@ This allows for incrementally adopting Nx in your existing workspace. {% cards %} -{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/core-features/cache-task-results" /%} +{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/features/cache-task-results" /%} {% card title="Task Pipeline Configuration" description="Learn more about how to setup task dependencies" type="documentation" url="/concepts/task-pipeline-configuration" /%} @@ -123,8 +271,6 @@ This allows for incrementally adopting Nx in your existing workspace. {% card title="Nx and Turbo" description="Read about how Nx compares to Turborepo" url="/concepts/more-concepts/turbo-and-nx" /%} -{% card title="Nx and Lerna" description="Read about how Nx and Lerna can be used together" url="/recipes/adopting-nx/lerna-and-nx" /%} - {% card title="Integrated Repos vs Package-Based Repos" description="Learn about two styles of monorepos." url="/concepts/integrated-vs-package-based" /%} {% /cards %} diff --git a/docs/shared/migration/from-turborepo.md b/docs/shared/migration/from-turborepo.md index 160c51bd5145d..3974fc030c07c 100644 --- a/docs/shared/migration/from-turborepo.md +++ b/docs/shared/migration/from-turborepo.md @@ -12,34 +12,7 @@ To switch to Nx, run this command: npx nx@latest init ``` -The command will ask you three questions. - -1. Which scripts need to be run in order? - - Any scripts you select in this step will be set up so project dependencies will be run first. i.e. `"dependsOn": "^build"` - -2. Which scripts are cacheable? - - Any scripts you select in this step will be made cacheable, i.e. the `cache` property will be set to `true` (`false` by default) in the `targetDefaults` section. - -3. For each cacheable script, does it produce output in the file system? - - Any folders identified will be added to the task's `outputs`. i.e. `"outputs": ["{projectRoot}/dist"]` - -This process adds `nx` to your `package.json` at the root of your workspace: - -```json {% fileName="package.json" %} -{ - "name": "my-workspace", - ... - "devDependencies": { - ... - "nx": "17.2.0" - } -} -``` - -It also creates an `nx.json` based on the answers given during the setup process. This includes cacheable operations as well as some initial definition of the task pipeline. +See the [Adding Nx to NPM/Yarn/PNPM Workspace](/recipes/adopting-nx/adding-to-monorepo) guide for details about everything the `nx init` command does. ## Convert turbo.json into Nx Configuration @@ -80,9 +53,6 @@ Let's say you start with the following `turbo.json` file: Creating the equivalent configuration with Nx yields the following files: -{% tabs %} -{% tab label="Nx >= 17" %} - ```json {% fileName="/nx.json" %} { "$schema": "./node_modules/nx/schemas/nx-schema.json", @@ -112,46 +82,6 @@ Creating the equivalent configuration with Nx yields the following files: } ``` -{% /tab %} -{% tab label="Nx < 17" %} - -```json {% fileName="/nx.json" %} -{ - "$schema": "./node_modules/nx/schemas/nx-schema.json", - "namedInputs": { - "sharedGlobals": ["babel.config.json"], - "default": ["{projectRoot}/**/*", "sharedGlobals"] - }, - "targetDefaults": { - "build": { - "dependsOn": ["^build"], - "inputs": ["default"], - "outputs": ["{projectRoot}/dist"] - }, - "test": { - "dependsOn": ["build"], - "inputs": ["default"] - }, - "e2e": { - "dependsOn": ["build"], - "inputs": ["default"] - } - }, - "tasksRunnerOptions": { - "default": { - "runner": "nx-cloud", - "options": { - "cacheableOperations": ["build", "e2e", "test"], - "accessToken": "..." - } - } - } -} -``` - -{% /tab %} -{% /tabs %} - ```jsonc {% fileName="/packages/docs/package.json" %} { "name": "docs", @@ -170,12 +100,12 @@ Creating the equivalent configuration with Nx yields the following files: For each `turbo.json` configuration property, the equivalent Nx property is listed. -| **Global Configuration:** | | -| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/customizing-inputs) | -| `globalEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/customizing-inputs) as an [`env` input](/reference/project-configuration#env-variables) | -| `globalPassThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) | -| `globalDotEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/customizing-inputs) | +| **Global Configuration:** | | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) | +| `globalEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) as an [`env` input](/reference/project-configuration#env-variables) | +| `globalPassThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) | +| `globalDotEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/configure-inputs) | | **Task Configuration:** | | | ------------------------------- | ------------------------------------------------------------------------------------------------- | @@ -204,7 +134,7 @@ For each `turbo.json` configuration property, the equivalent Nx property is list | `--filter` | Use [`-p admin-*` or `-p tag:api-*`](/nx-api/nx/documents/run-many#projects). Also see [`nx affected`](/nx-api/nx/documents/affected). | | `--graph` | [Same syntax](/nx-api/nx/documents/run-many#graph) or [`nx graph`](/nx-api/nx/documents/dep-graph) for the entire graph | | `--force` | [`nx reset`](/nx-api/nx/documents/reset) and then run the command again | -| `--global-deps` | Use [`inputs` in the `nx.json`](/recipes/running-tasks/customizing-inputs) or project configuration | +| `--global-deps` | Use [`inputs` in the `nx.json`](/recipes/running-tasks/configure-inputs) or project configuration | | `--framework-inference` | Nx knows if you're using a particular framework if you use an executor for that framework. | | `--ignore` | Use an [`.nxignore` file](/reference/nxignore) (or `.gitignore`) | | `--log-order` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) | diff --git a/docs/shared/migration/lerna-and-nx.md b/docs/shared/migration/lerna-and-nx.md deleted file mode 100644 index 6828a9dcde451..0000000000000 --- a/docs/shared/migration/lerna-and-nx.md +++ /dev/null @@ -1,207 +0,0 @@ -# Integrating Nx and Lerna - -{% callout type="check" title="Nrwl took over stewardship of Lerna" %} -[In case you missed it, Nrwl, the company behind Nx, took over stewardship of Lerna. This opens up a range of new opportunities for integrating the two. Continue reading to learn more](https://blog.nrwl.io/lerna-is-dead-long-live-lerna-61259f97dbd9). -{% /callout %} - -[Lerna](https://lerna.js.org/) is a popular JavaScript monorepo management tool and which can be used in combination with Nx. Lerna does three main things: - -1. it runs commands for a single package or multiple packages (`lerna run`) -2. it manages dependencies (`lerna bootstrap`) -3. it publishes your packages, handles version management, and does changelog generation (`lerna publish`) - -While Lerna is good at managing dependencies and publishing, it can quickly become painful to scale Lerna based monorepos, simply because Lerna is slow. That's where Nx shines and where it can really speed up your monorepo. - -If you are about to set up a new monorepo from scratch, you can directly go with Nx. If you have an existing Lerna monorepo, you can easily integrate the two. - -For a discussion on #2, see [dependency management](#dependency-management) below. For a discussion on #3, see [version management](#version-Management--publishing) below. - -## Speed up Lerna with Nx's powerful task scheduler - -Nx comes with a powerful task scheduler that intelligently runs operations and makes sure they are quick. This happens in a variety of ways: - -- **Parallelization and task dependencies -** Nx automatically [knows how your projects relate to each other](/concepts/more-concepts/how-project-graph-is-built). As a result, if `project-a` depends on `project-b` and you run the build command for `project-a`, Nx first runs the builds for all of `project-a`'s dependencies and then the invoked project itself. Nx sorts these tasks to maximize parallelism. -- **Only run what changed -** Using [Nx affected commands](/ci/features/affected) you only really execute tasks on the projects that changed, compared to a given baseline (usually the main branch). -- **Caching -** You get Nx's [computation caching](/concepts/how-caching-works) for free. All operations, including artifacts and terminal output are restored from the cache (if present) in a completely transparent way without disrupting your DX. No configuration needed. Obviously this results in an incredible speed improvement. -- **Distributed Task Execution -** This is unique to Nx. In combination with Nx Cloud your tasks are automatically distributed across CI agents, taking into account build order, maximizing parallelization and thus agent utilization. It even learns from previous runs to better distribute tasks! [Learn more](/ci/features/distribute-task-execution) - -## Integrating Nx with Lerna - -Since the [Nx core team now also maintains Lerna](https://blog.nrwl.io/lerna-is-dead-long-live-lerna-61259f97dbd9), there are a lot of different possibilities for integrating the two. The main strategy is to keep using Lerna's bootstrapping and publishing features, but use Nx for the fast task scheduling to speed up Lerna workspaces. - -There are two options: - -- Upgrade to the latest Lerna version and enable Nx by adding the `useNx` flag to your `lerna.json` file without changing anything else (including your current Lerna commands) -- Directly using the Nx commands - -### Use Nx for task scheduling, without changing the Lerna setup - -Starting with Lerna 5.1 you have Nx as an additional option to the existing `p-map` and `q-map` (previously used by Lerna) for running tasks. This is the **preferred approach if you have already a Lerna repository** since the impact is the lowest, while the benefit is still very high. - -To enable Nx support (and thus speed up task running) go through the following steps: - -**1. Install Nx** - -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D nx -``` - -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D nx -``` - -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D nx -``` - -{% /tab %} -{% /tabs %} - -**2. Adjust your lerna.json** - -Change your `lerna.json` by adding the following flag. - -```jsonc {% fileName="lerna.json" %} -{ - ... - "useNx": true -} -``` - -By default `useNx` will be set to `false`, so you have to explicitly opt-in. - -**3. Create a nx.json (optional but recommended)** - -Nx works even without `nx.json` but to configure some more details such as the `cacheableOperations` of your monorepo in particular, create a `nx.json` at the root of the monorepo. Alternatively you can also just run `npx nx@latest init` to have one generated. Specify the cacheable targets, usually something like `build`, `test`, `lint` etc, depending on your workspace setup: - -{% tabs %} -{% tab label="Nx >= 17" %} - -```json {% fileName="nx.json" %} -{ - "extends": "nx/presets/npm.json", - "targetDefaults": { - "build": { - "cache": true - } - } -} -``` - -{% /tab %} -{% tab label="Nx < 17" %} - -```json {% fileName="nx.json" %} -{ - "extends": "nx/presets/npm.json", - "tasksRunnerOptions": { - "default": { - "runner": "nx/tasks-runners/default", - "options": { - "cacheableOperations": ["build"] - } - } - } -} -``` - -{% /tab %} -{% /tabs %} - -Having done these steps, you can now keep using your Lerna repository as you did before. All the commands will work in a backwards compatible way but will be a lot faster. [Read our blog post for some benchmarks](https://blog.nrwl.io/lerna-used-to-walk-now-it-can-fly-eab7a0fe7700?source=friends_link&sk=6c827ec7c9adfc1c760ff2e3f3e05cc7). - -{% callout type="note" title="Enable remote caching?" %} -This does not include remote caching or distributed task execution powered by Nx Cloud. But you can easily add support for it if wanted. All that's required is `npx nx connect-to-nx-cloud`. -{% /callout %} - -### Switch to the Nx native commands in your Lerna workspace - -Nx can be added to an existing Lerna monorepo by running the following command: - -```shell -npx nx@latest init -``` - -This will - -1. Add Nx to your package.json. -2. Create `nx.json`, containing all the necessary configuration for Nx. -3. Set up [Nx Cloud](https://nx.app) (if you chose "yes"). - -You can then run your package's npm scripts by simply invoking - -```shell -nx -``` - -Hence, if package `myproj` has a `build` script, you can just run it using `nx build myproj`. Similarly for running tests use `nx test myproj` and so on. - -Here's an overview of some more Lerna commands and the corresponding Nx version: - -```diff -{ - "private": true, - "scripts": { -- "build:all": "lerna run build", -+ "build:all": "nx run-many -t build", -- "build:app1": "lerna run build --scope=app1", -+ "build:app1": "nx build app1", -- "build:since": "lerna run build --since=main", -+ "build:since": "nx affected -t build", -- "test:all": "lerna run test", -+ "test:all": "nx run-many -t test", -- "test:app1": "lerna run test --scope=app1", -+ "test:app1": "nx test app1", -- "test:since": "lerna run test --since=main", -+ "test:since": "nx affected -t test", -- "dev": "lerna run dev --stream --parallel", -+ "dev": "nx run-many -t dev", -- "dev:app1": "lerna run dev --stream --scope=app1", -+ "dev:app1": "nx dev app1" - }, - "devDependencies": { - "lerna": "5.*", -+ "nx": "latest" - } -} -``` - -## Dependency Management - -Lerna has dependency management already built-in using `lerna bootstrap`. Running that will install all npm dependencies for all packages and also symlink together all Lerna packages that have dependencies of each other. - -Nx does not handle dependency management. As a result, if you already have a Lerna workspace, you can safely keep using `lerna bootstrap`. Alternatively you can use some of the baked-in solutions that now come with npm/yarn/pnpm workspaces. - -## Version Management & Publishing - -Version management is defined as bumping the version of your changed monorepo packages and automatically creating a changelog. After bumping the version, you will commonly want to publish/upload the new version to NPM (or some other package repository). - -If you have an existing Lerna monorepo, feel free to continue using `lerna publish`. - -Right now Nx does not handle version management although you can use the [@jscutlery/semver](https://github.com/jscutlery/semver) Nx plugin. - -You can also leverage a 3rd-party tool such as: - -- [release-it](https://github.com/release-it/release-it) (standalone CLI tool) -- [changesets](https://github.com/changesets/changesets) (standalone CLI tool) - -## What's more? - -Nx comes with a whole range of additional features such as: - -- **Interactive workspace visualization -** to interactively explore the underlying [project graph](/core-features/explore-graph) for understanding dependencies and find paths between nodes. -- **Nx plugins -** for adding first-class support for React, Next.js, React Native, Angular, Node, NestJS, Jest, Cypress, Storybook and many more. -- **Dedicated VSCode extension -** You can install [Nx Console](/core-features/integrate-with-editors) which is a dedicated VSCode extension to provide a visual interface for navigating your monorepo workspace in terms of launching commands as well as for generating code. -- **GitHub integration -** Install the [Nx Cloud GitHub App](https://github.com/apps/nx-cloud) to get inline reporting on your CI jobs. -- ... - -But take your time to explore. diff --git a/docs/shared/migration/manual.md b/docs/shared/migration/manual.md index 751b2e5514cc8..e06a1fe70b9eb 100644 --- a/docs/shared/migration/manual.md +++ b/docs/shared/migration/manual.md @@ -1,199 +1,91 @@ # Manual migration of existing code bases -## What you’ll accomplish - -Migrating into an Nx workspace can seem intimidating. While every codebase is unique, we can offer recommendations for how to proceed based on the Nrwl team’s years of experience. The key to success is an incremental approach. You don’t need to migrate your entire codebase at once. Find a good target for migration, move it into your Nx workspace, get it working and stable, and go from there. - -This document will introduce you to the Nx workspace, help you get one created, and point you to some particular configuration that you may need for your codebase. - -## Create a workspace - -To get started, you’ll need an Nx workspace. While Nx offers several preset configurations for your workspace, we recommend starting migration with an `empty` workspace. This will allow you to have finer control over the configuration and creation of the applications and libraries in your workspace. - -To create an empty workspace: +The easiest way to start using Nx is to run the `nx init` command. ```shell -npx create-nx-workspace@latest +npx nx@latest init ``` -Select `empty` when prompted: +If you don't want to run the script, this guide will walk you through doing everything the script does manually. -```{% command="npx create-nx-workspace@latest" %} -? What to create in the new workspace (Use arrow keys) -❯ empty [an empty workspace with a layout that works best for building apps] -``` - -## Exploring your workspace - -Take a tour of your Nx workspace. There are some important areas to know about as you migrate. +## Install `nx` as a `devDependency` -### apps - -The `apps` directory is the place where your top-level applications will be stored. You should always begin your migration journey by adding an application. +We'll start by installing the `nx` package: {% tabs %} -{% tab label="Angular" %} +{% tab label="npm" %} ```shell -npm add -D @nx/angular -# then -nx generate @nx/angular:application my-application +npm add -D nx@latest ``` {% /tab %} -{% tab label="React" %} +{% tab label="yarn" %} ```shell -npm add -D @nx/react -# then -nx generate @nx/react:application my-application +yarn add -D nx@latest ``` {% /tab %} -{% /tabs %} - -There are a lot of options when creating your application. If you want to follow Nx recommendations, you can accept the defaults. If you have a well-established codebase, you can configure those options at the time of application generation. You can find documentation for these options for the different frameworks here: - -- [Angular](/nx-api/angular/generators/application) -- [React](/nx-api/react/generators/application) - -You may also find it useful to use the [Nx Console](/core-features/integrate-with-editors) in Visual Studio Code. This will give you a visual way to generate your application with all of the options laid out in front of you. - -### Configuration files - -Your workspace contains different configuration files for the tools you’ll need to develop, such as linters, bundlers, and executors. There are two sources of configuration files for your workspace: at the root of the workspace and at the root of your application. The configuration files at the root of your application extend the configuration files found at the root of your workspace. If you need to make global adjustments to these configurations, you should do so at the root of the workspace. If you have multiple applications that need different configurations, you should manage this using the configuration files in the root of each application. - -In general, you should not replace the configuration files provided for you. You should add to or modify the configurations that are there. This will help ensure that your configuration files are set up for Nx to work at its best. - -### Nx Configuration Files - -In addition to configuration files for external libraries, your Nx workspace will have configuration files for Nx itself. This will be `angular.json` for workspaces using the Angular CLI and `project.json` files for workspaces using the Nx CLI. This file will define all of the individual projects in your workspace (of which your application is one) and the tasks available for them. - -For example, your generated application should have four [tasks available](/core-features/plugin-features/use-task-executors) for it: `build`, `serve`, `lint`, and `test`. Each of these comes with its own configuration. If you find you need to adjust the configuration of a task for your codebase, this is the place to begin looking. - -These workspace configuration files can seem a little long and intimidating. The Nx Console can help you navigate it more easily with its Workspace JSON panel. By clicking on a project in your workspace, it will navigate you to the right place in the workspace file to begin making edits. - -Additionally, there is an `nx.json` file that contains metadata about your projects. [This metadata includes tags](/core-features/enforce-module-boundaries) that can help you impose constraints on your applications and library dependencies. - -## Migrating your code - -There are two major steps to migrating your application: migrating your dependencies and migrating your code. - -### Dependencies - -If you’re already using npm for package management, this is as easy as copying your dependencies from your old `package.json` file to your workspace’s `package.json`. Make sure you don’t add any duplicate dependencies during this step. - -If you’re using other package managers such as Bower, you’ll need to take an intermediary step of moving your dependencies from there to NPM. For Bower, [migration information is available](https://bower.io/blog/2017/how-to-migrate-away-from-bower/). - -### Code - -If your code is all in a single app, you can copy it into the application’s folder. Configuration files go in the root of your application, and application code goes into the `src/app` folder. Assets such as images, icons, and fonts can go into the `src/assets` directory. An `index.html` is provided for you in `src`. You should add anything else you may need such as external fonts or icons from a CDN. `src/main.ts` will bootstrap your application. You may need to modify this file or modify your application file names to bootstrap your app. - -## Running tasks - -Now that your code is present, it’s time to tackle building and testing it. - -### Local build and serve - -Each generated application has a build process defined by Nx. This uses the Angular CLI for Angular, and webpack is used for all other projects. See if this build process works out of the box for you by running +{% tab label="pnpm" %} ```shell -nx serve my-application +pnpm add -D nx@latest ``` -If this doesn’t work for you, you may need to add or modify some configuration on the `build` task in your workspace configuration file. - -### Unit tests - -Each application will have a unit test process defined by your choices (Jest or Karma) during the creation of the application. To run tests for your application: - -```shell -nx test my-application -``` - -It is recommended that unit tests live next to the code they exercise and code scaffolded by Nx will follow this pattern. If your unit tests currently live in a separate directory, you may need to modify your test configuration or move your test files. - -Testing configuration files can be found in the root of your application as well as the workspace configuration file. - -### End to End Tests - -Each application will have an e2e configuration created as a separate application, appended with `-e2e`. In our example, you’ll see `my-application-e2e`. This `e2e` task uses the test runner you chose during generation, Protractor or Cypress. Your application’s e2e tests should be migrated to this directory. There will be an e2e test scaffolded for you to make sure everything works before you start adding your own. To run the e2e tests: - -```shell -nx e2e my-application-e2e -``` - -All the configuration for your e2e tests should be in this directory. - -### Linting - -Nx uses ESLint for linting. Nx also has its own lint process to make sure your Nx configuration is valid. - -To run the `lint` task for your workspace - -```shell -nx lint -``` - -To run the `lint` task for a particular application: - -```shell -nx lint my-application -``` - -Global configuration files for linting will be at the root of your workspace. Each application and library will extend those configuration files. Global configuration changes should be made in the root, while application-or-library-specific changes should occur in the application or library configuration files. +{% /tab %} +{% /tabs %} -### Formatting +## Create a Basic `nx.json` File -Nx uses Prettier to ensure standard formatting across your codebase. Prettier configuration files are located in the root of the workspace. To format your workspace run: +Next, we'll create a blank `nx.json` configuration file for Nx: -```shell -nx format:write +```json {% fileName="nx.json" %} +{} ``` -[Learn more about formatting](/nx-api/nx/documents/format-write) - -### Adding tasks - -Nx offers built-in tasks for the most common needs: `serve`, `build`, `test`, `e2e`, and `lint`. You likely have additional tasks that are needed to manage or deploy your codebase. These tasks might include deployment, i18n workflows, or uploading assets to CDNs. These tasks can be set up as scripts that you run manually with node, ts-node, or npm scripts. You can migrate those tasks over as-is, to begin with. - -You should consider implementing them as Nx tasks which should be a quick transition with the `run-commands` builder. [The `run-commands` executor](/recipes/running-tasks/run-commands-executor) will allow you to run any custom commands you need as an Nx task. By implementing these commands in an Nx task, they are able to take advantage of the project graph in Nx and only run when necessary. They are also able to be cached and only be re-run when necessary. - -Your use-case may also be covered by one of our community plugins. Plugin authors are able to extend the functionality of Nx through our plugin API. +## Set Up Caching For a Task -[Learn more about the `run-commands` executor](/nx-api/nx/executors/run-commands) +Now, let's set up caching for a script in your `package.json` file. Let's say you have a `build` script that looks like this: -[Learn more about caching](/concepts/how-caching-works) - -[Learn more about community plugins](/community) - -## Migrating libraries - -If your code is divided into libraries, you should also generate libraries for your code to migrate into: - -{% tabs %} -{% tab label="Angular" %} - -```shell -nx generate @nx/angular:library +```json {% fileName="package.json" %} +{ + "scripts": { + "build": "tsc -p tsconfig.json" + } +} ``` -{% /tab %} -{% tab label="React" %} - -```shell -nx generate @nx/react:library +In order for Nx to cache this task, you need to: + +- run the script through Nx using `nx exec -- ` +- configure caching settings in the `nx` property of `package.json` + +The new `package.json` will look like this: + +```json {% fileName="package.json" %} +{ + "scripts": { + "build": "nx exec -- tsc -p tsconfig.json" + }, + "nx": { + "targets": { + "build": { + "cache": true, + "inputs": [ + "{projectRoot}/**/*.ts", + "{projectRoot}/tsconfig.json", + { "externalDependencies": ["typescript"] } + ], + "outputs": ["{projectRoot}/dist"] + } + } + } +} ``` -{% /tab %} -{% /tabs %} - -{% callout type="caution" title="Be mindful about where the code lives" %} -It’s important to remember: don’t just drop your code anywhere! Always generate an app or a library for that code before migration. Without the project configuration, you’ll miss out on key functionalities of Nx provided by the project graph generation and affected code detection. -{% /callout %} - -### Establishing code boundaries +Now, if you run `npm build` or `nx build` twice, the second run will be retrieved from the cache instead of being executed. -If you’re consolidating multiple repositories or libraries into a single Nx workspace, you may have concerns about code boundaries. Previously, you may have had well-established boundaries by separating code into different repositories or having a public API for a library. Nx features a tagging system that allows you to enforce these code boundaries in a granular way. Each project can be tagged, and you can constrain dependencies based on these tags. +## Enable More Features of Nx as Needed -[Learn more about tags and dependency constraints](/core-features/enforce-module-boundaries) +You could stop here if you want, but there are many more features of Nx that might be useful to you. Many [plugins](/plugin-registry) can automate the process of configuring the way Nx runs your tools. Plugins also provide [code generators](/features/generate-code) and [automatic dependency updates](/features/automate-updating-dependencies). You can speed up your CI with [remote caching](/ci/features/remote-cache) and [distributed task execution](/ci/features/distribute-task-execution). diff --git a/docs/shared/migration/migration-angular.md b/docs/shared/migration/migration-angular.md index 48ed1efa399a1..857ca65229185 100644 --- a/docs/shared/migration/migration-angular.md +++ b/docs/shared/migration/migration-angular.md @@ -122,7 +122,7 @@ Learn more about the advantages of Nx in the following guides: - [Using Jest for unit tests](/nx-api/jest) - [Computation Caching](/concepts/how-caching-works) - [Rebuilding and Retesting What is Affected](/ci/features/affected) -- [Integrate with Editors](/core-features/integrate-with-editors) +- [Integrate with Editors](/features/integrate-with-editors) - [Advanced Angular Micro Frontends with Dynamic Module Federation](/recipes/angular/dynamic-module-federation-with-angular) ## From Nx Console diff --git a/docs/shared/migration/migration-angularjs.md b/docs/shared/migration/migration-angularjs.md index 05dfe27c0c973..7b101457a6e9f 100644 --- a/docs/shared/migration/migration-angularjs.md +++ b/docs/shared/migration/migration-angularjs.md @@ -41,30 +41,10 @@ At the next prompt, you can choose whether to use [Nx Cloud](https://nx.app) or Your new workspace won’t have much in it because of the `apps` preset. You’ll need to generate an application to have some structure created. Add the Angular plugin to your workspace: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/angular -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/angular +nx add @nx/angular ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/angular -``` - -{% /tab %} -{% /tabs %} - For this example, we will use Karma and Protractor, the most common unit test runner and e2e test runner for AngularJS. {% callout type="note" title="Unit & E2E tests" %} @@ -389,27 +369,30 @@ But migrating AngularJS code means we need to switch some of our tools to a more {% tab label="npm" %} ```shell -npm add -D @nx/web babel-plugin-angularjs-annotate +npm add -D babel-plugin-angularjs-annotate +nx add @nx/web ``` {% /tab %} {% tab label="yarn" %} ```shell -yarn add -D @nx/web babel-plugin-angularjs-annotate +yarn add -D babel-plugin-angularjs-annotate +nx add @nx/web ``` {% /tab %} {% tab label="pnpm" %} ```shell -pnpm add -D @nx/web babel-plugin-angularjs-annotate +pnpm add -D babel-plugin-angularjs-annotate +nx add @nx/web ``` {% /tab %} {% /tabs %} -Nx already has most of what you need for webpack added as a dependency. `@nx/web` contains the [executors](/core-features/plugin-features/use-task-executors) we need to use to build and serve the application with webpack and +Nx already has most of what you need for webpack added as a dependency. `@nx/web` contains the [executors](/concepts/executors-and-configurations) we need to use to build and serve the application with webpack and `babel-plugin-angularjs-annotate` is going to accomplish the same thing that `browserify-ngannotate` previously did in gulp: add dependency injection annotations. Start with a `webpack.config.js` file in your application’s root directory: diff --git a/docs/shared/monorepo-ci-azure.md b/docs/shared/monorepo-ci-azure.md index e69b9788be45f..3ebb3e3daad02 100644 --- a/docs/shared/monorepo-ci-azure.md +++ b/docs/shared/monorepo-ci-azure.md @@ -1,10 +1,6 @@ # Configuring CI Using Azure Pipelines and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on Azure Pipelines - -Below is an example of an Azure Pipelines setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an Azure Pipelines setup building and testing only what is affected. ```yaml {% fileName="azure-pipelines.yml" %} trigger: @@ -49,27 +45,39 @@ jobs: # Required for nx affected if we're on a branch - script: git branch --track main origin/main + - script: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - script: npm ci - script: npx nx-cloud record -- nx format:check --base=$(BASE_SHA) - - script: npx nx affected --base=$(BASE_SHA) -t lint,test,build --parallel=3 --configuration=ci + - script: npx nx affected --base=$(BASE_SHA) -t lint test build --parallel=3 ``` {% callout type="note" title="Check your Shallow Fetch settings" %} -Nx needs additional Git history available for [`affected`](/ci/features/affected) to function correctly. Make sure Shallow fetching is disabled in your pipeline settings UI. For more info, check out this article from Microsoft [here](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/steps-checkout?view=azure-pipelines#shallow-fetch). +Nx needs additional Git history available for [`affected`](/ci/features/affected) to function correctly. Make sure +Shallow fetching is disabled in your pipeline settings UI. For more info, check out this article from +Microsoft [here](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/steps-checkout?view=azure-pipelines#shallow-fetch). {% /callout %} -Unlike `GitHub Actions` and `CircleCI`, you don't have the metadata to help you track the last successful run on `main`. In the example below, the base is set to `HEAD~1` (for push) or branching point (for pull requests), but a more robust solution would be to tag a SHA in the main job once it succeeds and then use this tag as a base. You can also try [using the devops CLI within the pipeline yaml](#get-the-commit-of-the-last-successful-build). See the [nx-tag-successful-ci-run](https://github.com/nrwl/nx-tag-successful-ci-run) and [nx-set-shas](https://github.com/nrwl/nx-set-shas) (version 1 implements tagging mechanism) repositories for more information. +Unlike `GitHub Actions` and `CircleCI`, you don't have the metadata to help you track the last successful run on `main`. +In the example below, the base is set to `HEAD~1` (for push) or branching point (for pull requests), but a more robust +solution would be to tag a SHA in the main job once it succeeds and then use this tag as a base. You can also +try [using the devops CLI within the pipeline yaml](#get-the-commit-of-the-last-successful-build). See +the [nx-tag-successful-ci-run](https://github.com/nrwl/nx-tag-successful-ci-run) +and [nx-set-shas](https://github.com/nrwl/nx-set-shas) (version 1 implements tagging mechanism) repositories for more +information. -We also have to set `NX_BRANCH` explicitly. NX_BRANCH does not impact the functionality of your runs, but does provide a human-readable label to easily identify them in the Nx Cloud app. +We also have to set `NX_BRANCH` explicitly. NX_BRANCH does not impact the functionality of your runs, but does provide a +human-readable label to easily identify them in the Nx Cloud app. The `main` job implements the CI workflow. ## Get the Commit of the Last Successful Build -In the example above we ran a script to retrieve the commit of the last successful build. The idea is to use [Azure Devops CLI](https://learn.microsoft.com/en-us/cli/azure/pipelines?view=azure-cli-latest) -directly in the [Pipeline Yaml](https://learn.microsoft.com/en-us/azure/devops/cli/azure-devops-cli-in-yaml?view=azure-devops) +In the example above we ran a script to retrieve the commit of the last successful build. The idea is to +use [Azure Devops CLI](https://learn.microsoft.com/en-us/cli/azure/pipelines?view=azure-cli-latest) +directly in +the [Pipeline Yaml](https://learn.microsoft.com/en-us/azure/devops/cli/azure-devops-cli-in-yaml?view=azure-devops) First, we configure Devops CLI @@ -99,81 +107,10 @@ We can target a specific build, in this example we specified: - The result type (--result) - The number of result (-top) -By default the command returns an entire JSON object with all the information. But we can narrow it down to the desired result with the `--query` param that uses [JMESPath](https://jmespath.org/) format ([more details](https://learn.microsoft.com/en-us/cli/azure/query-azure-cli?tabs=concepts%2Cbash)) - -Finally we extract the result in a common [custom variable](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash) named `BASE_SHA` used later by `nx affected` commands - -## Distribute Tasks Across Agents on Azure Pipelines - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can run this generator: - -```shell -npx nx g ci-workflow --ci=azure -``` - -Or you can copy and paste the workflow below: +By default the command returns an entire JSON object with all the information. But we can narrow it down to the desired +result with the `--query` param that uses [JMESPath](https://jmespath.org/) +format ([more details](https://learn.microsoft.com/en-us/cli/azure/query-azure-cli?tabs=concepts%2Cbash)) -```yaml {% fileName="azure-pipelines.yml" %} -trigger: - - main -pr: - - main - -variables: - CI: 'true' - ${{ if eq(variables['Build.Reason'], 'PullRequest') }}: - NX_BRANCH: $(System.PullRequest.PullRequestNumber) - TARGET_BRANCH: $[replace(variables['System.PullRequest.TargetBranch'],'refs/heads/','origin/')] - BASE_SHA: $(git merge-base $(TARGET_BRANCH) HEAD) - ${{ if ne(variables['Build.Reason'], 'PullRequest') }}: - NX_BRANCH: $(Build.SourceBranchName) - BASE_SHA: $(git rev-parse HEAD~1) - HEAD_SHA: $(git rev-parse HEAD) - -jobs: - - job: agents - strategy: - parallel: 3 - displayName: Nx Cloud Agent - pool: - vmImage: 'ubuntu-latest' - steps: - - script: npm ci - - script: npx nx-cloud start-agent - - - job: main - displayName: Nx Cloud Main - pool: - vmImage: 'ubuntu-latest' - steps: - # Get last successfull commit from Azure Devops CLI - - displayName: 'Get last successful commit SHA' - condition: ne(variables['Build.Reason'], 'PullRequest') - env: - AZURE_DEVOPS_EXT_PAT: $(System.AccessToken) - bash: | - LAST_SHA=$(az pipelines build list --branch $(Build.SourceBranchName) --definition-ids $(System.DefinitionId) --result succeeded --top 1 --query "[0].triggerInfo.\"ci.sourceSha\"") - if [ -z "$LAST_SHA" ] - then - echo "Last successful commit not found. Using fallback 'HEAD~1': $BASE_SHA" - else - echo "Last successful commit SHA: $LAST_SHA" - echo "##vso[task.setvariable variable=BASE_SHA]$LAST_SHA" - fi - - - script: git branch --track main origin/main - - script: npm ci - - script: npx nx-cloud start-ci-run --stop-agents-after="build" - - script: npx nx-cloud record -- nx format:check --base=$(BASE_SHA) --head=$(HEAD_SHA) - - script: npx nx affected --base=$(BASE_SHA) --head=$(HEAD_SHA) -t lint,test,build --parallel=2 --configuration=ci -``` - -This configuration is setting up two types of jobs - a main job and three agent jobs. - -The main job tells Nx Cloud to use DTE and then runs normal Nx commands as if this were a single pipeline set up. Once the commands are done, it notifies Nx Cloud to stop the agent jobs. - -The agent jobs set up the repo and then wait for Nx Cloud to assign them tasks. - -{% callout type="warning" title="Two Types of Parallelization" %} -The agent strategy of `parallel: 3` and the `nx affected --parallel=2` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} +Finally we extract the result in a +common [custom variable](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/set-variables-scripts?view=azure-devops&tabs=bash) +named `BASE_SHA` used later by `nx affected` commands diff --git a/docs/shared/monorepo-ci-bitbucket-pipelines.md b/docs/shared/monorepo-ci-bitbucket-pipelines.md index 705ad3b0f045f..d734089f838e0 100644 --- a/docs/shared/monorepo-ci-bitbucket-pipelines.md +++ b/docs/shared/monorepo-ci-bitbucket-pipelines.md @@ -1,10 +1,6 @@ # Configuring CI Using Bitbucket Pipelines and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on Bitbucket Pipelines - -Below is an example of an Bitbucket Pipelines setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an Bitbucket Pipelines, building and testing only what is affected. ```yaml {% fileName="bitbucket-pipelines.yml" %} image: node:20 @@ -16,9 +12,10 @@ pipelines: caches: # optional - node script: + - npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - npm ci - npx nx-cloud record -- nx format:check - - npx nx affected -t lint,test,build --base=origin/master --head=HEAD --configuration=ci + - npx nx affected -t lint test build --base=origin/master --head=HEAD branches: main: @@ -27,63 +24,10 @@ pipelines: caches: # optional - node script: + - npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - npm ci - npx nx-cloud record -- nx format:check - - npx nx affected -t lint,test,build --base=HEAD~1 --configuration=ci + - npx nx affected -t lint test build --base=HEAD~1 ``` The `pull-requests` and `main` jobs implement the CI workflow. - -## Distribute Tasks Across Agents on Bitbucket Pipelines - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can run this generator: - -```shell -npx nx g ci-workflow --ci=bitbucket-pipelines -``` - -Or you can copy and paste the workflow below: - -```yaml {% fileName="bitbucket-pipelines.yml" %} -image: node:20 - -clone: - depth: full - -definitions: - steps: - - step: &agent - name: Agent - script: - - export NX_BRANCH=$BITBUCKET_PR_ID - - - npm ci - - npx nx-cloud start-agent - -pipelines: - pull-requests: - '**': - - parallel: - - step: - name: CI - script: - - export NX_BRANCH=$BITBUCKET_PR_ID - - - npm ci - - npx nx-cloud start-ci-run --stop-agents-after="build" --agent-count=3 - - npx nx-cloud record -- nx format:check - - npx nx affected --target=lint,test,build --parallel=2 - - step: *agent - - step: *agent - - step: *agent -``` - -This configuration is setting up two types of jobs - a main job and three agent jobs. - -The main job tells Nx Cloud to use DTE and then runs normal Nx commands as if this were a single pipeline set up. Once the commands are done, it notifies Nx Cloud to stop the agent jobs. - -The agent jobs set up the repo and then wait for Nx Cloud to assign them tasks. - -{% callout type="warning" title="Two Types of Parallelization" %} -The agents and the `--parallel` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} diff --git a/docs/shared/monorepo-ci-circle-ci.md b/docs/shared/monorepo-ci-circle-ci.md index 9ff06d20e7e91..60948ca6b4221 100644 --- a/docs/shared/monorepo-ci-circle-ci.md +++ b/docs/shared/monorepo-ci-circle-ci.md @@ -1,10 +1,6 @@ # Configuring CI Using Circle CI and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on Circle CI - -Below is an example of an Circle CI setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an Circle CI setup, building and testing only what is affected. ```yaml {% fileName=".circleci/config.yml" %} version: 2.1 @@ -16,11 +12,12 @@ jobs: - image: cimg/node:lts-browsers steps: - checkout + - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - run: npm ci - nx/set-shas - run: npx nx-cloud record -- nx format:check - - run: npx nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=3 --configuration=ci + - run: npx nx affected --base=$NX_BASE --head=$NX_HEAD -t lint test build --parallel=3 workflows: build: jobs: @@ -40,65 +37,3 @@ To use the [Nx Orb](https://github.com/nrwl/nx-orb) with a private repository on {% callout type="warning" title="Caution" %} It should be a user token, not the project token. {% /callout %} - -## Distribute Tasks Across Agents on Circle CI - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can run this generator: - -```shell -npx nx g ci-workflow --ci=circleci -``` - -Or you can copy and paste the workflow below: - -```yaml {% fileName=".circleci/config.yml" %} -version: 2.1 -orbs: - nx: nrwl/nx@1.5.1 -jobs: - main: - docker: - - image: cimg/node:lts-browsers - steps: - - checkout - - run: npm ci - - nx/set-shas - - # Tell Nx Cloud to use DTE and stop agents when the build tasks are done - - run: npx nx-cloud start-ci-run --stop-agents-after=build - # Send logs to Nx Cloud for any CLI command - - run: npx nx-cloud record -- nx format:check - # Lint, test and build on agent jobs everything affected by a change - - run: npx nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=2 --configuration=ci - agent: - docker: - - image: cimg/node:lts-browsers - parameters: - ordinal: - type: integer - steps: - - checkout - - run: npm ci - # Wait for instructions from Nx Cloud - - run: - command: npx nx-cloud start-agent - no_output_timeout: 60m -workflows: - build: - jobs: - - agent: - matrix: - parameters: - ordinal: [1, 2, 3] - - main -``` - -This configuration is setting up two types of jobs - a main job and three agent jobs. - -The main job tells Nx Cloud to use DTE and then runs normal Nx commands as if this were a single pipeline set up. Once the commands are done, it notifies Nx Cloud to stop the agent jobs. - -The agent jobs set up the repo and then wait for Nx Cloud to assign them tasks. - -{% callout type="warning" title="Two Types of Parallelization" %} -The `ordinal: [1, 2, 3]` line and the `--parallel` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} diff --git a/docs/shared/monorepo-ci-github-actions.md b/docs/shared/monorepo-ci-github-actions.md index c70f58e4d4629..8760b9a7c831f 100644 --- a/docs/shared/monorepo-ci-github-actions.md +++ b/docs/shared/monorepo-ci-github-actions.md @@ -1,10 +1,6 @@ # Configuring CI Using GitHub Actions and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on GitHub Actions - -Below is an example of an GitHub Actions setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an GitHub Actions setup, building and testing only what is affected. ```yaml {% fileName=".github/workflows/ci.yml" %} name: CI @@ -32,206 +28,17 @@ jobs: with: node-version: 20 cache: 'npm' + - run: npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - run: npm ci - uses: nrwl/nx-set-shas@v3 # This line is needed for nx affected to work when CI is running on a PR - run: git branch --track main origin/main - run: npx nx-cloud record -- nx format:check - - run: npx nx affected -t lint,test,build --parallel=3 + - run: npx nx affected -t lint test build --parallel=3 ``` ### Get the Commit of the Last Successful Build `GitHub` can track the last successful run on the `main` branch and use this as a reference point for the `BASE`. The `nrwl/nx-set-shas` provides a convenient implementation of this functionality which you can drop into your existing CI config. To understand why knowing the last successful build is important for the affected command, check out the [in-depth explanation in Actions's docs](https://github.com/marketplace/actions/nx-set-shas#background). - -## Distribute Tasks Across Agents on GitHub Actions - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can run this generator: - -```shell -npx nx g ci-workflow --ci=github -``` - -Or you can copy and paste the workflow below: - -```yaml {% fileName=".github/workflows/ci.yml" %} -name: CI -on: - push: - branches: - - main - pull_request: - -# Needed for nx-set-shas when run on the main branch -permissions: - actions: read - contents: read - -jobs: - main: - name: Nx Cloud - Main Job - uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.13.0 - with: - number-of-agents: 3 - parallel-commands: | - npx nx-cloud record -- nx format:check - parallel-commands-on-agents: | - npx nx affected -t lint,test,build --parallel=2 - - agents: - name: Nx Cloud - Agents - uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.13.0 - with: - number-of-agents: 3 -``` - -This configuration is using two reusable workflows from the `nrwl/ci` repository. You can check out the full [API](https://github.com/nrwl/ci) for those workflows. - -The first workflow is for the main job: - -``` - uses: nrwl/ci/.github/workflows/nx-cloud-main.yml@v0.13.0 -``` - -The `parallel-commands` script will be run on the main job. The `parallel-commands-on-agents` script will be distributed across the available agents. - -The second workflow is for the agents: - -``` - uses: nrwl/ci/.github/workflows/nx-cloud-agents.yml@v0.13.0 -``` - -The `number-of-agents` property controls how many agent jobs are created. Note that this property should be the same number for each workflow. - -{% callout type="warning" title="Two Types of Parallelization" %} -The `number-of-agents` property and the `--parallel` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} - -## Custom Distributed CI with Nx Cloud on GitHub Actions - -Our [reusable GitHub workflow](https://github.com/nrwl/ci) represents a good set of defaults that works for a large number of our users. However, reusable GitHub workflows come with their [limitations](https://docs.github.com/en/actions/using-workflows/reusing-workflows). - -If the reusable workflow above doesn't satisfy your needs you should create a custom workflow. If you were to rewrite the reusable workflow yourself, it would look something like this: - -```yaml {% fileName=".github/workflows/ci.yml" %} -name: CI -on: - push: - branches: - - main - pull_request: - -# Needed for nx-set-shas when run on the main branch -permissions: - actions: read - contents: read - -env: - NX_CLOUD_DISTRIBUTED_EXECUTION: true # this enables DTE - NX_CLOUD_DISTRIBUTED_EXECUTION_AGENT_COUNT: 3 # expected number of agents - NX_BRANCH: ${{ github.event.number || github.ref_name }} - NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # this is needed if our pipeline publishes to npm - -jobs: - main: - name: Nx Cloud - Main Job - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - name: Checkout [Pull Request] - if: ${{ github.event_name == 'pull_request' }} - with: - # By default, PRs will be checked-out based on the Merge Commit, but we want the actual branch HEAD. - ref: ${{ github.event.pull_request.head.sha }} - # We need to fetch all branches and commits so that Nx affected has a base to compare against. - fetch-depth: 0 - - - uses: actions/checkout@v4 - name: Checkout [Default Branch] - if: ${{ github.event_name != 'pull_request' }} - with: - # We need to fetch all branches and commits so that Nx affected has a base to compare against. - fetch-depth: 0 - - # Set node/npm/yarn versions using volta - - uses: volta-cli/action@v4 - with: - package-json-path: '${{ github.workspace }}/package.json' - - - name: Use the package manager cache if available - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Check out the default branch - run: git branch --track main origin/main - - - name: Initialize the Nx Cloud distributed CI run and stop agents when the build tasks are done - run: npx nx-cloud start-ci-run --stop-agents-after=build - - - name: Run commands in parallel - run: | - # initialize an array to store process IDs (PIDs) - pids=() - - # function to run commands and store the PID - function run_command() { - local command=$1 - $command & # run the command in the background - pids+=($!) # store the PID of the background process - } - - # list of commands to be run on main has env flag NX_CLOUD_DISTRIBUTED_EXECUTION set to false - run_command "NX_CLOUD_DISTRIBUTED_EXECUTION=false npx nx-cloud record -- nx format:check" - - # list of commands to be run on agents - run_command "npx nx affected -t lint,test,build --parallel=3" - - # wait for all background processes to finish - for pid in ${pids[*]}; do - if ! wait $pid; then - exit 1 # exit with an error status if any process fails - fi - done - - exit 0 # exits with success status if a all processes complete successfully - - agents: - name: Agent ${{ matrix.agent }} - runs-on: ubuntu-latest - strategy: - matrix: - # Add more agents here as your repository expands - agent: [1, 2, 3] - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Set node/npm/yarn versions using volta - - uses: volta-cli/action@v4 - with: - package-json-path: '${{ github.workspace }}/package.json' - - - name: Use the package manager cache if available - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Start Nx Agent ${{ matrix.agent }} - run: npx nx-cloud start-agent - env: - NX_AGENT_NAME: ${{ matrix.agent }} -``` - -There are comments throughout the workflow to help you understand what is happening in each section. diff --git a/docs/shared/monorepo-ci-gitlab.md b/docs/shared/monorepo-ci-gitlab.md index 339a5b61e06a2..a53b5fc65cd4e 100644 --- a/docs/shared/monorepo-ci-gitlab.md +++ b/docs/shared/monorepo-ci-gitlab.md @@ -1,10 +1,6 @@ # Configuring CI Using GitLab and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on GitLab - -Below is an example of an GitLab setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an GitLab setup, building and testing only what is affected. ```yaml {% fileName=".gitlab-ci.yml" %} image: node:18 @@ -26,6 +22,7 @@ stages: paths: - .npm/ before_script: + - npx nx-cloud start-ci-run --distribute-on="5 linux-medium-js" --stop-agents-after="build" # this line enables distribution - npm ci --cache .npm --prefer-offline - NX_HEAD=$CI_COMMIT_SHA - NX_BASE=${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_BEFORE_SHA} @@ -49,7 +46,7 @@ test: stage: test extends: .distributed script: - - npx nx affected --base=$NX_BASE --head=$NX_HEAD -t test --parallel=3 --configuration=ci + - npx nx affected --base=$NX_BASE --head=$NX_HEAD -t test --parallel=3 build: stage: build @@ -57,83 +54,3 @@ build: script: - npx nx affected --base=$NX_BASE --head=$NX_HEAD -t build --parallel=3 ``` - -The `build` and `test` jobs implement the CI workflow using `.distributed` as a template to keep the CI configuration file more readable. - -## Distribute Tasks Across Agents on GitLab - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can run this generator: - -```shell -npx nx g ci-workflow --ci=gitlab -``` - -Or you can copy and paste the workflow below: - -```yaml {% fileName=".gitlab-ci.yml" %} -image: node:18 - -# Creating template for DTE agents -.dte-agent: - interruptible: true - cache: - key: - files: - - yarn.lock - paths: - - '.yarn-cache/' - script: - - yarn install --cache-folder .yarn-cache --prefer-offline --frozen-lockfile - - yarn nx-cloud start-agent - -# Creating template for a job running DTE (orchestrator) -.base-pipeline: - interruptible: true - only: - - main - - merge_requests - cache: - key: - files: - - yarn.lock - paths: - - '.yarn-cache/' - before_script: - - yarn install --cache-folder .yarn-cache --prefer-offline --frozen-lockfile - - NX_HEAD=$CI_COMMIT_SHA - - NX_BASE=${CI_MERGE_REQUEST_DIFF_BASE_SHA:-$CI_COMMIT_BEFORE_SHA} - artifacts: - expire_in: 5 days - paths: - - dist - -# Main job running DTE -nx-dte: - stage: affected - extends: .base-pipeline - script: - - yarn nx-cloud start-ci-run --stop-agents-after=build - - yarn nx-cloud record -- nx format:check --base=$NX_BASE --head=$NX_HEAD - - yarn nx affected --base=$NX_BASE --head=$NX_HEAD -t lint,test,build --parallel=2 - -# Create as many agents as you want -nx-dte-agent1: - extends: .dte-agent - stage: affected -nx-dte-agent2: - extends: .dte-agent - stage: affected -nx-dte-agent3: - extends: .dte-agent - stage: affected -``` - -This configuration is setting up two types of jobs - a main job and three agent jobs. - -The main job tells Nx Cloud to use DTE and then runs normal Nx commands as if this were a single pipeline set up. Once the commands are done, it notifies Nx Cloud to stop the agent jobs. - -The agent jobs set up the repo and then wait for Nx Cloud to assign them tasks. - -{% callout type="warning" title="Two Types of Parallelization" %} -The agents and the `--parallel` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} diff --git a/docs/shared/monorepo-ci-jenkins.md b/docs/shared/monorepo-ci-jenkins.md index e8ce0c481c6d0..b5320cc6642b6 100644 --- a/docs/shared/monorepo-ci-jenkins.md +++ b/docs/shared/monorepo-ci-jenkins.md @@ -1,10 +1,6 @@ # Configuring CI Using Jenkins and Nx -There are two general approaches to setting up CI with Nx - using a single job or distributing tasks across multiple jobs. For smaller repositories, a single job is faster and cheaper, but once a full CI run starts taking 10 to 15 minutes, using multiple jobs becomes the better option. Nx Cloud's distributed task execution allows you to keep the CI pipeline fast as you scale. As the repository grows, all you need to do is add more agents. - -## Process Only Affected Projects With One Job on Jenkins - -Below is an example of an Jenkins setup that runs on a single job, building and testing only what is affected. This uses the [`nx affected` command](/ci/features/affected) to run the tasks only for the projects that were affected by that PR. +Below is an example of an Jenkins setup, building and testing only what is affected. ```groovy pipeline { @@ -21,9 +17,10 @@ pipeline { } agent any steps { + sh "npx nx-cloud start-ci-run --distribute-on='5 linux-medium-js' --stop-agents-after='build'" // this line enables distribution sh "npm ci" sh "npx nx-cloud record -- nx format:check" - sh "npx nx affected --base=HEAD~1 -t lint,test,build --parallel=3" + sh "npx nx affected --base=HEAD~1 -t lint test build --parallel=3" } } stage('PR') { @@ -32,9 +29,10 @@ pipeline { } agent any steps { + sh "npx nx-cloud start-ci-run --distribute-on='5 linux-medium-js' --stop-agents-after='build'" // this line enables distribution sh "npm ci" sh "npx nx-cloud record -- nx format:check" - sh "npx nx affected --base origin/${env.CHANGE_TARGET} -t lint,test,build --parallel=3" + sh "npx nx affected --base origin/${env.CHANGE_TARGET} -t lint test build --parallel=3" } } } @@ -48,79 +46,3 @@ pipeline { Unlike `GitHub Actions` and `CircleCI`, you don't have the metadata to help you track the last successful run on `main`. In the example below, the base is set to `HEAD~1` (for push) or branching point (for pull requests), but a more robust solution would be to tag an SHA in the main job once it succeeds and then use this tag as a base. See the [nx-tag-successful-ci-run](https://github.com/nrwl/nx-tag-successful-ci-run) and [nx-set-shas](https://github.com/nrwl/nx-set-shas) (version 1 implements tagging mechanism) repositories for more information. We also have to set `NX_BRANCH` explicitly. - -## Distribute Tasks Across Agents on Jenkins - -To set up [Distributed Task Execution (DTE)](/ci/features/distribute-task-execution), you can copy and paste the workflow below: - -```groovy -pipeline { - agent none - environment { - NX_BRANCH = env.BRANCH_NAME.replace('PR-', '') - } - stages { - stage('Pipeline') { - parallel { - stage('Main') { - when { - branch 'main' - } - agent any - steps { - sh "npm ci" - sh "npx nx-cloud start-ci-run --stop-agents-after='build'" - sh "npx nx-cloud record -- nx format:check" - sh "npx nx affected --base=HEAD~1 -t lint --parallel=3 & npx nx affected --base=HEAD~1 -t test --parallel=3 --configuration=ci & npx nx affected --base=HEAD~1 -t build --parallel=3" - } - } - stage('PR') { - when { - not { branch 'main' } - } - agent any - steps { - sh "npm ci" - sh "npx nx-cloud start-ci-run --stop-agents-after='build'" - sh "npx nx-cloud record -- nx format:check" - sh "npx nx affected --base origin/${env.CHANGE_TARGET} -t lint --parallel=2 & npx nx affected --base origin/${env.CHANGE_TARGET} -t test --parallel=2 --configuration=ci & npx nx affected --base origin/${env.CHANGE_TARGET} -t build --parallel=2" - } - } - - # Add as many agent you want - stage('Agent1') { - agent any - steps { - sh "npm ci" - sh "npx nx-cloud start-agent" - } - } - stage('Agent2') { - agent any - steps { - sh "npm ci" - sh "npx nx-cloud start-agent" - } - } - stage('Agent3') { - agent any - steps { - sh "npm ci" - sh "npx nx-cloud start-agent" - } - } - } - } - } -} -``` - -This configuration is setting up two types of jobs - a main job and three agent jobs. - -The main job tells Nx Cloud to use DTE and then runs normal Nx commands as if this were a single pipeline set up. Once the commands are done, it notifies Nx Cloud to stop the agent jobs. - -The agent jobs set up the repo and then wait for Nx Cloud to assign them tasks. - -{% callout type="warning" title="Two Types of Parallelization" %} -The agents and the `--parallel` flag both parallelize tasks, but in different ways. The way this workflow is written, there will be 3 agents running tasks and each agent will try to run 2 tasks at once. If a particular CI run only has 2 tasks, only one agent will be used. -{% /callout %} diff --git a/docs/shared/monorepo-nx-enterprise.md b/docs/shared/monorepo-nx-enterprise.md index d8d2e540449b5..6f453668412fc 100644 --- a/docs/shared/monorepo-nx-enterprise.md +++ b/docs/shared/monorepo-nx-enterprise.md @@ -148,7 +148,7 @@ For a large organization it's crucial to establish how projects can depend on ea feature libraries. Nx provides a feature called tags that can be used to codify and statically-enforce these rules. Read more about -tags [here](/core-features/enforce-module-boundaries). +tags [here](/features/enforce-module-boundaries). ## Code Ownership diff --git a/docs/shared/node-server-tutorial/1-code-generation.md b/docs/shared/node-server-tutorial/1-code-generation.md deleted file mode 100644 index 28ce09252ca1e..0000000000000 --- a/docs/shared/node-server-tutorial/1-code-generation.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 1: Code Generation' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -{% callout type="check" title="Two Styles of Repo" %} -There are two styles of repos: integrated and package-based. This tutorial shows the integrated style. - -You can find more information on the difference between the two in [our introduction](/getting-started/intro). -{% /callout %} - -{% youtube -src="https://www.youtube.com/embed/-Oe8j-NZcBc" -title="Tutorial: Node Server" -/%} - -# Node Server Tutorial - Part 1: Code Generation - -In this tutorial you'll create a backend-focused workspace with Nx. - -## Contents - -- [1 - Code Generation](/node-server-tutorial/1-code-generation) -- [2 - Project Graph](/node-server-tutorial/2-project-graph) -- [3 - Task Running](/node-server-tutorial/3-task-running) -- [4 - Task Pipelines](/node-server-tutorial/4-task-pipelines) -- [5 - Docker Target](/node-server-tutorial/5-docker-target) -- [6 - Summary](/node-server-tutorial/6-summary) - -## Your Objective - -For this tutorial, you'll create an Express API application, a library that the API can reference to handle authentication and a suite of e2e tests. - -## Creating an Nx Workspace - -Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses: - -```{% command="npx create-nx-workspace@latest" path="~" %} - - > NX Let's create a new workspace [https://nx.dev/getting-started/intro] - -✔ Where would you like to create your workspace? · products-api -✔ Which stack do you want to use? · node -✔ What framework should be used? · express -✔ Standalone project or integrated monorepo? · standalone -✔ Would you like to generate a Dockerfile? [https://docs.docker.com/] · Yes -✔ Do you want Nx Cloud to make your CI fast? · Yes -``` - -{% card title="Opting into Nx Cloud" description="You will also be prompted whether to add Nx Cloud to your workspace. We won't address this in this tutorial, but you can see the introduction to Nx Cloud for more details." url="/ci/intro/ci-with-nx" /%} - -The `node-standalone` preset automatically creates a `products-api` application at the root of the workspace and an `e2e` project that runs against it. - -{% callout type="note" title="Framework Options" %} -This tutorial uses the `express` framework. The `node-standalone` preset also provides starter files for `koa` and `fastify`. For other frameworks, you can choose `none` and add a it yourself. -{% /callout %} - -## Generating Libraries - -To create the `auth` library, use the `@nx/node:lib` generator: - -![Nx Generator Syntax](/shared/node-server-tutorial/generator-syntax.svg) - -```{% command="npx nx g @nx/node:lib auth --buildable" path="~/products-api" %} -> NX Generating @nx/node:library - -CREATE auth/README.md -CREATE auth/.babelrc -CREATE auth/package.json -CREATE auth/src/index.ts -CREATE auth/src/lib/auth.spec.ts -CREATE auth/src/lib/auth.ts -CREATE auth/tsconfig.json -CREATE auth/tsconfig.lib.json -UPDATE tsconfig.json -UPDATE package.json -CREATE auth/project.json -CREATE .eslintrc.base.json -UPDATE .eslintrc.json -UPDATE e2e/.eslintrc.json -CREATE auth/.eslintrc.json -CREATE jest.config.app.ts -UPDATE jest.config.ts -UPDATE project.json -CREATE auth/jest.config.ts -CREATE auth/tsconfig.spec.json -``` - -You have now created three projects: - -- `products-api` in `/` -- `e2e` in `/e2e` -- `auth` in `/auth` - -## What's Next - -- Continue to [2: Project Graph](/node-server-tutorial/2-project-graph) diff --git a/docs/shared/node-server-tutorial/2-project-graph.md b/docs/shared/node-server-tutorial/2-project-graph.md deleted file mode 100644 index aa34ee460572f..0000000000000 --- a/docs/shared/node-server-tutorial/2-project-graph.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 2: Project Graph' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -# Node Server Tutorial - Part 2: Project Graph - -Run the command: `npx nx graph`. A browser should open up with the following contents: - -{% graph height="200px" type="project" jsonFile="shared/node-server-tutorial/initial-project-graph.json" %} -{% /graph %} - -You'll notice that there is no dependency drawn from `products-api` to the `auth` library. The project graph is derived from the source code of your workspace. Once we actually wire everything up, the project graph will update accordingly. - -### `auth` - -Update the contents of the generated `auth.ts` file: - -```typescript {% fileName="auth/src/lib/auth.ts" %} -export type AuthResponse = AuthSuccessResponse | AuthFailureResponse; -export interface AuthSuccessResponse { - success: true; - name: string; -} -export interface AuthFailureResponse { - success: false; -} - -export function doAuth(): AuthResponse { - return { success: true, name: 'Cheddar' }; -} -``` - -### `products-api` - -Add a post endpoint to the `main.ts` file of the root project that uses the `doAuth()` function. - -```typescript {% fileName="src/main.ts" %} -import express from 'express'; -import { doAuth } from 'auth'; - -const host = process.env.HOST ?? 'localhost'; -const port = process.env.PORT ? Number(process.env.PORT) : 3000; - -const app = express(); - -app.get('/', (req, res) => { - res.send({ message: 'Hello API' }); -}); - -app.post('/auth', (req, res) => { - res.send(doAuth()); -}); - -app.listen(port, host, () => { - console.log(`[ ready ] http://${host}:${port}`); -}); -``` - -{% callout type="note" title="Typescript Paths" %} -When a library is created, Nx adds a new Typescript path to the `tsconfig.base.json` file. The running Typescript server process inside of your editor sometimes doesn't pick up these changes and you have to restart the server to remove inline errors on your import statements. This can be done in VS Code from the command palette when viewing a typescript file (Command-Shift-P) "Typescript: Restart TS server" -{% /callout %} - -### `e2e` - -Update the e2e tests to check the new `/auth` endpoint. - -```javascript {% fileName="e2e/src/server/server.spec.ts" %} -import axios from 'axios'; - -describe('GET /', () => { - it('should return a message', async () => { - const res = await axios.get(`/`); - - expect(res.status).toBe(200); - expect(res.data).toEqual({ message: 'Hello API' }); - }); -}); - -describe('POST /auth', () => { - it('should return a status and a name', async () => { - const res = await axios.post(`/auth`, {}); - - expect(res.status).toBe(200); - expect(res.data).toEqual({ success: true, name: 'Cheddar' }); - }); -}); -``` - -Now run `npx nx graph` again: - -{% graph height="200px" type="project" jsonFile="shared/node-server-tutorial/final-project-graph.json" %} -{% /graph %} - -The graph now shows the dependency between `products-api` and `auth`. - -The project graph is more than just a visualization - Nx provides tooling to optimize your task-running and even automate your CI based on this graph. This will be covered in more detail in: [4: Task Pipelines](/node-server-tutorial/4-task-pipelines). - -## What's Next - -- Continue to [3: Task Running](/node-server-tutorial/3-task-running) diff --git a/docs/shared/node-server-tutorial/3-task-running.md b/docs/shared/node-server-tutorial/3-task-running.md deleted file mode 100644 index 39ca6e52ea4a7..0000000000000 --- a/docs/shared/node-server-tutorial/3-task-running.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 3: Task-Running' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -# Node Server Tutorial - Part 3: Task-Running - -Common tasks include: - -- Building an application -- Serving an application locally for development purposes -- Running your unit tests -- Linting your code - -When you ran your generators in Part 1, you already set up these common tasks for each project. - -## Defining Targets - -Here's the `project.json` file for the `auth` project: - -```json {% fileName="/auth/project.json" %} -{ - "name": "auth", - "$schema": "../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "auth/src", - "projectType": "library", - "targets": { - "build": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/./auth", - "tsConfig": "auth/tsconfig.lib.json", - "packageJson": "auth/package.json", - "main": "auth/src/index.ts", - "assets": ["auth/*.md"] - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "lintFilePatterns": ["auth/**/*.ts"] - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "auth/jest.config.ts", - "passWithNoTests": true - }, - "configurations": { - "ci": { - "ci": true, - "codeCoverage": true - } - } - } - }, - "tags": [] -} -``` - -You can see that three targets are defined here: `build`, `test` and `lint`. - -The properties of these targets are defined as follows: - -- `executor` - which Nx executor to run. The syntax here is: `:` -- `outputs` - this is an array of files that would be created by running this target. (This informs Nx on what to save for it's caching mechanisms you'll learn about in [4 - Task Pipelines](/node-server-tutorial/4-task-pipelines)). -- `options` - this is an object defining which executor options to use for the given target. Every Nx executor allows for options as a way to parameterize it's functionality. - -## Running Tasks - -![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) - -Run the `build` target for your `auth` project: - -```{% command="npx nx build auth" path="~/products-api" %} - -> nx run auth:build - -Compiling TypeScript files for project "auth"... -Done compiling TypeScript files for project "auth". - - ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project auth (1s) -``` - -You can now find your built `auth` distributable in your `dist/auth/` directory, as specified in the `outputPath` property of the `build` target options in your `project.json` file. - -Next, run a lint check on `auth`: - -```{% command="npx nx lint auth" path="~/products-api" %} - -> nx run auth:lint - - -Linting "auth"... - -All files pass linting. - - - ——————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target lint for project products-api (777ms) -``` - -## Run e2e Tests - -To run the e2e tests, you first need to serve the root `products-api` project: - -```{% command="npx nx serve products-api" path="~/products-api" %} -> nx run products-api:serve - -Debugger listening on ws://localhost:9229/5ee3e454-1e38-4d9b-a5de-64a4cb1e21b9 -Debugger listening on ws://localhost:9229/5ee3e454-1e38-4d9b-a5de-64a4cb1e21b9 -For help, see: https://nodejs.org/en/docs/inspector -[ ready ] http://localhost:3000 -[ watch ] build succeeded, watching for changes... -``` - -Then you can run the e2e tests from the `e2e` project in a separate terminal: - -```{% command="npx nx e2e e2e" path="~/products-api" %} -> nx run e2e:e2e - -Determining test suites to run... -Setting up... - - PASS e2e e2e/src/server/server.spec.ts - GET / - ✓ should return a message (39 ms) - POST /auth - ✓ should return a status and a name (19 ms) - -Test Suites: 1 passed, 1 total -Tests: 2 passed, 2 total -Snapshots: 0 total -Time: 0.263 s, estimated 1 s -Ran all test suites. - -Tearing down... - - - ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target e2e for project e2e (2s) -``` - -## What's Next - -- Continue to [4: Task Pipelines](/node-server-tutorial/4-task-pipelines) diff --git a/docs/shared/node-server-tutorial/4-task-pipelines.md b/docs/shared/node-server-tutorial/4-task-pipelines.md deleted file mode 100644 index d75c660bb5a62..0000000000000 --- a/docs/shared/node-server-tutorial/4-task-pipelines.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 4: Task Pipelines' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -# Node Server Tutorial - Part 4: Task Pipelines - -## Running Dependent Tasks - -Let's build the `products-api` application: - -```{% command="npx nx build products-api" path="~/products-api" %} - - ✔ 1/1 dependent project tasks succeeded [0 read from cache] - - Hint: you can run the command with --verbose to see the full dependent project outputs - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - -> nx run products-api:build:production - -✔ Browser application bundle generation complete. -✔ Copying assets complete. -✔ Index html generation complete. - -Initial Chunk Files | Names | Raw Size | Estimated Transfer Size -main.dc68f58360ec52f7.js | main | 203.69 kB | 55.81 kB -polyfills.19459ef8805e51da.js | polyfills | 33.04 kB | 10.64 kB -runtime.639feb9584ec9047.js | runtime | 2.62 kB | 1.23 kB -styles.ef46db3751d8e999.css | styles | 0 bytes | - - - | Initial Total | 239.35 kB | 67.68 kB - -Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size -967.25ab9a0a8950995f.js | store-cart | 719 bytes | 395 bytes - -Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms - - ————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project products-api and 1 task(s) they depend on (9s) - -``` - -Notice this line: - -```shell - ✔ 1/1 dependent project tasks succeeded [0 read from cache] -``` - -When you run a task, Nx will run all the task's dependencies before running the task you specified. This ensures all the needed artifacts are in place before the task is run. - -## Configuring Task Pipelines - -Nx can infer how projects depend on each other by examining the source code, but Nx doesn't know which tasks depend on each other. - -In the `nx.json` file you can see the default set up: - -```json -{ - "targetDefaults": { - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"] - } - } -} -``` - -The `"dependsOn": ["^build"]` line says that every `build` task depends on the `build` tasks for its project dependencies. You can override the `dependsOn` setting for individual projects in the `project.json` files. - -{% card title="More On The Task Pipeline Configuration" description="See the Task Pipeline Configuration Guide for more details on how to configure your Task Graph." url="/concepts/task-pipeline-configuration" /%} - -## Skip Repeated Tasks - -Why does Nx always run the dependent tasks? Doesn't that waste time repeating the same work? - -It would, if Nx didn't have a robust caching mechanism to take care of that problem for you. Let's build the `products-api` app again. - -```{% command="npx nx build products-api" path="~/products-api" %} - - ✔ 1/1 dependent project tasks succeeded [1 read from cache] - - Hint: you can run the command with --verbose to see the full dependent project outputs - - ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - -> nx run store:build:production [existing outputs match the cache, left as is] - - -Initial Chunk Files | Names | Raw Size | Estimated Transfer Size -main.dc68f58360ec52f7.js | main | 203.69 kB | 55.81 kB -polyfills.19459ef8805e51da.js | polyfills | 33.04 kB | 10.64 kB -runtime.639feb9584ec9047.js | runtime | 2.62 kB | 1.23 kB -styles.ef46db3751d8e999.css | styles | 0 bytes | - - - | Initial Total | 239.35 kB | 67.68 kB - -Lazy Chunk Files | Names | Raw Size | Estimated Transfer Size -967.25ab9a0a8950995f.js | store-cart | 719 bytes | 395 bytes - -Build at: 2022-11-30T16:44:43.171Z - Hash: 9850ece7cc7c6b7c - Time: 6527ms - - ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target build for project store and 1 task(s) they depend on (13ms) - - Nx read the output from the cache instead of running the command for 2 out of 2 tasks. -``` - -This time the build only took 13 ms. Also, if you delete the `dist` folder and run the command again, the build output will be recreated. - -{% card title="More Task Caching Details" description="See the documentation for more information on caching." url="/core-features/cache-task-results" /%} - -## Cache Inputs and Outputs - -How does Nx know when to replace a cached task result? And how does Nx know what should be cached? - -Nx determines if a project has been modified by looking at the task's defined `inputs`. And then when the task is completed, it caches the terminal output and all the defined file `outputs`. - -### Inputs - -When you run a task, Nx uses the inputs for your task to create a hash that is used as an index for the task results. If the task has already been run with the same inputs, Nx replays the results stored in the cache. - -If this index does not exist, Nx runs the command and if the command succeeds, it stores the result in the cache. - -{% card title="More On Customizing Inputs" description="See the Customizing Inputs Guide for more details on how to set inputs for your tasks." url="/concepts/task-pipeline-configuration" /%} - -### Outputs - -Outputs of the cache include the terminal output created by the task, as well as any files created by the task - for example: the artifact created by running a `build` task. - -Here are the outputs defined for the `auth` project: - -```json {% fileName="auth/project.json" %} -{ - "name": "auth", - "targets": { - "build": { - "executor": "@nx/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/auth" - } - }, - "lint": { - "executor": "@nx/eslint:lint", - "outputs": ["{options.outputFile}"], - "options": { - "outputFile": "dist/auth/lint-report.txt" - } - }, - "test": { - "executor": "@nx/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": {} - } - }, - "tags": [] -} -``` - -Outputs are stored in the cache so that terminal output can be replayed, and any created files can be pulled from your cache, and placed where they were created the original time the task was run. - -## Testing Affected Projects - -Another way that Nx saves you from unnecessary work is the `affected` command. `affected` is a mechanism that relies on your git metadata to determine the projects in your workspace that were affected by a given commit. - -Run the command: - -```shell -git add . ; git commit -m "commiting to test affected" -``` - -Then make a change to an endpoint of your `products-api` project: - -```ts {% fileName="src/main.ts" %} -import express from 'express'; -import { doAuth } from 'auth'; - -const host = process.env.HOST ?? 'localhost'; -const port = process.env.PORT ? Number(process.env.PORT) : 3000; - -const app = express(); - -app.get('/', (req, res) => { - res.send({ message: 'Hello modified API' }); -}); - -app.post('/auth', (req, res) => { - res.send(doAuth()); -}); - -app.listen(port, host, () => { - console.log(`[ ready ] http://${host}:${port}`); -}); -``` - -You can visualize how our workspace is affected by this change using the command: - -```shell -npx nx affected:graph -``` - -{% graph height="450px" jsonFile="shared/node-server-tutorial/affected-project-graph.json" %} -{% /graph %} - -The change made to the `products-api` project is also affecting the `e2e` project. This can be leveraged to run tasks only on the projects that were affected by this commit. - -To run the `lint` targets only for affected projects, run the command: - -```shell -npx nx affected -t lint -``` - -This can be particularly helpful in CI pipelines for larger repos, where most commits only affect a small subset of the entire workspace. - -{% card title="Affected Documentation" description="Checkout Affected documentation for more details" url="/nx-api/nx/documents/affected" /%} - -## What's Next - -- Continue to [5: Docker Target](/node-server-tutorial/5-docker-target) diff --git a/docs/shared/node-server-tutorial/5-docker-target.md b/docs/shared/node-server-tutorial/5-docker-target.md deleted file mode 100644 index d287e80716d8e..0000000000000 --- a/docs/shared/node-server-tutorial/5-docker-target.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 5: Docker Target' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -# Node Server Tutorial - Part 5: Docker Target - -## Using Docker - -Let's take a look at the `Dockerfile` that was generated when we first created the repo. - -```{% filename="/Dockerfile" %} -# This file is generated by Nx. -# -# Build the docker image with `npx nx docker-build products-api`. -# Tip: Modify "docker-build" options in project.json to change docker build args. -# -# Run the container with `docker run -p 3000:3000 -t products-api`. -FROM docker.io/node:lts-alpine - -ENV HOST=0.0.0.0 -ENV PORT=3000 - -WORKDIR /app - -RUN addgroup --system products-api && \ - adduser --system -G products-api products-api - -COPY dist/products-api products-api -RUN chown -R products-api:products-api . - -CMD [ "node", "products-api" ] -``` - -There is also an Nx target to build your Docker image. - -```{% command="npx nx docker-build products-api" path="~/products-api" %} -> nx run products-api:build - - -> nx run products-api:docker-build - -#1 [internal] load build definition from Dockerfile -#1 sha256:4c99d8269ea9b513bd4dc776dba71aa66d5829ea8e590b8aeb803a2067f59cd7 -#1 transferring dockerfile: 37B done -#1 DONE 0.0s -#2 [internal] load .dockerignore -#2 sha256:e71d5f0270d20785d8ae5f235f0abefd0806a3001ce09bbd5fd6f34cb8b1ca81 -#2 transferring context: 2B done -#2 DONE 0.0s -#3 [internal] load metadata for docker.io/library/node:lts-alpine -#3 sha256:e161ecf2e6f1cf45a4881933800e629a1213e55a987b539a70bb5826846509fd -#3 DONE 0.2s -#8 [1/5] FROM docker.io/library/node:lts-alpine@sha256:fda98168118e5a8f4269efca4101ee51dd5c75c0fe56d8eb6fad80455c2f5827 -#8 sha256:00cf67cfc27afade2e1236f1196ec1d784e6c26792e57b580683350c09199e48 -#8 DONE 0.0s -#9 [internal] load build context -#9 sha256:9103d257e071bd890d889058da8bff61c78e8bb01b7ed24337b78f75e8830218 -#9 transferring context: 1.70MB 0.1s done -#9 DONE 0.1s -#4 [2/5] WORKDIR /app -#4 sha256:17db46c2fd7998a5902ae01d80def26aa254289bbab2c6fc5aacc55252ac84b0 -#4 CACHED -#5 [3/5] RUN addgroup --system products-api && adduser --system -G products-api products-api -#5 sha256:b44659fc59b4a2b2d6e4ab5e87ab46bcef11185d06154f4b1ec6d7a1753379f2 -#5 CACHED -#6 [4/5] COPY dist/products-api products-api -#6 sha256:b903d3e7efcc38acf17f87fc8de482eb267fe0269156e8862cf149cdee04c2df -#6 CACHED -#7 [5/5] RUN chown -R products-api:products-api . -#7 sha256:250b9a198f6002246bab3725d205af49d6327990451320d8642f56b9882f4f0a -#7 CACHED -#10 exporting to image -#10 sha256:e8c613e07b0b7ff33893b694f7759a10d42e180f2b4dc349fb57dc6b71dcab00 -#10 exporting layers done -#10 writing image sha256:e3543d878821de18de83201719f1f333bb7072a50e42216ff5c253db9081ce71 done -#10 naming to docker.io/library/products-api done -#10 DONE 0.0s -Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them - - ———————————————————————————————————————————————————————————————————————————————————————————————————————————— - - > NX Successfully ran target docker-build for project products-api and 1 task it depends on (2s) - - View logs and investigate cache misses at https://nx.app/runs/NrNdfzx12g -``` - -The `docker-build` command is defined as a target in the root `project.json` file. If you need to make any modifications to the command, you can make them there. Note that this target is set up so that the `build` target will always be run first. - -```json {% filename="/project.json" %} -{ - "targets": { - "docker-build": { - "dependsOn": ["build"], - "command": "docker build -f orders-api/Dockerfile . -t orders-api" - } - } -} -``` - -## Generate a Micro-service with a Docker File - -You can also add a `Dockerfile` to a new node app using the `--docker` flag. Here we're creating an `orders-api` application: - -```{% command="npx nx g @nx/node:app orders-api --docker" path="~/products-api" %} -> NX Generating @nx/node:application - -✔ Which framework do you want to use? · express -CREATE orders-api/src/assets/.gitkeep -CREATE orders-api/src/main.ts -CREATE orders-api/tsconfig.app.json -CREATE orders-api/tsconfig.json -CREATE orders-api/project.json -CREATE orders-api/.eslintrc.json -CREATE orders-api/jest.config.ts -CREATE orders-api/tsconfig.spec.json -CREATE orders-api-e2e/project.json -CREATE orders-api-e2e/jest.config.ts -CREATE orders-api-e2e/src/orders-api/orders-api.spec.ts -CREATE orders-api-e2e/src/support/global-setup.ts -CREATE orders-api-e2e/src/support/global-teardown.ts -CREATE orders-api-e2e/src/support/test-setup.ts -CREATE orders-api-e2e/tsconfig.json -CREATE orders-api-e2e/tsconfig.spec.json -CREATE orders-api-e2e/.eslintrc.json -CREATE orders-api/Dockerfile -``` - -## What's Next - -- Continue to [6: Summary](/node-server-tutorial/6-summary) diff --git a/docs/shared/node-server-tutorial/6-summary.md b/docs/shared/node-server-tutorial/6-summary.md deleted file mode 100644 index 0ca9262dcc92e..0000000000000 --- a/docs/shared/node-server-tutorial/6-summary.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: 'Node Server Tutorial - Part 6: Summary' -description: In this tutorial you'll create a backend-focused workspace with Nx. ---- - -# Node Server Tutorial - Part 6: Summary - -In this tutorial you: - -- Learned how to use Nx's Generators to generate code for your workspace. -- Learned how Nx determines a graph of your workspace -- Learned how to configure and run tasks in your workspace -- Learned how Nx's built-in optimizations work, and how to apply those to your own workspace -- Learned how Nx can create a simple Dockerfile for you - -## Learn More - -{% cards %} - -{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%} - -{% card title="Plugin Features" description="Read about the plugin features of Nx." url="/core-features/plugin-features" /%} - -{% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%} - -{% card title="Adopting Nx" description="Learn how to add Nx to your existing repo." url="/recipes/adopting-nx" /%} - -{% /cards %} diff --git a/docs/shared/node-server-tutorial/affected-project-graph.json b/docs/shared/node-server-tutorial/affected-project-graph.json deleted file mode 100644 index e419354106aa4..0000000000000 --- a/docs/shared/node-server-tutorial/affected-project-graph.json +++ /dev/null @@ -1,344 +0,0 @@ -{ - "hash": "69d706f56987672f5650b3b4007076d431d26232d3c1a09f4fe5af46daf8301b", - "projects": [ - { - "name": "auth", - "type": "lib", - "data": { - "tags": [], - "root": "auth", - "files": [ - { - "file": "auth/.babelrc", - "hash": "cf7ddd99c615a064ac18eb3109eee4f394ab1faf" - }, - { - "file": "auth/.eslintrc.json", - "hash": "2ecc0fb3287e0c1e27691b519c3a058a3248ab44" - }, - { - "file": "auth/jest.config.ts", - "hash": "9a572192bd6837978590302b51b89644e075ed71" - }, - { - "file": "auth/package.json", - "hash": "802cad57c0ab5b838834efc500b28f342cc33fd0" - }, - { - "file": "auth/project.json", - "hash": "c93aa4cc32972ac2dcfeacbffee3b73d8a529383" - }, - { - "file": "auth/README.md", - "hash": "e895849f0d4f455473302f8dd795da5f2ff2dfab" - }, - { - "file": "auth/src/index.ts", - "hash": "2953bfc1d2b036689276d7f95bd6653b2a487993" - }, - { - "file": "auth/src/lib/auth.spec.ts", - "hash": "6b29b9cb382148b049b80a7a1ba6ec98193f90a6" - }, - { - "file": "auth/src/lib/auth.ts", - "hash": "87694589f307699e63ba8041cc774165851f359e" - }, - { - "file": "auth/tsconfig.json", - "hash": "f1a0ff5ec6a6f796fa26b4a8c82e74632b92a031" - }, - { - "file": "auth/tsconfig.lib.json", - "hash": "53c4ac8d833637e0dca7b03920b04cae26d9c5bb" - }, - { - "file": "auth/tsconfig.spec.json", - "hash": "fdb45891ed0c135fa82a503b4f115e31fe36bf91" - } - ], - "targets": { - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"], - "executor": "@nrwl/js:tsc", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist/./auth", - "tsConfig": "auth/tsconfig.lib.json", - "packageJson": "auth/package.json", - "main": "auth/src/index.ts", - "assets": ["auth/*.md"] - }, - "configurations": {} - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "auth/jest.config.ts", - "passWithNoTests": true - }, - "configurations": {} - } - } - } - }, - { - "name": "e2e", - "type": "lib", - "data": { - "tags": [], - "root": "e2e", - "files": [ - { - "file": "e2e/.eslintrc.json", - "hash": "c9038d6e5ca20e9fa5cd35c9e3a6c99a5a7feb8b" - }, - { - "file": "e2e/jest.config.ts", - "hash": "f9477b3d4a1ff3d9604277e734c2225999a83b0e" - }, - { - "file": "e2e/project.json", - "hash": "699de53c0ad89a54bc901260b28c34fc9e4f4132" - }, - { - "file": "e2e/src/server/server.spec.ts", - "hash": "61ea782c168679416bc726b0d8c91b34f6503127", - "deps": ["npm:axios"] - }, - { - "file": "e2e/src/support/global-setup.ts", - "hash": "c1f514446d8c15b5f2ef8eb1f6bf232a9b3b6cae" - }, - { - "file": "e2e/src/support/global-teardown.ts", - "hash": "32ea345c47f1533607149a609aac15010d8c68e9" - }, - { - "file": "e2e/src/support/test-setup.ts", - "hash": "07f2870393f1e3001ccdcdba4d7857aa5a36f03a", - "deps": ["npm:axios"] - }, - { - "file": "e2e/tsconfig.json", - "hash": "9f8b535226f17c8a0597e41249116f0de7b2cf08" - }, - { - "file": "e2e/tsconfig.spec.json", - "hash": "2ac21b50bb8d3c742fe5058d8ec0ae43e668d2dd" - } - ], - "targets": { - "e2e": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"], - "options": { - "jestConfig": "e2e/jest.config.ts", - "passWithNoTests": true - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "configurations": {} - } - } - } - }, - { - "name": "products-api", - "type": "app", - "data": { - "tags": [], - "root": ".", - "files": [ - { - "file": ".eslintrc.base.json", - "hash": "7c52faa3cc08c835904b5313d738d8d9781e6997" - }, - { - "file": ".eslintrc.json", - "hash": "53d540eebe0a66d946cc7e8e963fc94033742beb" - }, - { - "file": ".gitignore", - "hash": "51b9af5269c1df38f3252250d5b46665822374cc" - }, - { - "file": ".prettierignore", - "hash": "d0b804da2a462044bb1c63364440b2c2164e86ad" - }, - { - "file": ".prettierrc", - "hash": "544138be45652abc7bc3873341deacd3f4f90c61" - }, - { - "file": ".vscode/extensions.json", - "hash": "64553b175b1109d40227087360bba86cbaa738fb" - }, - { - "file": "jest.config.app.ts", - "hash": "2ff66d3d84af8b60b6b296eee248e086f99bd542" - }, - { - "file": "jest.config.ts", - "hash": "2a738f7746dcbefabfa363e4e0a9ed10024ca942", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "jest.preset.js", - "hash": "e6c8ebea00cfb845c55c897266534e9386904de0", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "nx.json", - "hash": "fe0b6e421b0c7e03b5c3cc571ea256069ad054b1" - }, - { - "file": "package-lock.json", - "hash": "24bbcf950e8435a6f83295321c5d8c3c67df9582" - }, - { - "file": "package.json", - "hash": "4b8184bd2510cf4ed177b63d225f6ada51a3316e", - "deps": [ - "npm:axios", - "npm:tslib", - "npm:@nrwl/esbuild", - "npm:@nrwl/eslint-plugin-nx", - "npm:@nrwl/jest", - "npm:@nrwl/js", - "npm:@nrwl/linter", - "npm:@nrwl/node", - "npm:nx-cloud", - "npm:@nrwl/workspace", - "npm:@types/express", - "npm:@types/jest", - "npm:@types/node", - "npm:@typescript-eslint/eslint-plugin", - "npm:@typescript-eslint/parser", - "npm:esbuild", - "npm:eslint", - "npm:eslint-config-prettier", - "npm:express", - "npm:jest", - "npm:jest-environment-jsdom", - "npm:nx", - "npm:prettier", - "npm:ts-jest", - "npm:ts-node", - "npm:typescript" - ] - }, - { - "file": "project.json", - "hash": "e848e5ca90d075791876a4f54f57de789e212a4b" - }, - { - "file": "README.md", - "hash": "11b2d2170208c891b85335735fd609a57fcf9af8" - }, - { - "file": "src/app/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/assets/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/main.ts", - "hash": "7be55ba18caf4cea1a68a8f0d8a396f1674d8244", - "deps": ["npm:express", "auth"] - }, - { - "file": "tsconfig.app.json", - "hash": "c300cd67e29c6755eabb25a7529dd2e9de82177d" - }, - { - "file": "tsconfig.json", - "hash": "e8e698fbde0725b5d2c6769947a458797d4495b3" - }, - { - "file": "tsconfig.spec.json", - "hash": "2fa7e96d8d7f2598d83b187fbe3eaebd654f667b" - } - ], - "targets": { - "start": { - "executor": "nx:run-script", - "options": { "script": "start" } - }, - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"], - "executor": "@nrwl/esbuild:esbuild", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist", - "format": ["cjs"], - "main": "src/main.ts", - "tsConfig": "tsconfig.app.json", - "assets": ["src/assets"] - }, - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectName}"], - "options": { - "jestConfig": "jest.config.app.ts", - "passWithNoTests": true - }, - "configurations": {} - }, - "serve": { - "executor": "@nrwl/js:node", - "options": { "buildTarget": "products-api:build" }, - "configurations": { - "production": { "buildTarget": "products-api:build:production" } - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { "lintFilePatterns": ["./src"] }, - "configurations": {} - } - } - } - } - ], - "dependencies": { - "auth": [], - "e2e": [{ "source": "e2e", "target": "products-api", "type": "implicit" }], - "products-api": [ - { "source": "products-api", "target": "auth", "type": "static" } - ] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": ["products-api", "e2e"], - "focus": null, - "groupByFolder": false, - "exclude": "" -} diff --git a/docs/shared/node-server-tutorial/final-project-graph.json b/docs/shared/node-server-tutorial/final-project-graph.json deleted file mode 100644 index 97969525b72d6..0000000000000 --- a/docs/shared/node-server-tutorial/final-project-graph.json +++ /dev/null @@ -1,325 +0,0 @@ -{ - "hash": "1828ed9ae8ba437cd57a41182e400677f0ff28bda80f3b9f1541c0fd7cd81ddf", - "projects": [ - { - "name": "auth", - "type": "lib", - "data": { - "tags": [], - "root": "auth", - "files": [ - { - "file": "auth/.babelrc", - "hash": "cf7ddd99c615a064ac18eb3109eee4f394ab1faf" - }, - { - "file": "auth/.eslintrc.json", - "hash": "2ecc0fb3287e0c1e27691b519c3a058a3248ab44" - }, - { - "file": "auth/jest.config.ts", - "hash": "9a572192bd6837978590302b51b89644e075ed71" - }, - { - "file": "auth/project.json", - "hash": "947e2a7cfb1d11fc0edb398bb9cbabf05f3eed21" - }, - { - "file": "auth/README.md", - "hash": "e895849f0d4f455473302f8dd795da5f2ff2dfab" - }, - { - "file": "auth/src/index.ts", - "hash": "2953bfc1d2b036689276d7f95bd6653b2a487993" - }, - { - "file": "auth/src/lib/auth.spec.ts", - "hash": "6b29b9cb382148b049b80a7a1ba6ec98193f90a6" - }, - { - "file": "auth/src/lib/auth.ts", - "hash": "87694589f307699e63ba8041cc774165851f359e" - }, - { - "file": "auth/tsconfig.json", - "hash": "f1a0ff5ec6a6f796fa26b4a8c82e74632b92a031" - }, - { - "file": "auth/tsconfig.lib.json", - "hash": "53c4ac8d833637e0dca7b03920b04cae26d9c5bb" - }, - { - "file": "auth/tsconfig.spec.json", - "hash": "fdb45891ed0c135fa82a503b4f115e31fe36bf91" - } - ], - "targets": { - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "auth/jest.config.ts", - "passWithNoTests": true - }, - "configurations": {} - } - } - } - }, - { - "name": "e2e", - "type": "lib", - "data": { - "tags": [], - "root": "e2e", - "files": [ - { - "file": "e2e/.eslintrc.json", - "hash": "c9038d6e5ca20e9fa5cd35c9e3a6c99a5a7feb8b" - }, - { - "file": "e2e/jest.config.ts", - "hash": "f9477b3d4a1ff3d9604277e734c2225999a83b0e" - }, - { - "file": "e2e/project.json", - "hash": "67123c12436c550477c2788ef4eb5870a3adb3f0" - }, - { - "file": "e2e/src/server/server.spec.ts", - "hash": "61ea782c168679416bc726b0d8c91b34f6503127", - "deps": ["npm:axios"] - }, - { - "file": "e2e/src/support/global-setup.ts", - "hash": "c1f514446d8c15b5f2ef8eb1f6bf232a9b3b6cae" - }, - { - "file": "e2e/src/support/global-teardown.ts", - "hash": "32ea345c47f1533607149a609aac15010d8c68e9" - }, - { - "file": "e2e/src/support/test-setup.ts", - "hash": "07f2870393f1e3001ccdcdba4d7857aa5a36f03a", - "deps": ["npm:axios"] - }, - { - "file": "e2e/tsconfig.json", - "hash": "9f8b535226f17c8a0597e41249116f0de7b2cf08" - }, - { - "file": "e2e/tsconfig.spec.json", - "hash": "2ac21b50bb8d3c742fe5058d8ec0ae43e668d2dd" - } - ], - "targets": { - "e2e": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"], - "options": { - "jestConfig": "e2e/jest.config.ts", - "passWithNoTests": true - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "configurations": {} - } - } - } - }, - { - "name": "products-api", - "type": "app", - "data": { - "tags": [], - "root": ".", - "files": [ - { - "file": ".eslintrc.base.json", - "hash": "7c52faa3cc08c835904b5313d738d8d9781e6997" - }, - { - "file": ".eslintrc.json", - "hash": "53d540eebe0a66d946cc7e8e963fc94033742beb" - }, - { - "file": ".gitignore", - "hash": "51b9af5269c1df38f3252250d5b46665822374cc" - }, - { - "file": ".prettierignore", - "hash": "d0b804da2a462044bb1c63364440b2c2164e86ad" - }, - { - "file": ".prettierrc", - "hash": "544138be45652abc7bc3873341deacd3f4f90c61" - }, - { - "file": ".vscode/extensions.json", - "hash": "64553b175b1109d40227087360bba86cbaa738fb" - }, - { - "file": "jest.config.app.ts", - "hash": "33759b382d178de6c65ff4f26b34c192de5573cd" - }, - { - "file": "jest.config.ts", - "hash": "2a738f7746dcbefabfa363e4e0a9ed10024ca942", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "jest.preset.js", - "hash": "e6c8ebea00cfb845c55c897266534e9386904de0", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "nx.json", - "hash": "af988c9133568995e00c8392e641ae3d5f5c7f9f" - }, - { - "file": "package-lock.json", - "hash": "c673e6ed166924761428c2fa0c6406327870e420" - }, - { - "file": "package.json", - "hash": "de7138436eaf8100c6de4cddddd50ccb881ad5df", - "deps": [ - "npm:axios", - "npm:tslib", - "npm:@nrwl/esbuild", - "npm:@nrwl/eslint-plugin-nx", - "npm:@nrwl/jest", - "npm:@nrwl/linter", - "npm:@nrwl/node", - "npm:nx-cloud", - "npm:@nrwl/workspace", - "npm:@types/express", - "npm:@types/jest", - "npm:@types/node", - "npm:@typescript-eslint/eslint-plugin", - "npm:@typescript-eslint/parser", - "npm:esbuild", - "npm:eslint", - "npm:eslint-config-prettier", - "npm:express", - "npm:jest", - "npm:jest-environment-jsdom", - "npm:nx", - "npm:prettier", - "npm:ts-jest", - "npm:ts-node", - "npm:typescript" - ] - }, - { - "file": "project.json", - "hash": "d808a6dfae9220eaecb9804da9f9186e580dacaa" - }, - { - "file": "README.md", - "hash": "be383295d307d4db7bb3b773bf72acb4243c226b" - }, - { - "file": "src/app/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/assets/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/main.ts", - "hash": "6cab50d279bc6ce17e8a35112ec854d68e0579c1", - "deps": ["npm:express", "auth"] - }, - { - "file": "tsconfig.app.json", - "hash": "c300cd67e29c6755eabb25a7529dd2e9de82177d" - }, - { - "file": "tsconfig.json", - "hash": "10390542b24ec4b22c9358c82d0a858f10e9a7ec" - }, - { - "file": "tsconfig.spec.json", - "hash": "2fa7e96d8d7f2598d83b187fbe3eaebd654f667b" - } - ], - "targets": { - "start": { - "executor": "nx:run-script", - "options": { "script": "start" } - }, - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"], - "executor": "@nrwl/esbuild:esbuild", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist", - "format": ["cjs"], - "main": "src/main.ts", - "tsConfig": "tsconfig.app.json", - "assets": ["src/assets"] - }, - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectName}"], - "options": { - "jestConfig": "jest.config.app.ts", - "passWithNoTests": true - }, - "configurations": {} - }, - "serve": { - "executor": "@nrwl/js:node", - "options": { "buildTarget": "products-api:build" }, - "configurations": { - "production": { "buildTarget": "products-api:build:production" } - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { "lintFilePatterns": ["./**/*.ts"] }, - "configurations": {} - } - } - } - } - ], - "dependencies": { - "auth": [], - "e2e": [{ "source": "e2e", "target": "products-api", "type": "implicit" }], - "products-api": [ - { "source": "products-api", "target": "auth", "type": "static" } - ] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false, - "exclude": [] -} diff --git a/docs/shared/node-server-tutorial/generator-syntax.svg b/docs/shared/node-server-tutorial/generator-syntax.svg deleted file mode 100644 index f0dadf08e3541..0000000000000 --- a/docs/shared/node-server-tutorial/generator-syntax.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/docs/shared/node-server-tutorial/initial-project-graph.json b/docs/shared/node-server-tutorial/initial-project-graph.json deleted file mode 100644 index 0282c1fd241e3..0000000000000 --- a/docs/shared/node-server-tutorial/initial-project-graph.json +++ /dev/null @@ -1,324 +0,0 @@ -{ - "hash": "2243ecc815a9b5c726fa59f3c2eb8d15a36c9f467eed41cd231dd9980a737a4d", - "projects": [ - { - "name": "auth", - "type": "lib", - "data": { - "tags": [], - "root": "auth", - "files": [ - { - "file": "auth/.babelrc", - "hash": "cf7ddd99c615a064ac18eb3109eee4f394ab1faf" - }, - { - "file": "auth/.eslintrc.json", - "hash": "2ecc0fb3287e0c1e27691b519c3a058a3248ab44" - }, - { - "file": "auth/jest.config.ts", - "hash": "9a572192bd6837978590302b51b89644e075ed71" - }, - { - "file": "auth/project.json", - "hash": "947e2a7cfb1d11fc0edb398bb9cbabf05f3eed21" - }, - { - "file": "auth/README.md", - "hash": "e895849f0d4f455473302f8dd795da5f2ff2dfab" - }, - { - "file": "auth/src/index.ts", - "hash": "2953bfc1d2b036689276d7f95bd6653b2a487993" - }, - { - "file": "auth/src/lib/auth.spec.ts", - "hash": "6b29b9cb382148b049b80a7a1ba6ec98193f90a6" - }, - { - "file": "auth/src/lib/auth.ts", - "hash": "dcd6088b201a8159a82243b2d04034a7023a0087" - }, - { - "file": "auth/tsconfig.json", - "hash": "f1a0ff5ec6a6f796fa26b4a8c82e74632b92a031" - }, - { - "file": "auth/tsconfig.lib.json", - "hash": "53c4ac8d833637e0dca7b03920b04cae26d9c5bb" - }, - { - "file": "auth/tsconfig.spec.json", - "hash": "fdb45891ed0c135fa82a503b4f115e31fe36bf91" - } - ], - "targets": { - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], - "options": { - "jestConfig": "auth/jest.config.ts", - "passWithNoTests": true - }, - "configurations": {} - } - } - } - }, - { - "name": "e2e", - "type": "lib", - "data": { - "tags": [], - "root": "e2e", - "files": [ - { - "file": "e2e/.eslintrc.json", - "hash": "c9038d6e5ca20e9fa5cd35c9e3a6c99a5a7feb8b" - }, - { - "file": "e2e/jest.config.ts", - "hash": "f9477b3d4a1ff3d9604277e734c2225999a83b0e" - }, - { - "file": "e2e/project.json", - "hash": "67123c12436c550477c2788ef4eb5870a3adb3f0" - }, - { - "file": "e2e/src/server/server.spec.ts", - "hash": "51717c797954a51eb0495dd069d018268f1921de", - "deps": ["npm:axios"] - }, - { - "file": "e2e/src/support/global-setup.ts", - "hash": "c1f514446d8c15b5f2ef8eb1f6bf232a9b3b6cae" - }, - { - "file": "e2e/src/support/global-teardown.ts", - "hash": "32ea345c47f1533607149a609aac15010d8c68e9" - }, - { - "file": "e2e/src/support/test-setup.ts", - "hash": "07f2870393f1e3001ccdcdba4d7857aa5a36f03a", - "deps": ["npm:axios"] - }, - { - "file": "e2e/tsconfig.json", - "hash": "9f8b535226f17c8a0597e41249116f0de7b2cf08" - }, - { - "file": "e2e/tsconfig.spec.json", - "hash": "2ac21b50bb8d3c742fe5058d8ec0ae43e668d2dd" - } - ], - "targets": { - "e2e": { - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{e2eProjectRoot}"], - "options": { - "jestConfig": "e2e/jest.config.ts", - "passWithNoTests": true - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "configurations": {} - } - } - } - }, - { - "name": "products-api", - "type": "app", - "data": { - "tags": [], - "root": ".", - "files": [ - { - "file": ".eslintrc.base.json", - "hash": "7c52faa3cc08c835904b5313d738d8d9781e6997" - }, - { - "file": ".eslintrc.json", - "hash": "53d540eebe0a66d946cc7e8e963fc94033742beb" - }, - { - "file": ".gitignore", - "hash": "51b9af5269c1df38f3252250d5b46665822374cc" - }, - { - "file": ".prettierignore", - "hash": "d0b804da2a462044bb1c63364440b2c2164e86ad" - }, - { - "file": ".prettierrc", - "hash": "544138be45652abc7bc3873341deacd3f4f90c61" - }, - { - "file": ".vscode/extensions.json", - "hash": "64553b175b1109d40227087360bba86cbaa738fb" - }, - { - "file": "jest.config.app.ts", - "hash": "33759b382d178de6c65ff4f26b34c192de5573cd" - }, - { - "file": "jest.config.ts", - "hash": "2a738f7746dcbefabfa363e4e0a9ed10024ca942", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "jest.preset.js", - "hash": "e6c8ebea00cfb845c55c897266534e9386904de0", - "deps": ["npm:@nrwl/jest"] - }, - { - "file": "nx.json", - "hash": "af988c9133568995e00c8392e641ae3d5f5c7f9f" - }, - { - "file": "package-lock.json", - "hash": "c673e6ed166924761428c2fa0c6406327870e420" - }, - { - "file": "package.json", - "hash": "de7138436eaf8100c6de4cddddd50ccb881ad5df", - "deps": [ - "npm:axios", - "npm:tslib", - "npm:@nrwl/esbuild", - "npm:@nrwl/eslint-plugin-nx", - "npm:@nrwl/jest", - "npm:@nrwl/linter", - "npm:@nrwl/node", - "npm:nx-cloud", - "npm:@nrwl/workspace", - "npm:@types/express", - "npm:@types/jest", - "npm:@types/node", - "npm:@typescript-eslint/eslint-plugin", - "npm:@typescript-eslint/parser", - "npm:esbuild", - "npm:eslint", - "npm:eslint-config-prettier", - "npm:express", - "npm:jest", - "npm:jest-environment-jsdom", - "npm:nx", - "npm:prettier", - "npm:ts-jest", - "npm:ts-node", - "npm:typescript" - ] - }, - { - "file": "project.json", - "hash": "d808a6dfae9220eaecb9804da9f9186e580dacaa" - }, - { - "file": "README.md", - "hash": "be383295d307d4db7bb3b773bf72acb4243c226b" - }, - { - "file": "src/app/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/assets/.gitkeep", - "hash": "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" - }, - { - "file": "src/main.ts", - "hash": "664465562bdb3a29608d9eac73f05e633615fa02", - "deps": ["npm:express"] - }, - { - "file": "tsconfig.app.json", - "hash": "c300cd67e29c6755eabb25a7529dd2e9de82177d" - }, - { - "file": "tsconfig.json", - "hash": "10390542b24ec4b22c9358c82d0a858f10e9a7ec" - }, - { - "file": "tsconfig.spec.json", - "hash": "2fa7e96d8d7f2598d83b187fbe3eaebd654f667b" - } - ], - "targets": { - "start": { - "executor": "nx:run-script", - "options": { "script": "start" } - }, - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "^production"], - "executor": "@nrwl/esbuild:esbuild", - "outputs": ["{options.outputPath}"], - "options": { - "outputPath": "dist", - "format": ["cjs"], - "main": "src/main.ts", - "tsConfig": "tsconfig.app.json", - "assets": ["src/assets"] - }, - "configurations": {} - }, - "test": { - "inputs": [ - "default", - "^production", - "{workspaceRoot}/jest.preset.js" - ], - "executor": "@nrwl/jest:jest", - "outputs": ["{workspaceRoot}/coverage/{projectName}"], - "options": { - "jestConfig": "jest.config.app.ts", - "passWithNoTests": true - }, - "configurations": {} - }, - "serve": { - "executor": "@nrwl/js:node", - "options": { "buildTarget": "products-api:build" }, - "configurations": { - "production": { "buildTarget": "products-api:build:production" } - } - }, - "lint": { - "inputs": ["default", "{workspaceRoot}/.eslintrc.json"], - "executor": "@nrwl/linter:eslint", - "outputs": ["{options.outputFile}"], - "options": { "lintFilePatterns": ["./src"] }, - "configurations": {} - } - } - } - } - ], - "dependencies": { - "auth": [], - "e2e": [{ "source": "e2e", "target": "products-api", "type": "implicit" }], - "products-api": [] - }, - "workspaceLayout": { "appsDir": "apps", "libsDir": "libs" }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false, - "exclude": [] -} diff --git a/docs/shared/npm-tutorial/integrated.md b/docs/shared/npm-tutorial/integrated.md index 8f8ad5b55e1ff..f07e704fc63cc 100644 --- a/docs/shared/npm-tutorial/integrated.md +++ b/docs/shared/npm-tutorial/integrated.md @@ -229,7 +229,7 @@ npx nx affected -t build {% cards %} -{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%} +{% card title="Core Features" description="Read about the core features of Nx." url="/features" /%} {% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%} @@ -239,6 +239,4 @@ npx nx affected -t build {% card title="React Tutorial" description="A step-by-step tutorial showing how to build an integrated monorepo with React applications sharing code." url="/getting-started/tutorials/react-monorepo-tutorial" /%} -{% card title="Node.js Tutorial" description="A step-by-step tutorial showing how to build an integrated monorepo with Node.js applications sharing code." url="/getting-started/tutorials/node-server-tutorial" /%} - {% /cards %} diff --git a/docs/shared/npm-tutorial/package-based.md b/docs/shared/npm-tutorial/package-based.md index b0b15f8926215..1fa758da7bcad 100644 --- a/docs/shared/npm-tutorial/package-based.md +++ b/docs/shared/npm-tutorial/package-based.md @@ -282,7 +282,7 @@ Notice that the `base` and `head` options were populated with their default valu {% cards %} -{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%} +{% card title="Core Features" description="Read about the core features of Nx." url="/features" /%} {% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%} diff --git a/docs/shared/packages/angular/angular-plugin.md b/docs/shared/packages/angular/angular-plugin.md index f3a1a7f2b44b6..1c13b60467247 100644 --- a/docs/shared/packages/angular/angular-plugin.md +++ b/docs/shared/packages/angular/angular-plugin.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Angular Plugin +description: The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. +--- + The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications and libraries within an Nx workspace. It provides: @@ -15,35 +20,32 @@ You can easily and mostly **automatically migrate from an Angular CLI** project more [here](/recipes/angular/migration/angular). {% /callout %} -## Setting up the Angular plugin +## Setting Up @nx/angular + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/angular` version that matches the version of `nx` in your repository. If the version -numbers get out of sync, you can encounter some difficult to debug errors. You -can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +Make sure to install the `@nx/angular` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -Adding the Angular plugin to an existing Nx workspace can be done with the following: +In any Nx workspace, you can install `@nx/angular` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/angular +nx add @nx/angular ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/angular -``` +This will install the correct version of `@nx/angular`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/angular` package with your package manager. ```shell -pnpm add -D @nx/angular +npm add -D @nx/angular ``` {% /tab %} diff --git a/docs/shared/packages/cypress/cypress-plugin.md b/docs/shared/packages/cypress/cypress-plugin.md index d785f02ad4dd7..0f0022e7e9cc8 100644 --- a/docs/shared/packages/cypress/cypress-plugin.md +++ b/docs/shared/packages/cypress/cypress-plugin.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Cypress Plugin +description: The Nx Plugin for Cypress contains executors and generators that support e2e testing with Cypress. This page also explains how to configure Cypress on your Nx workspace. +--- + Cypress is a test runner built for the modern web. It has a lot of great features: - Time travel @@ -7,33 +12,76 @@ Cypress is a test runner built for the modern web. It has a lot of great feature - Network traffic control - Screenshots and videos -## Setting Up Cypress +## Setting Up @nx/cypress > Info about [Cypress Component Testing can be found here](/recipes/cypress/cypress-component-testing) > > Info about [using Cypress and Storybook can be found here](/recipes/storybook/overview-react#cypress-tests-for-storiesbook) -If the `@nx/cypress` package is not installed, install the version that matches your `nx` package version. +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/cypress` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/cypress` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/cypress +nx add @nx/cypress ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/cypress`. -```shell -yarn add -D @nx/cypress +### How @nx/cypress Infers Tasks + +The `@nx/cypress` plugin will create a task for any project that has a Cypress configuration file present. Any of the following files will be recognized as a Cypress configuration file: + +- `cypress.config.js` +- `cypress.config.ts` +- `cypress.config.mjs` +- `cypress.config.mts` +- `cypress.config.cjs` +- `cypress.config.cts` + +### 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 --web` in the command line. + +### @nx/cypress Configuration + +The `@nx/cypress/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/cypress/plugin", + "options": { + "ciTargetName": "e2e-ci", + "targetName": "e2e", + "componentTestingTargetName": "component-test" + } + } + ] +} ``` +- The `targetName`, `ciTargetName` and `componentTestingTargetName` options control the namea of the inferred Cypress tasks. The default names are `e2e`, `e2e-ci` and `component-test`. + +### Splitting E2E tasks by file + +The `@nx/cypress/plugin` will automatically split your e2e tasks by file. You can read more about this feature [here](/ci/features/split-e2e-tasks). + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/cypress` package with your package manager. ```shell -pnpm add -D @nx/cypress +npm add -D @nx/cypress ``` {% /tab %} @@ -67,7 +115,7 @@ Replace `your-app-name` with the app's name as defined in your `tsconfig.base.js Run `nx e2e frontend-e2e` to execute e2e tests with Cypress. -You can run your e2e test against a production build by using the `production` [configuration](https://nx.dev/plugin-features/use-task-executors#use-executor-configurations) +You can run your e2e test against a production build by using the `production` [configuration](https://nx.dev/concepts/executors-and-configurations#use-task-configurations) ```shell nx e2e frontend-e2e --configuration=production diff --git a/docs/shared/packages/cypress/cypress-v11-migration.md b/docs/shared/packages/cypress/cypress-v11-migration.md index a9f5a7f042ffc..aaed534729934 100644 --- a/docs/shared/packages/cypress/cypress-v11-migration.md +++ b/docs/shared/packages/cypress/cypress-v11-migration.md @@ -11,7 +11,7 @@ If your nx version is below v15.3.0, this migration is called `migrate-to-cypres From v15.3.0+ this generator is called `migrate-to-cypress-11`. -As of nx v15.1.0, if your project was already using Cypress v10, then your project will be migrated to Cypress v11 via the [standard nx migration process](/core-features/automate-updating-dependencies) +As of nx v15.1.0, if your project was already using Cypress v10, then your project will be migrated to Cypress v11 via the [standard nx migration process](/features/automate-updating-dependencies) {% /callout %} ```shell diff --git a/docs/shared/packages/detox/detox-plugin.md b/docs/shared/packages/detox/detox-plugin.md index 5f894f477e9c6..af5cd72b508cf 100644 --- a/docs/shared/packages/detox/detox-plugin.md +++ b/docs/shared/packages/detox/detox-plugin.md @@ -8,7 +8,9 @@ Detox is gray box end-to-end testing and automation library for mobile apps. It ## Setting Up Detox -### Install applesimutils (Mac only) +### Setup Environment + +#### Install applesimutils (Mac only) [applesimutils](https://github.com/wix/AppleSimulatorUtils) is a collection of utils for Apple simulators. @@ -17,59 +19,80 @@ brew tap wix/brew brew install applesimutils ``` -### Install Jest Globally +#### Install Jest Globally ```sh npm install -g jest ``` -### Generating Applications +### Installation -By default, when creating a mobile application, Nx will use Detox to create the e2e tests project. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/detox` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/detox` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} ```shell -nx g @nx/react-native:app frontend +nx add @nx/detox ``` -### Creating a Detox E2E project for an existing project +This will install the correct version of `@nx/detox`. -You can create a new Detox E2E project for an existing mobile project. +### How @nx/detox Infers Tasks -If the `@nx/detox` package is not installed, install the version that matches your `@nx/workspace` version. +The `@nx/detox` plugin will create a task for any project that has an ESLint configuration file present. Any of the following files will be recognized as an ESLint configuration file: -{% tabs %} -{% tab label="npm" %} +- `.detoxrc.js` +- `.detoxrc.json` +- `detox.config.js` +- `detox.config.json` -```shell -npm add -D @nx/detox -``` +### View Inferred Tasks -{% /tab %} -{% tab label="yarn" %} +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 --web` in the command line. -```shell -yarn add -D @nx/detox -``` +### @nx/detox Configuration -{% /tab %} -{% tab label="pnpm" %} +The `@nx/detox/plugin` is configured in the `plugins` array in `nx.json`. -```shell -pnpm add -D @nx/detox +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/detox/plugin", + "options": { + "buildTargetName": "build", + "startTargetName": "start", + "testTargetName": "test" + } + } + ] +} ``` +Once a Detox configuration file has been identified, the targets are created with the name you specify under `buildTargetName`, `startTargetName` or `testTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `build` and `test`. + {% /tab %} -{% /tabs %} +{% tab label="Nx < 18" %} -Next, generate an E2E project based on an existing project. +Install the `@nx/detox` package with your package manager. -```sh -nx g @nx/detox:app your-app-name-e2e --project=your-app-name +```shell +npm add -D @nx/detox ``` -Replace `your-app-name` with the app's name as defined in your `tsconfig.base.json` file or the `name` property of your `package.json`. +### Generating Applications + +By default, when creating a mobile application, Nx will use Detox to create the e2e tests project. -In addition, you need to follow [instructions at Detox](https://github.com/wix/Detox/blob/master/docs/Introduction.Android.md) to do manual setup for Android files. +```shell +nx g @nx/react-native:app frontend --e2eTestRunner=deotx +nx g @nx/expo:app frontend --e2eTestRunner=detox +``` ## Using Detox diff --git a/docs/shared/packages/esbuild/esbuild-plugin.md b/docs/shared/packages/esbuild/esbuild-plugin.md index 577d15f763f8b..e472942780ea2 100644 --- a/docs/shared/packages/esbuild/esbuild-plugin.md +++ b/docs/shared/packages/esbuild/esbuild-plugin.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx esbuild Plugin +description: The Nx Plugin for esbuild contains executors and generators that support building applications using esbuild. This page also explains how to configure esbuild on your Nx workspace. +--- + The Nx Plugin for [esbuild](https://esbuild.github.io/api/), an extremely fast JavaScript bundler. Why should you use this plugin? @@ -7,40 +12,39 @@ Why should you use this plugin? - Intelligent `package.json` output. - Additional [assets](/nx-api/esbuild/executors/esbuild#assets) for the output. -## Setting up esbuild +## Setting Up @nx/esbuild -To create a new workspace, run `npx create-nx-workspace@latest --preset=npm`. +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/esbuild` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the esbuild plugin to an existing workspace, run the following: +In any Nx workspace, you can install `@nx/esbuild` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/esbuild +nx add @nx/esbuild ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/esbuild -``` +This will install the correct version of `@nx/esbuild`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/esbuild` package with your package manager. ```shell -pnpm add -D @nx/esbuild +npm add -D @nx/esbuild ``` {% /tab %} {% /tabs %} +## Using the @nx/esbuild Plugin + ### Creating a new JS library {% callout type="note" title="Directory Flag Behavior Changes" %} diff --git a/docs/shared/packages/eslint/enforce-module-boundaries.md b/docs/shared/packages/eslint/enforce-module-boundaries.md index 0bffdba043751..0c2d127ad7383 100644 --- a/docs/shared/packages/eslint/enforce-module-boundaries.md +++ b/docs/shared/packages/eslint/enforce-module-boundaries.md @@ -53,7 +53,7 @@ The `depConstraints` is an array of objects representing the constraints defined Read more about the proper usage of this rule: -- [Enforce Module Boundaries](/core-features/enforce-module-boundaries) +- [Enforce Module Boundaries](/features/enforce-module-boundaries) - [Ban Dependencies with Certain Tags](/recipes/enforce-module-boundaries/ban-dependencies-with-tags) - [Tag in Multiple Dimensions](/recipes/enforce-module-boundaries/tag-multiple-dimensions) - [Ban External Imports](/recipes/enforce-module-boundaries/ban-external-imports) diff --git a/docs/shared/packages/eslint/eslint-plugin.md b/docs/shared/packages/eslint/eslint-plugin.md index b87b4e4285e21..9036a11648559 100644 --- a/docs/shared/packages/eslint/eslint-plugin.md +++ b/docs/shared/packages/eslint/eslint-plugin.md @@ -13,30 +13,10 @@ Make sure to install the `@nx/eslint-plugin` version that matches the version of In any Nx workspace, you can install `@nx/eslint-plugin` by running the following commands if the package is not already installed: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/eslint-plugin -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/eslint-plugin +nx add @nx/eslint-plugin ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/eslint-plugin -``` - -{% /tab %} -{% /tabs %} - ## Included plugins The plugin contains the following rule configurations divided into sub-plugins. diff --git a/docs/shared/packages/eslint/eslint.md b/docs/shared/packages/eslint/eslint.md index d5cf2a6f4360d..ca49e9ce2d73f 100644 --- a/docs/shared/packages/eslint/eslint.md +++ b/docs/shared/packages/eslint/eslint.md @@ -1,6 +1,6 @@ -The ESLint plugin contains executors, generator, plugin and utilities used for linting JavaScript/TypeScript projects within an Nx workspace. +The ESLint plugin integrates [ESLint](https://eslint.org/) with Nx. It allows you to run ESLint through Nx with caching enabled. It also includes code generators to help you set up ESLint in your workspace. -## Setting Up ESLint +## Setting Up @nx/eslint ### Installation @@ -11,24 +11,58 @@ Make sure to install the `@nx/eslint` version that matches the version of `nx` i In any Nx workspace, you can install `@nx/eslint` by running the following command: {% tabs %} -{%tab label="npm"%} +{% tab label="Nx 18+" %} ```shell -npm i -D @nx/eslint +nx add @nx/eslint ``` -{% /tab %} -{%tab label="yarn"%} +This will install the correct version of `@nx/eslint`. -```shell -yarn add -D @nx/eslint +### How @nx/eslint Infers Tasks + +The `@nx/eslint` plugin will create a task for any project that has an ESLint configuration file present. Any of the following files will be recognized as an ESLint configuration file: + +- `.eslintrc` +- `.eslintrc.js` +- `.eslintrc.cjs` +- `.eslintrc.yaml` +- `.eslintrc.yml` +- `.eslintrc.json` +- `eslint.config.js` + +Because ESLint applies configuration files to all subdirectories, the `@nx/eslint` plugin will also infer tasks for projects in subdirectories. So, if there is an ESLint configuration file in the root of the repository, every project will have an inferred ESLint task. + +### 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 --web` in the command line. + +### @nx/eslint Configuration + +The `@nx/eslint/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + } + ] +} ``` +- The `targetName` option controls the name of the inferred ESLint tasks. The default name is `lint`. + {% /tab %} -{%tab label="pnpm"%} +{% tab label="Nx < 18" %} + +Install the `@nx/eslint` package with your package manager. ```shell -pnpm add -D @nx/eslint +npm add -D @nx/eslint ``` {% /tab %} diff --git a/docs/shared/packages/expo/expo-plugin.md b/docs/shared/packages/expo/expo-plugin.md index 67551bd597a0e..9ee33616ac22d 100644 --- a/docs/shared/packages/expo/expo-plugin.md +++ b/docs/shared/packages/expo/expo-plugin.md @@ -4,44 +4,87 @@ Expo is a set of tools built on top of React Native. The Nx Plugin for Expo cont ## Setting Up Expo -To create a new workspace with expo, run the following command: +To create a new workspace with Expo, run the following command: ```shell - npx create-nx-workspace --preset=expo + npx create-nx-workspace@latest --preset=expo --appName=your-app-name ``` -### Adding Expo to an Existing Project - -Install the expo plugin +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/expo` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/expo` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/expo +nx add @nx/expo ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/expo`. -```shell -yarn add -D @nx/expo +### How @nx/expo Infers Tasks + +The `@nx/expo` plugin will create a task for any project that has an app configuration file present. Any of the following files will be recognized as an app configuration file: + +- `app.config.js` +- `app.json` + +In the app config file, it needs to have key `expo`: + +```json +{ + "expo": { + "name": "MyProject", + "slug": "my-project" + } +} ``` +### 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 --web` in the command line. + +### @nx/expo Configuration + +The `@nx/expo/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/expo/plugin", + "options": { + "startTargetName": "start", + "serveTargetName": "serve", + "runIosTargetName": "run-ios", + "runAndroidTargetName": "run-android", + "exportTargetName": "export", + "prebuildTargetName": "prebuild", + "installTargetName": "install", + "buildTargetName": "build", + "submitTargetName": "submit" + } + } + ] +} +``` + +Once a Expo configuration file has been identified, the targets are created with the name you specify under `startTargetName`, `serveTargetName`, `runIosTargetName`, `runAndroidTargetname`, `exportTargetName`, `prebuildTargetName`, `installTargetName`, `buildTargetName` or `submitTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `start`, `serve`, `run-ios`, `run-anroid`, `export`, `prebuild`, `install`, `build` and `submit`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/expo` package with your package manager. ```shell -pnpm add -D @nx/expo +npm add -D @nx/expo ``` -{% /tab %} -{% /tabs %} - ### Creating Applications Add a new application to your workspace with the following command: diff --git a/docs/shared/packages/express/express-plugin.md b/docs/shared/packages/express/express-plugin.md index 8709622944378..abda6b0ea476f 100644 --- a/docs/shared/packages/express/express-plugin.md +++ b/docs/shared/packages/express/express-plugin.md @@ -9,6 +9,37 @@ To create a new workspace with a pre-created Express app, run the following comm npx create-nx-workspace --preset=express ``` +## Setting Up @nx/express + +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/express` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/express` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/express +``` + +This will install the correct version of `@nx/express`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/express` package with your package manager. + +```shell +npm add -D @nx/express +``` + +{% /tab %} +{% /tabs %} + ## Recipes - [Add an Express Application to Your Workspace](/showcase/example-repos/add-express) diff --git a/docs/shared/packages/jest/jest-plugin.md b/docs/shared/packages/jest/jest-plugin.md index c8b02f9bfc9b2..c42b3d0fa6e40 100644 --- a/docs/shared/packages/jest/jest-plugin.md +++ b/docs/shared/packages/jest/jest-plugin.md @@ -1,52 +1,92 @@ +--- +title: Overview of the Nx Jest Plugin +description: The Nx Plugin for Jest contains executors and generators that support testing projects using Jest. This page also explains how to configure Jest on your Nx workspace. +--- + [Jest](https://jestjs.io/) is an open source test runner created by Facebook. It has a lot of great features: - Immersive watch mode for providing near instant feedback when developing tests. - Snapshot testing for validating features. - Great built-in reporter for printing out test results. -## Setting up Jest +## Setting Up @nx/jest -By default, Nx will use Jest when creating applications and libraries. +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/jest` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} ```shell -nx g @nx/web:app frontend +nx add @nx/jest ``` -### Adding Jest to an Existing Project +This will install the correct version of `@nx/jest`. -Add Jest to a project using the `configuration` generator from `@nx/jest`. +### How @nx/jest Infers Tasks -First, install `@nx/jest`, if not already installed using your preferred package manager. +The `@nx/jest` plugin will create a task for any project that has an Jest configuration file present. Any of the following files will be recognized as an Jest configuration file: -{% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/jest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). -{% /callout %} +- `jest.config.js` +- `jest.config.ts` +- `jest.config.mjs` +- `jest.config.mts` +- `jest.config.cjs` +- `jest.config.cts` -{% tabs %} -{% tab label="npm" %} +### View Inferred Tasks -```shell -npm add -D @nx/jest +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 --web` in the command line. + +### @nx/jest Configuration + +The `@nx/jest/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/jest/plugin", + "options": { + "targetName": "test" + } + } + ] +} ``` +- The `targetName` option controls the name of the inferred Jest tasks. The default name is `test`. + {% /tab %} -{% tab label="yarn" %} +{% tab label="Nx < 18" %} + +Install the `@nx/jest` package with your package manager. ```shell -yarn add -D @nx/jest +npm add -D @nx/jest ``` {% /tab %} -{% tab label="pnpm" %} +{% /tabs %} + +## Using Jest + +### Generate a new project set up with Jest + +By default, Nx will use Jest when creating applications and libraries. ```shell -pnpm add -D @nx/jest +nx g @nx/web:app frontend ``` -{% /tab %} -{% /tabs %} +### Add Jest to a project -Once installed, run the `configuration` generator +Run the `configuration` generator ```shell nx g @nx/jest:configuration --project= @@ -56,8 +96,6 @@ nx g @nx/jest:configuration --project= Replacing `` with the name of the project you're wanting to add Jest too. -## Using Jest - ### Testing Applications The recommended way to run/debug Jest tests via an editor diff --git a/docs/shared/packages/js/js-plugin.md b/docs/shared/packages/js/js-plugin.md index 2474d369dbb05..0548e3c69e00e 100644 --- a/docs/shared/packages/js/js-plugin.md +++ b/docs/shared/packages/js/js-plugin.md @@ -1,6 +1,11 @@ +--- +title: Overview of the Nx JS Plugin +description: The Nx JS plugin contains executors and generators that are useful for JavaScript/TypeScript projects in an Nx workspace. +--- + The JS plugin contains executors and generators that are useful for JavaScript/TypeScript projects in an Nx workspace. -## Setting Up JS +## Setting Up @nx/js ### Installation @@ -8,27 +13,24 @@ The JS plugin contains executors and generators that are useful for JavaScript/T Make sure to install the `@nx/js` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -In any Nx workspace, you can install `@nx/js` by running the following commands if `@nx/js` package is not installed: +In any Nx workspace, you can install `@nx/js` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/js +nx add @nx/js ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/js -``` +This will install the correct version of `@nx/js`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/js` package with your package manager. ```shell -pnpm add -D @nx/js +npm add -D @nx/js ``` {% /tab %} diff --git a/docs/shared/packages/nest/nest-plugin.md b/docs/shared/packages/nest/nest-plugin.md index b4b4fd2608fe2..df9b7fe9ec2f5 100644 --- a/docs/shared/packages/nest/nest-plugin.md +++ b/docs/shared/packages/nest/nest-plugin.md @@ -7,7 +7,9 @@ Nest.js is a framework designed for building scalable server-side applications. Many conventions and best practices used in Angular applications can be also be used in Nest. -## Setting Up Nest +## Setting Up @nx/nest + +### Generating a new workspace To create a new workspace with Nest, run the following command: @@ -21,31 +23,30 @@ Yarn users can use the following command instead: yarn create nx-workspace my-workspace --preset=nest ``` +### Installation + {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/nest` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the Nest plugin to an existing workspace, run one the following commands: +In any Nx workspace, you can install `@nx/nest` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/nest +nx add @nx/nest ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/nest -``` +This will install the correct version of `@nx/nest`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/nest` package with your package manager. ```shell -pnpm add -D @nx/nest +npm add -D @nx/nest ``` {% /tab %} diff --git a/docs/shared/packages/next/plugin-overview.md b/docs/shared/packages/next/plugin-overview.md index 0a0f056e6717f..012d307e277dd 100644 --- a/docs/shared/packages/next/plugin-overview.md +++ b/docs/shared/packages/next/plugin-overview.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Next.js Plugin +description: The Nx Next.js plugin contains executors and generators for managing Next.js applications and libraries within an Nx workspace. This page also explains how to configure Next.js on your Nx workspace. +--- + When using Next.js in Nx, you get the out-of-the-box support for TypeScript, Cypress, and Jest. No need to configure anything: watch mode, source maps, and typings just work. The Next.js plugin contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides: @@ -6,36 +11,80 @@ The Next.js plugin contains executors and generators for managing Next.js applic - Integration with building, serving, and exporting a Next.js application. - Integration with React libraries within the workspace. -## Setting up Next.js +## Setting up @nx/next + +To create a new Nx workspace with Next.js, run: + +```shell +npx create-nx-workspace@latest --preset=next +``` + +### Installation -To create a new Nx workspace with Next.js, run `npx create-nx-workspace@latest --preset=next`. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/next` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -To add Next.js to an existing Nx workspace, install the `@nx/next` package. Make sure to install the version that matches your `nx` version. +In any workspace, you can install `@nx/next` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/next +nx add @nx/next ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/next`. -```shell -yarn add -D @nx/next +### How @nx/next Infers Tasks + +The `@nx/next` plugin will create tasks for any project that has a Next.js configuration file preset. Any of the following files will be recognized as a Next.js configuration file: + +- `next.config.js` +- `next.config.cjs` +- `next.config.mjs` + +### 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 --web` in your command line. + +### @nx/next Configuration + +The `@nx/next/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/next/plugin", + "options": { + "buildTargetName": "build", + "devTargetName": "dev", + "startTargetName": "start" + } + } + ] +} ``` +- The `buildTargetName` option controls the name of Next.js' compilation task which compiles the application for production deployment. The default name is `build`. +- The `devTargetName` option controls the name of Next.js' development serve task which starts the application in development mode. The default name is `dev`. +- The `startTargetName` option controls the name of Next.js' production serve task which starts the application in production mode. The default name is `start`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/next` package with your package manager. ```shell -pnpm add -D @nx/next +npm add -D @nx/next ``` {% /tab %} {% /tabs %} +## Using @nx/next + ### Creating Applications You can add a new application with the following: @@ -79,7 +128,28 @@ Nx generates components with tests by default. For pages, you can pass the `--wi ### Serving Next.js Applications -You can run `nx serve my-new-app` to serve a Next.js application called `my-new-app` for development. This will start the dev server at http://localhost:4200. +{% tabs %} + +{% tab label="Nx 18+" %} + +You can serve a Next.js application `my-new-app` for development: + +```shell +nx dev my-new-app +``` + +To serve a Next.js application for production: + +```shell +nx start my-new-app +``` + +This will start the server at by default. + +{% /tab %} +{% tab label="Nx < 18" %} + +You can run `nx serve my-new-app` to serve a Next.js application called `my-new-app` for development. This will start the dev server at . To serve a Next.js application for production, add the `--prod` flag to the serve command: @@ -87,6 +157,9 @@ To serve a Next.js application for production, add the `--prod` flag to the serv nx serve my-new-app --prod ``` +{% /tab %} +{% /tabs %} + ### Using an Nx Library in your Application You can import a library called `my-new-lib` in your application as follows. @@ -165,10 +238,15 @@ The library in `dist` is publishable to npm or a private registry. ### Static HTML Export -Next.js applications can be statically exported with: +Next.js applications can be statically exported by changing th eoutput inside your Next.js configuration file. -```shell -nx export my-new-app +```js {% fileName="apps/my-next-app/next.config.js" %} +const nextConfig = { + output: 'export', + nx: { + svgr: false, + }, +}; ``` ### Deploying Next.js Applications diff --git a/docs/shared/packages/node/node-plugin.md b/docs/shared/packages/node/node-plugin.md index 21aa25e0e3e5b..ce2127391e9fd 100644 --- a/docs/shared/packages/node/node-plugin.md +++ b/docs/shared/packages/node/node-plugin.md @@ -1,37 +1,38 @@ The Node Plugin contains generators and executors to manage Node applications within an Nx workspace. It provides: -## Setting Up Node +## Setting Up @nx/node + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/node` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the Node plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/node` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/node +nx add @nx/node ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/node -``` +This will install the correct version of `@nx/node`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/node` package with your package manager. ```shell -pnpm add -D @nx/node +npm add -D @nx/node ``` {% /tab %} {% /tabs %} +## Using the @nx/node Plugin + ### Creating Applications You can add a new application with the following: diff --git a/docs/shared/packages/nuxt/nuxt-plugin.md b/docs/shared/packages/nuxt/nuxt-plugin.md index 9eb93e516a5d8..6440d1768d5d6 100644 --- a/docs/shared/packages/nuxt/nuxt-plugin.md +++ b/docs/shared/packages/nuxt/nuxt-plugin.md @@ -5,7 +5,7 @@ description: The Nx Plugin for Nuxt contains generators for managing Nuxt applic The Nx plugin for [Nuxt](https://nuxt.com/). -## Setting up a new Nx workspace with Nuxt +## Setting up a new Nx workspace with @nx/nuxt You can create a new workspace that uses Nuxt with one of the following commands: @@ -15,35 +15,57 @@ You can create a new workspace that uses Nuxt with one of the following commands npx create-nx-workspace@latest --preset=nuxt ``` -## Add Nuxt to an existing workspace +### Installation -There are a number of ways to use Nuxt in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/nuxt` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -### Install the `@nx/nuxt` plugin - -{% tabs %} -{% tab label="npm" %} +In any Nx workspace, you can install `@nx/nuxt` by running the following command: ```shell -npm add -D @nx/nuxt +nx add @nx/nuxt ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/nuxt`. -```shell -yarn add -D @nx/nuxt -``` +### How @nx/nuxt Infers Tasks -{% /tab %} -{% tab label="pnpm" %} +The `@nx/nuxt` plugin will create a task for any project that has an Nuxt configuration file present. Any of the following files will be recognized as an Nuxt configuration file: -```shell -pnpm add -D @nx/nuxt +- `nuxt.config.js` +- `nuxt.config.ts` +- `nuxt.config.mjs` +- `nuxt.config.mts` +- `nuxt.config.cjs` +- `nuxt.config.cts` + +### 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 --web` in the command line. + +### @nx/nuxt Configuration + +The `@nx/nuxt/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/nuxt/plugin", + "options": { + "buildTargetName": "build", + "testTargetName": "test", + "serveTargetName": "serve" + } + } + ] +} ``` -{% /tab %} -{% /tabs %} +- The `buildTargetName`, `testTargetName` and `serveTargetName` options control the names of the inferred Nuxt tasks. The default names are `build`, `test` and `serve`. + +## Using Nuxt ### Generate a new Nuxt app diff --git a/docs/shared/packages/playwright/playwright-plugin.md b/docs/shared/packages/playwright/playwright-plugin.md index c01e59e715428..730ed65055932 100644 --- a/docs/shared/packages/playwright/playwright-plugin.md +++ b/docs/shared/packages/playwright/playwright-plugin.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Playwright Plugin +description: The Nx Plugin for Playwright contains executors and generators that support e2e testing with Playwright. This page also explains how to configure Playwright on your Nx workspace. +--- + Playwright is a modern web test runner. With included features such as: - Cross browser support, including mobile browsers @@ -6,29 +11,71 @@ Playwright is a modern web test runner. With included features such as: - Test generation - Screenshots and videos -## Setting Up Playwright +## Setting Up @nx/playwright + +### Installation -If the `@nx/playwright` package is not installed, install the version that matches your `nx` package version. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/playwright` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/playwright` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/playwright +nx add @nx/playwright ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/playwright`. -```shell -yarn add -D @nx/playwright +### How @nx/playwright Infers Tasks + +The `@nx/playwright` plugin will create a task for any project that has a Playwright configuration file present. Any of the following files will be recognized as a Playwright configuration file: + +- `playwright.config.js` +- `playwright.config.ts` +- `playwright.config.mjs` +- `playwright.config.mts` +- `playwright.config.cjs` +- `playwright.config.cts` + +### 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 --web` in the command line. + +### @nx/playwright Configuration + +The `@nx/playwright/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/playwright/plugin", + "options": { + "ciTargetName": "e2e-ci", + "targetName": "e2e" + } + } + ] +} ``` +- The `targetName` and `ciTargetName` options control the namea of the inferred Playwright tasks. The default names are `e2e` and `e2e-ci`. + +### Splitting E2E tasks by file + +The `@nx/playwright/plugin` will automatically split your e2e tasks by file. You can read more about this feature [here](/ci/features/split-e2e-tasks). + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/playwright` package with your package manager. ```shell -pnpm add -D @nx/playwright +npm add -D @nx/playwright ``` {% /tab %} diff --git a/docs/shared/packages/plugin/plugin.md b/docs/shared/packages/plugin/plugin.md index 459807ba2e2ef..30179db3dae2c 100644 --- a/docs/shared/packages/plugin/plugin.md +++ b/docs/shared/packages/plugin/plugin.md @@ -1,4 +1,4 @@ -Nx plugins are npm packages that contain [generators](/core-features/plugin-features/use-code-generators) and [executors](/core-features/plugin-features/use-task-executors) to extend a Nx workspace. +Nx plugins are npm packages that contain [generators](/features/generate-code) and [executors](/concepts/executors-and-configurations) to extend a Nx workspace. This package contains tooling to help plugin authors create and maintain plugins. diff --git a/docs/shared/packages/react-native/react-native-plugin.md b/docs/shared/packages/react-native/react-native-plugin.md index 5a533982f453d..8fa0b538e95fd 100644 --- a/docs/shared/packages/react-native/react-native-plugin.md +++ b/docs/shared/packages/react-native/react-native-plugin.md @@ -10,12 +10,10 @@ The Nx Plugin for React Native contains generators for managing React Native app ### Create a New Workspace -The easiest way to create your workspace is via `npx`. +To create a new workspace with React Native, run the following command: ```shell -npx create-nx-workspace your-workspace-name \ ---preset=react-native \ ---appName=your-app-name +npx create-nx-workspace@latest --preset=react-native --appName=your-app-name ``` {% callout type="note" title="Don't know what you need?" %} @@ -26,38 +24,68 @@ You can also run the command without arguments to go through the interactive pro npx create-nx-workspace your-workspace-name ``` -### Adding React Native to an Existing Workspace - -For existing Nx workspaces, install the `@nx/react-native` package to add React Native capabilities to it. +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/react-native` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/react-native` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/react-native +nx add @nx/react-native ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/react-native`. -```shell -yarn add -D @nx/react-native +### How @nx/react-native Infers Tasks + +The `@nx/react-native` plugin will create a task for any project that has an app configuration file present. Any of the following files will be recognized as an app configuration file: + +- `app.config.js` +- `app.json` + +### 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 --web` in the command line. + +### @nx/react-native Configuration + +The `@nx/react-native/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/react-native/plugin", + "options": { + "startTargetName": "start", + "podInstallTargetName": "pod-install", + "bundleTargetName": "bundle", + "runIosTargetName": "run-ios", + "runAndroidTargetName": "run-android", + "buildIosTargetName": "build-ios", + "buildAndroidTargetName": "build-android" + } + } + ] +} ``` +Once a React Native configuration file has been identified, the targets are created with the name you specify under `startTargetName`, `podInstallTargetName`, `bundleTargetName`, `runIosTargetName`, `runAndroidTargetname`, `buildIosTargetName` or `buildAndroidTargetName` in the `nx.json` `plugins` array. The default names for the inferred targets are `start`, `pod-install`, `bundle`, `run-ios`, `run-anroid`, `build-ios` and `build-android`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/react-native` package with your package manager. ```shell -pnpm add -D @nx/react-native +npm add -D @nx/react-native ``` -{% /tab %} -{% /tabs %} - ### Generating Applications To create additional React Native apps run: @@ -86,7 +114,7 @@ Replace `your-lib-name` with the app's name as defined in your `tsconfig.base.js ### Upgrade React Native -The Nx CLI provides the [`migrate` command](/core-features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx. +The Nx CLI provides the [`migrate` command](/features/automate-updating-dependencies) to help you stay up to date with the latest version of Nx. #### Use upgrade-native Generator @@ -139,7 +167,7 @@ The build artifacts will be located under `/ios/build`. You can specify the build folder by setting the `buildFolder` option: ```shell -nx build ios --buildFolder="./build" +nx build-ios --buildFolder="./build" ``` ### Build Android diff --git a/docs/shared/packages/react/react-plugin.md b/docs/shared/packages/react/react-plugin.md index 7afbe410e1ffa..ca980ce308664 100644 --- a/docs/shared/packages/react/react-plugin.md +++ b/docs/shared/packages/react/react-plugin.md @@ -6,43 +6,46 @@ It provides: - Library build support for publishing packages to npm or other registries. - Utilities for automatic workspace refactoring. -## Setting Up React +## Setting Up @nx/react + +### Generating a new Workspace To create a new workspace with React, run `npx create-nx-workspace@latest --preset=react-standalone`. +{% callout type="note" title="React Tutorials" %} +For a full tutorial experience, follow the [React Standalone Tutorial](/getting-started/tutorials/react-standalone-tutorial) or the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) +{% /callout %} + +### Installation + {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/react` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the React plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/react` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/react +nx add @nx/react ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/react -``` +This will install the correct version of `@nx/react`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/react` package with your package manager. ```shell -pnpm add -D @nx/react +npm add -D @nx/react ``` {% /tab %} {% /tabs %} -{% callout type="note" title="React Tutorials" %} -For a full tutorial experience, follow the [React Standalone Tutorial](/getting-started/tutorials/react-standalone-tutorial) or the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) -{% /callout %} +## Using the @nx/react Plugin ### Creating Applications and Libraries diff --git a/docs/shared/packages/remix/remix-plugin.md b/docs/shared/packages/remix/remix-plugin.md index d234672adf0a9..b38a58fb42780 100644 --- a/docs/shared/packages/remix/remix-plugin.md +++ b/docs/shared/packages/remix/remix-plugin.md @@ -1,3 +1,8 @@ +--- +title: Overview of the Nx Remix Plugin +description: The Nx Plugin for Remix contains executors, generators, and utilities for managing Remix applications and libraries within an Nx workspace. +--- + The Nx Plugin for Remix contains executors, generators, and utilities for managing Remix applications and libraries within an Nx workspace. It provides: @@ -10,35 +15,66 @@ within an Nx workspace. It provides: - Meta - Utilities for automatic workspace refactoring. -## Setting up the Remix plugin +## Setting up @nx/remix + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/remix` version that matches the version of `nx` in your repository. If the version -numbers get out of sync, you can encounter some difficult to debug errors. You -can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +Make sure to install the `@nx/remix` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -Adding the Remix plugin to an existing Nx workspace can be done with the following: +In any Nx workspace, you can install `@nx/remix` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/remix +nx add @nx/remix ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/remix`. -```shell -yarn add -D @nx/remix +### How @nx/remix Infers Tasks + +The `@nx/remix` plugin will create a task for any project that has a Remix configuration file present. Any of the following files will be recognized as a Remix configuration file: + +- `remix.config.js` +- `remix.config.mjs` +- `remix.config.cjs` + +### 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 --web` in the command line. + +### @nx/remix Configuration + +The `@nx/remix/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/remix/plugin", + "options": { + "buildTargetName": "build", + "serveTargetName": "serve", + "startTargetName": "start", + "typecheckTargetName": "typecheck" + } + } + ] +} ``` +- The `buildTargetName`, `serveTargetName`, `startTargetName` and `typecheckTargetName` options control the names of the inferred Remix tasks. The default names are `build`, `serve`, `start` and `typecheck`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/remix` package with your package manager. ```shell -pnpm add -D @nx/remix +npm add -D @nx/remix ``` {% /tab %} diff --git a/docs/shared/packages/storybook/plugin-overview.md b/docs/shared/packages/storybook/plugin-overview.md index 47590c3960eb3..2e970f928cc72 100644 --- a/docs/shared/packages/storybook/plugin-overview.md +++ b/docs/shared/packages/storybook/plugin-overview.md @@ -9,31 +9,67 @@ This guide will briefly walk you through using Storybook within an Nx workspace. ## Setting Up Storybook -### Add the Storybook plugin +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/storybook` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} +In any Nx workspace, you can install `@nx/storybook` by running the following command: + {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/storybook +nx add @nx/storybook ``` -{% /tab %} -{% tab label="yarn" %} +This will install the correct version of `@nx/storybook`. -```shell -yarn add -D @nx/storybook +### How @nx/storybook Infers Tasks + +The `@nx/storybook` plugin will create a task for any project that has a Storybook configuration file present. Any of the following files will be recognized as a Storybook configuration file: + +- `.storybook/main.js` +- `.storybook/main.ts` +- `.storybook/main.cjs` +- `.storybook/main.cts` +- `.storybook/main.mjs` +- `.storybook/main.mts` + +### 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 --web` in the command line. + +### @nx/storybook Configuration + +The `@nx/storybook/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/storybook/plugin", + "options": { + "buildStorybookTargetName": "build-storybook", + "serveStorybookTargetName": "storybook", + "testStorybookTargetName": "test-storybook", + "staticStorybookTargetName": "static-storybook" + } + } + ] +} ``` +- The `builtStorybookTargetName`, `serveStorybookTargetName`, `testStorybookTargetName` and `staticStorybookTargetName` options control the names of the inferred Storybook tasks. The default names are `build-storybook`, `storybook`, `test-storybook` and `static-storybook`. + {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/storybook` package with your package manager. ```shell -pnpm add -D @nx/storybook +npm add -D @nx/storybook ``` {% /tab %} diff --git a/docs/shared/packages/vite/vite-plugin.md b/docs/shared/packages/vite/vite-plugin.md index 8dc7c626606d4..268149d633515 100644 --- a/docs/shared/packages/vite/vite-plugin.md +++ b/docs/shared/packages/vite/vite-plugin.md @@ -16,7 +16,7 @@ Why should you use this plugin? Read more about Vite and Vitest in the [Vite documentation](https://vitejs.dev/). -## Setting up a new Nx workspace with Vite +## Setting up a new Nx workspace with @nx/vite Here's an example on how to create a new React app with Vite @@ -24,9 +24,80 @@ Here's an example on how to create a new React app with Vite npx create-nx-workspace@latest --preset=react-standalone --bundler=vite ``` -## Add Vite to an existing workspace +### Installation -There is a number of ways to use Vite in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/vite` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/vite` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/vite +``` + +This will install the correct version of `@nx/vite`. + +### How @nx/vite Infers Tasks + +The `@nx/vite` plugin will create a task for any project that has a Vite configuration file present. Any of the following files will be recognized as a Vite configuration file: + +- `vite.config.js` +- `vite.config.ts` +- `vite.config.mjs` +- `vite.config.mts` +- `vite.config.cjs` +- `vite.config.cts` +- `vitest.config.js` +- `vitest.config.ts` +- `vitest.config.mjs` +- `vitest.config.mts` +- `vitest.config.cjs` +- `vitest.config.cts` + +### 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 --web` in the command line. + +### @nx/vite Configuration + +The `@nx/vite/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/vite/plugin", + "options": { + "buildTargetName": "build", + "previewTargetName": "preview", + "testTargetName": "test", + "serveTargetName": "serve", + "serveStaticTargetName": "serve-static" + } + } + ] +} +``` + +- The `buildTargetName`, `previewTargetName`, `testTargetName`, `serveTargetName` and `serveStaticTargetName` options control the names of the inferred Vite tasks. The default names are `build`, `preview`, `test`, `serve` and `serve-static`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/vite` package with your package manager. + +```shell +npm add -D @nx/vite +``` + +{% /tab %} +{% /tabs %} + +## Using @nx/vite ### Generate a new project using Vite @@ -55,49 +126,3 @@ nx g @nx/web:app my-app --bundler=vite You can use the `@nx/vite:configuration` generator to change your React or Web project to use Vite.js. This generator will modify your project's configuration to use Vite.js, and it will also install all the necessary dependencies, including the `@nx/vite` plugin.. You can read more about this generator on the [`@nx/vite:configuration`](/nx-api/vite/generators/configuration) generator page. - -### Initialize Vite - -If you do not want to create any new projects or convert any existing projects yet, you can still use Nx to install all the necessary dependencies for Vite.js. This, for example, could be useful if you want to set up Vite.js manually for a project. - -#### Install the `@nx/vite` plugin - -{% callout type="note" title="Keep Nx Package Versions In Sync" %} -Make sure to install the `@nx/vite` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). -{% /callout %} - -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/vite -``` - -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/vite -``` - -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/vite -``` - -{% /tab %} -{% /tabs %} - -#### Ask Nx to install the necessary dependencies - -After you install the plugin, you can automatically initialize the project with Vite using an Nx generator: - -```bash -nx g @nx/vite:init -``` - -{% callout type="note" title="Choosing a framework" %} -You will notice that the generator will ask you of the framework you are planning to use. This is just to make sure that the right dependencies are installed. You can always install manually any other dependencies you need. -{% /callout %} diff --git a/docs/shared/packages/vue/vue-plugin.md b/docs/shared/packages/vue/vue-plugin.md index d1e514316220f..814ca05c84040 100644 --- a/docs/shared/packages/vue/vue-plugin.md +++ b/docs/shared/packages/vue/vue-plugin.md @@ -5,50 +5,47 @@ description: The Nx Plugin for Vue contains generators for managing Vue applicat The Nx plugin for [Vue](https://vuejs.org/). -## Setting up a new Nx workspace with Vue +## Setting Up @nx/vue -You can create a new workspace that uses Vue with one of the following commands: +### Generating a new Workspace -- Generate a new monorepo with a Vue app set up with Vue - -```shell -npx create-nx-workspace@latest --preset=vue -``` +To create a new workspace with React, run `npx create-nx-workspace@latest --preset=vue`. {% callout type="note" title="Vue Standalone Tutorial" %} For a full tutorial experience, follow the [Vue Standalone Tutorial](/getting-started/tutorials/vue-standalone-tutorial) {% /callout %} -## Add Vue to an existing workspace +### Installation -There are a number of ways to use Vue in your existing workspace. +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/vue` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} -### Install the `@nx/vue` plugin +In any Nx workspace, you can install `@nx/vue` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/vue +nx add @nx/vue ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/vue -``` +This will install the correct version of `@nx/vue`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/vue` package with your package manager. ```shell -pnpm add -D @nx/vue +npm add -D @nx/vue ``` {% /tab %} {% /tabs %} +## Using the @nx/vue Plugin + ### Generate a new project using Vue To generate a Vue application, run the following: diff --git a/docs/shared/packages/web/web-plugin.md b/docs/shared/packages/web/web-plugin.md index e24927d7d4c9a..cadc015e3b41e 100644 --- a/docs/shared/packages/web/web-plugin.md +++ b/docs/shared/packages/web/web-plugin.md @@ -4,40 +4,43 @@ The Nx Plugin for Web Components contains generators for managing Web Component - Scaffolding for creating buildable libraries that can be published to npm. - Utilities for automatic workspace refactoring. -## Setting Up Web +## Setting Up @nx/web -To create a new workspace with web, run `npx create-nx-workspace@latest --preset=web-components`. +### Generating a new Workspace + +To create a new workspace with React, run `npx create-nx-workspace@latest --preset=web-components`. + +### Installation {% callout type="note" title="Keep Nx Package Versions In Sync" %} Make sure to install the `@nx/web` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -To add the web plugin to an existing workspace, run one of the following: +In any Nx workspace, you can install `@nx/web` by running the following command: {% tabs %} -{% tab label="npm" %} +{% tab label="Nx 18+" %} ```shell -npm add -D @nx/web +nx add @nx/web ``` -{% /tab %} -{% tab label="yarn" %} - -```shell -yarn add -D @nx/web -``` +This will install the correct version of `@nx/web`. {% /tab %} -{% tab label="pnpm" %} +{% tab label="Nx < 18" %} + +Install the `@nx/web` package with your package manager. ```shell -pnpm add -D @nx/web +npm add -D @nx/web ``` {% /tab %} {% /tabs %} +## Using the @nx/web Plugin + ### Creating Applications You can add a new application with the following: diff --git a/docs/shared/packages/webpack/plugin-overview.md b/docs/shared/packages/webpack/plugin-overview.md index af0c063509a9c..103051397e9bf 100644 --- a/docs/shared/packages/webpack/plugin-overview.md +++ b/docs/shared/packages/webpack/plugin-overview.md @@ -25,6 +25,72 @@ npx create-nx-workspace@latest --preset=react-standalone --bundler=webpack npx create-nx-workspace@latest --preset=react-monorepo --bundler=webpack ``` +### Installation + +{% callout type="note" title="Keep Nx Package Versions In Sync" %} +Make sure to install the `@nx/webpack` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). +{% /callout %} + +In any Nx workspace, you can install `@nx/webpack` by running the following command: + +{% tabs %} +{% tab label="Nx 18+" %} + +```shell +nx add @nx/webpack +``` + +This will install the correct version of `@nx/webpack`. + +### How @nx/webpack Infers Tasks + +The `@nx/webpack` plugin will create a task for any project that has a Webpack configuration file present. Any of the following files will be recognized as a Webpack configuration file: + +- `webpack.config.js` +- `webpack.config.ts` +- `webpack.config.mjs` +- `webpack.config.mts` +- `webpack.config.cjs` +- `webpack.config.cts` + +### 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 --web` in the command line. + +### @nx/webpack Configuration + +The `@nx/webpack/plugin` is configured in the `plugins` array in `nx.json`. + +```json {% fileName="nx.json" %} +{ + "plugins": [ + { + "plugin": "@nx/webpack/plugin", + "options": { + "buildTargetName": "build", + "previewTargetName": "preview", + "serveTargetName": "serve", + "serveStaticTargetName": "serve-static" + } + } + ] +} +``` + +- The `buildTargetName`, `previewTargetName`, `serveTargetName` and `serveStaticTargetName` options control the names of the inferred Webpack tasks. The default names are `build`, `preview`, `serve` and `serve-static`. + +{% /tab %} +{% tab label="Nx < 18" %} + +Install the `@nx/webpack` package with your package manager. + +```shell +npm add -D @nx/webpack +``` + +{% /tab %} +{% /tabs %} + ## Generate a new project using Webpack You can generate a [React](/nx-api/react) application or a [Web](/nx-api/web) application that uses Webpack in an existing Nx workspace. The [`@nx/react:app`](/nx-api/react/generators/application), [`@nx/node:app`](/nx-api/node/generators/application) and [`@nx/web:app`](/nx-api/web/generators/application) generators accept the `bundler` option, where you can pass `webpack`. This will generate a new application configured to use Webpack, and it will also install all the necessary dependencies, including the `@nx/webpack` plugin. diff --git a/docs/shared/packages/webpack/webpack-config-setup.md b/docs/shared/packages/webpack/webpack-config-setup.md index 1a9a371d12c59..57bdce655eca2 100644 --- a/docs/shared/packages/webpack/webpack-config-setup.md +++ b/docs/shared/packages/webpack/webpack-config-setup.md @@ -1,172 +1,199 @@ --- -title: How to configure webpack on your Nx workspace +title: Configure Webpack in your Nx workspace description: A guide on how to configure webpack on your Nx workspace, and instructions on how to customize your webpack configuration --- -# Configure webpack on your Nx workspace +# Configure Webpack in your Nx workspace -You can configure Webpack using a `webpack.config.js` file in your project. You can set the path to this file in your `project.json` file, in the `build` target options: +You can configure Webpack using a [`webpack.config.js`](https://webpack.js.org/concepts/configuration/) file in your project. Nx infers the `build` and `serve` targets from your webpack configuration as long as you have `@nx/webpack/plugin` added to your `nx.json`. -```json -//... -"my-app": { - "targets": { - //... - "build": { - "executor": "@nx/webpack:webpack", - //... - "options": { - //... - "webpackConfig": "apps/my-app/webpack.config.js" - }, - "configurations": { - ... - } - }, +```json5 {% fileName="nx.json" %} +"plugins": [ + { + "plugin": "@nx/webpack/plugin", + "options": { + "buildTargetName": "build", + "serveTargetName": "serve" } -} + } +] ``` -In that file, you can add the necessary configuration for Webpack. You can read more on how to configure webpack in the [Webpack documentation](https://webpack.js.org/concepts/configuration/). - -## Using webpack with `isolatedConfig` - -Setting `isolatedConfig` to `true` in your `project.json` file means that Nx will not apply the Nx webpack plugins automatically. In that case, the Nx plugins need to be applied in the project's `webpack.config.js` file (e.g. `withNx`, `withReact`, etc.). So don't forget to also specify the path to your webpack config file (using the `webpackConfig` option). - -Note that this is the new default setup for webpack in the latest version of Nx. - -Set `isolatedConfig` to `true` in your `project.json` file in the `build` target options like this: +If you are using the [`@nx/webpack:webpack`](/nx-api/webpack/executors/webpack) executor, the path to your webpack config is set in the `webpackConfig` option in your `project.json` file. -```json -//... +```json5 {% fileName="project.json" highlightLines=["7"] %} "my-app": { - "targets": { + "targets": { + //... + "build": { + "executor": "@nx/webpack:webpack", + "options": { + "webpackConfig": "apps/my-app/webpack.config.js", //... - "build": { - "executor": "@nx/webpack:webpack", - //... - "options": { - //... - "webpackConfig": "apps/my-app/webpack.config.js", - "isolatedConfig": true - }, - "configurations": { - ... - } - }, - } + }, + // ... + }, + } } ``` -Now, you need to manually add the Nx webpack plugins in your `webpack.config.js` file for Nx to work properly. Let's see how to do that. +In the webpack config file, you can add the necessary configuration for Webpack. Read more on how to configure Webpack in the [Webpack documentation](https://webpack.js.org/concepts/configuration/). -### Basic configuration for Nx +## Basic and Nx-enhanced configuration files -You should start with a basic webpack configuration for Nx in your project, that looks like this: +Nx supports two flavors of Webpack configuration files: -```js {% fileName="apps/my-app/webpack.config.js" %} -const { composePlugins, withNx } = require('@nx/webpack'); +1. [_Basic_](#basic-configuration-for-nx) (or standard) Webpack configuration. The file exports a Webpack config object, or one of the [standard configuration types](https://webpack.js.org/configuration/configuration-types). +2. [_Nx-enhanced_](#nxenhanced-configuration-with-composable-plugins) Webpack configuration. The file exports a function that takes in a Webpack configuration object, plus the [`@nx/webpack:webpack`](/nx-api/webpack/executors/webpack) options and context, and returns an updated Webpack configuration object. -module.exports = composePlugins(withNx(), (config, { options, context }) => { - // customize webpack config here - return config; -}); -``` +The basic configuration works with Webpack CLI, whereas the Nx-enhanced configuration requires the use of the `@nx/webpack:webpack` executor. -The `withNx()` plugin adds the necessary configuration for Nx to work with Webpack. The `composePlugins` function allows you to add other plugins to the configuration. - -#### The `composePlugins` function - -The `composePlugins` function takes a list of plugins and a function, and returns a webpack `Configuration` object. The `composePlugins` function is an enhanced version of the [webpack configuration function](https://webpack.js.org/configuration/configuration-types/#exporting-a-function), which allows you to add plugins to the configuration, and provides you with a function which accepts two arguments: +### Basic configuration for Nx -1. `config`: The webpack configuration object. -2. An object with the following properties: - - `options`: The options passed to the `@nx/webpack:webpack` executor. - - `context`: The context passed of the `@nx/webpack:webpack` executor. +{% callout type="info" title="Module federation support" %} +Currently, Nx module federation requires an enhanced Webpack configuration file an the use of the `withModuleFederation` plugin. See the next section for more details. +{% /callout %} -This gives you the ability to customize the webpack configuration as needed, and make use of the options and context passed to the executor, as well. +A basic Webpack configuration was introduced in Nx 18, and it looks like this: -### Add configurations for other functionalities +```js {% fileName="apps/demo/webpack.config.js" %} +const { NxWebpackPlugin } = require('@nx/webpack'); +const { join } = require('path'); -In addition to the basic configuration, you can add configurations for other frameworks or features. The `@nx/webpack` package provides plugins such as `withWeb` and `withReact`. This plugins provide features such as TS support, CSS support, JSX support, etc. You can read more about how these plugins work and how to use them in our [Webpack Plugins guide](/recipes/webpack/webpack-plugins). +module.exports = { + output: { + path: join(__dirname, '../../dist/apps/demo'), + }, + devServer: { + port: 4200, + }, + plugins: [ + new NxWebpackPlugin({ + main: './src/main.ts', + tsConfig: './tsconfig.app.json', + index: './src/index.html', + styles: ['./src/styles.css'], + outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none', + optimization: process.env['NODE_ENV'] === 'production', + }), + ], +}; +``` -You may still reconfigure everything manually, without using the Nx plugins. However, these plugins ensure that you have the necessary configuration for Nx to work with your project. +The [`NxWebpackPlugin`](/recipes/webpack/webpack-plugins#nxwebpackplugin) plugin takes a `main` entry file and produces a bundle in the output directory as defined in `output.path`. You can also pass the `index` option if it is a webapp, which will handle outputting scripts and stylesheets in the output file. Note that `NxWebpackPlugin` is optional, and you can bring your own Webpack configuration without using it or any plugins from `@nx/webpack`. -## Customize your Webpack config +For more information, see the [Webpack plugins guide](/recipes/webpack/webpack-plugins). -For most apps, the default configuration of webpack is sufficient, but sometimes you need to tweak a setting in your webpack config. This guide explains how to make a small change without taking on the maintenance burden of the entire webpack config. +### Nx-enhanced configuration with composable plugins -### Configure webpack for React projects +{% callout type="info" title="Non-standard webpack config" %} +Nx-enhanced configuration, via `composePlugins` and [`withNx`](/recipes/webpack/webpack-plugins#withnx) functions, requires the usage of `@nx/webpack:webpack` executor in your `project.json` file. This flavor of configuration do not work with the Webpack CLI. +{% /callout %} -React projects use the `@nx/react` package to build their apps. This package provides a `withReact` plugin that adds the necessary configuration for React to work with webpack. You can use this plugin to add the necessary configuration to your webpack config. +Nx supports a function to be returned from the Webpack configuration file. This function is a composable plugin that is understood by the `@nx/webpack:webpack` executor. The enhanced configuration looks something like this: -```js {% fileName="apps/my-app/webpack.config.js" %} +```js {% fileName="apps/demo/webpack.config.js" %} const { composePlugins, withNx } = require('@nx/webpack'); -const { withReact } = require('@nx/react'); -// Nx plugins for webpack. module.exports = composePlugins( + // Default Nx composable plugin withNx(), - withReact(), + // Custom composable plugin (config, { options, context }) => { - // Update the webpack config as needed here. - // e.g. config.plugins.push(new MyPlugin()) + // `config` is the Webpack configuration object + // `options` is the options passed to the `@nx/webpack:webpack` executor + // `context` is the context passed to the `@nx/webpack:webpack` executor + // customize configuration here return config; } ); ``` -### Add a CSS loader to your webpack config +There are two advantages of this approach: -To add the `css-loader` to your config, install it and add the rule. +1. You can chain multiple plugins together using the `composePlugins` function. Each plugin can update the webpack configuration as needed. +2. You gain access to the target options and executor context within the webpack configuration file. -{% tabs %} -{% tab label="npm" %} +This gives you the ability to customize the Webpack configuration as needed, and make use of the options and context passed to the executor, as well. -```shell -npm add -D css-loader -``` +#### Additional composable plugins for Nx -{% /tab %} -{% tab label="yarn" %} +In addition to the `withNx` composable plugin, Nx provides other composable plugins such as `withWeb`, `withReact`, and `withModuleFederation`. You can read more about how these plugins work and how to use them in our [Webpack plugins guide](/recipes/webpack/webpack-plugins). -```shell -yarn add -D css-loader -``` +## Customize your Webpack configuration -{% /tab %} -{% tab label="pnpm" %} +For most apps, the default configuration of Webpack is sufficient, but sometimes you need to tweak a setting in your Webpack config. This guide explains how to make a small change without taking on the maintenance burden of the entire webpack config. + +### Configure Webpack for React projects + +React projects use the `@nx/react` package to build their apps. This package provides `NxReactWebpackPlugin` and a `withReact` composable plugin that adds the necessary configuration for React to work with Webpack. The `NxReactWebpackPlugin` is used in a basic Webpack configuration file, whereas `withReact` is requires a Nx-enhanced Webpack configuration file. + +{% tabs %} +{% tab label="Basic Webpack configuration" %} + +```js {% fileName="apps/demo/app/webpack.config.js" %} +const { NxWebpackPlugin } = require('@nx/webpack'); +const { NxReactWebpackPlugin } = require('@nx/react'); +const { join } = require('path'); -```shell -pnpm add -D css-loader +module.exports = { + output: { + path: join(__dirname, '../../dist/apps/demo'), + }, + devServer: { + port: 4200, + }, + plugins: [ + new NxWebpackPlugin({ + tsConfig: './tsconfig.app.json', + compiler: 'swc', + main: './src/main.tsx', + index: '.src/index.html', + styles: ['./src/styles.css'], + outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none', + optimization: process.env['NODE_ENV'] === 'production', + }), + new NxReactWebpackPlugin({ + // Uncomment this line if you don't want to use SVGR + // See: https://react-svgr.com/ + // svgr: false + }), + ], +}; ``` {% /tab %} -{% /tabs %} +{% tab label="Nx-enhanced Webpack configuration" %} -```js {% fileName="apps/my-app/webpack.config.js" %} +```js {% fileName="apps/demo/app/webpack.config.js" %} const { composePlugins, withNx } = require('@nx/webpack'); -const { merge } = require('webpack-merge'); +const { withReact } = require('@nx/react'); -module.exports = composePlugins(withNx(), (config, { options, context }) => { - return merge(config, { - module: { - rules: [ - { - test: /\.css$/i, - use: ['style-loader', 'css-loader'], - }, - ], - }, - }); -}); +// Nx composable plugins for webpack. +module.exports = composePlugins( + withNx(), + withReact(), + (config, { options, context }) => { + // Update the webpack configuration as needed here. + // e.g. config.plugins.push(new MyPlugin()) + return config; + } +); ``` -### Configure webpack for Module Federation +{% /tab %} + +{% /tabs %} + +### Configure Webpack for Module Federation + +{% callout type="info" title="Non-standard webpack config" %} +`composePlugins`, `withNx`, and `withModuleFederation` do not work with the Webpack CLI and requires the use of the `@nx/webpack:webpack` executor. +{% /callout %} If you use the [Module Federation](/concepts/module-federation/faster-builds-with-module-federation) support from `@nx/angular` or `@nx/react` then -you can customize your webpack configuration as follows. +you can customize your Webpack configuration as follows. ```js {% fileName="apps/my-app/webpack.config.js" %} const { composePlugins, withNx } = require('@nx/webpack'); @@ -188,12 +215,12 @@ module.exports = composePlugins( ); ``` -Reference the [webpack documentation](https://webpack.js.org/configuration/) for details on the structure of the webpack -config object. +Reference the [Webpack documentation](https://webpack.js.org/configuration/) for details on the structure of the Webpack +configuration object. -### Configure webpack for Next.js Applications +### Configure Webpack for Next.js Applications -Next.js supports webpack customization in the `next.config.js` file. +Next.js supports Webpack customization in the `next.config.js` file. ```js {% fileName="next.config.js" %} const { withNx } = require('@nx/next/plugins/with-nx'); diff --git a/docs/shared/packages/webpack/webpack-plugins.md b/docs/shared/packages/webpack/webpack-plugins.md index 5220d439681a3..d7f6833357d28 100644 --- a/docs/shared/packages/webpack/webpack-plugins.md +++ b/docs/shared/packages/webpack/webpack-plugins.md @@ -5,26 +5,372 @@ description: A guide for webpack plugins that are provided by Nx. # Webpack plugins -Nx uses enhanced webpack configuration files (e.g. `webpack.config.js`). These configuration files export a _plugin_ that takes in a webpack -[configuration](https://webpack.js.org/configuration/) object and returns an updated configuration object. Plugins are used by Nx to add -functionality to the webpack build. +Nx provides two types of Webpack plugins: -This guide contains information on the plugins provided by Nx. For more information on customizing webpack configuration, refer to the -[Nx Webpack configuration guide](/recipes/webpack/webpack-config-setup). +1. [_Basic_](#basic-plugins) plugins that work in a + standard [webpack configuration](https://webpack.js.org/configuration/) file. +2. [_Nx-enhanced_](#nxenhanced-plugins) plugins that work with + the [`@nx/webpack:webpack`](/nx-api/webpack/executors/webpack) executor. -## withNx +The basic plugins are used in Nx 18 to provide seamless integration with the Webpack CLI. Prior to Nx 18, apps are +generated with Nx-enhanced plugins and require `@nx/webpack:webpack` executor to be used. -The `withNx` plugin provides common configuration for the build, including TypeScript support and linking workspace libraries (via tsconfig paths). +This guide contains information on the plugins provided by Nx. For more information on webpack configuration and the +difference between basic and Nx-enhanced configuration, refer to +the [Nx Webpack configuration guide](/recipes/webpack/webpack-config-setup). -### Options +## Basic plugins -#### skipTypeChecking +The basic plugins work with a standard webpack configuration file by adding them to the `plugins` option. + +### NxWebpackPlugin + +The `NxWebpackPlugin` plugin provides common configuration for the build, including TypeScript support and linking +workspace libraries (via tsconfig paths). + +#### Options + +##### tsConfig + +Type: `string` + +The tsconfig file for the project. e.g. `tsconfig.json`. + +##### main + +Type: `string` + +The entry point for the bundle. e.g. `src/main.ts`. + +##### additionalEntryPoints + +Type: `Array<{ entryName: string; entryPath: string; }>` + +Secondary entry points for the bundle. + +#### assets + +Type: `string[]` + +Assets to be copied over to the output path. + +##### babelConfig + +Type: `string` + +Babel configuration file if compiler is babel. + +##### babelUpwardRootMode + +Type: `boolean` +If true, Babel will look for a babel.config.json up the directory tree. + +##### baseHref + +Type: `string` + +Set `` for the resulting index.html. + +##### compiler + +Type: `'babel' | 'swc' | 'tsc'` + +The compiler to use. Default is `babel` and requires a `.babelrc` file. + +##### crossOrigin + +Type: `'none' | 'anonymous' | 'use-credentials'` + +Set `crossorigin` attribute on the `script` and `link` tags. + +##### deleteOutputPath + +Type: `boolean` + +Delete the output path before building. + +##### deployUrl + +Type: `string` + +The deploy path for the application. e.g. `/my-app/` + +##### externalDependencies + +Type: `'all' | 'none' | string[]` + +Define external packages that will not be bundled. Use `all` to exclude all 3rd party packages, and `none` to bundle all +packages. Use an array to exclude specific packages from the bundle. Default is `none`. + +##### extractCss + +Type: `boolean` + +Extract CSS as an external file. Default is `true`. + +##### extractLicenses + +Type: `boolean` +Extract licenses from 3rd party modules and add them to the output. + +##### fileReplacements + +Type: `FileReplacement[]` + +Replace files at build time. e.g. `[{ "replace": "src/a.dev.ts", "with": "src/a.prod.ts" }]` + +##### generateIndexHtml + +Type: `boolean` + +Generate an `index.html` file if `index.html` is passed. Default is `true` + +##### generatePackageJson + +Type: `boolean` + +Generate a `package.json` file for the bundle. Useful for Node applications. + +##### index + +Type: `string` + +Path to the `index.html`. + +##### memoryLimit + +Type: `number` + +Set the memory limit for the type-checking process. Default is `2048`. + +##### namedChunks + +Type: `boolean` + +Use the source file name in output chunks. Useful for development or for Node. + +##### optimization + +Type: `boolean` + +Optimize the bundle using Terser. + +##### outputFileName + +Type: `string` + +Specify the output filename for the bundle. Useful for Node applications that use `@nx/js:node` to serve. + +##### outputHashing + +Type: `'none' | 'all'` + +Use file hashes in the output filenames. Recommended for production web applications. + +##### outputPath + +Type: `string` + +Override `output.path` in webpack configuration. This setting is not recommended and exists for backwards compatibility. + +##### poll + +Type: `number` + +Override `watchOptions.poll` in webpack configuration. This setting is not recommended and exists for backwards +compatibility. + +##### polyfills + +Type: `string` + +The polyfill file to use. Useful for supporting legacy browsers. e.g. `src/polyfills.ts` + +##### postcssConfig + +Type: `string` +Manually set the PostCSS configuration file. By default, PostCSS will look for `postcss.config.js` in the directory. + +##### progress + +Type: `boolean` + +Display build progress in the terminal. + +##### runtimeChunk + +Type: `boolean` + +Add an additional chunk for the Webpack runtime. Defaults to `true` when `target === 'web'`. + +##### scripts + +Type: `string[]` + +External scripts that will be included before the main application entry. + +##### skipTypeChecking + +Type: `boolean` + +Skip type checking. Default is `false`. + +##### sourceMap + +Type: `boolean | 'hidden'` + +Generate source maps. + +##### ssr + +Type: `boolean` + +When `true`, `process.env.NODE_ENV` will be excluded from the bundle. Useful for building a web application to run in a +Node environment. + +##### statsJson + +Type: `boolean` + +Generate a `stats.json` file which can be analyzed using tools such as `webpack-bundle-analyzer`. + +##### stylePreprocessorOptions + +Type: `object` + +Options for the style preprocessor. e.g. `{ "includePaths": [] }` for SASS. + +##### styles + +Type: `string[]` + +External stylesheets that will be included with the application. + +##### subresourceIntegrity + +Type: `boolean` + +Enables the use of subresource integrity validation. + +##### target + +Type: `string | string[]` + +Override the `target` option in webpack configuration. This setting is not recommended and exists for backwards +compatibility. + +##### transformers + +Type: `TransformerEntry[]` + +List of TypeScript Compiler Transformers Plugins. + +##### vendorChunk + +Type: `boolean` + +Generate a separate vendor chunk for 3rd party packages. + +##### verbose + +Type: `boolean` + +Log additional information for debugging purposes. + +##### watch + +Type: `boolean` + +Watch for file changes. + +#### Example + +```js +const { NxWebpackPlugin } = require('@nx/webpack'); +const { join } = require('path'); + +module.exports = { + output: { + path: join(__dirname, '../../dist/apps/demo'), + }, + devServer: { + port: 4200, + }, + plugins: [ + new NxWebpackPlugin({ + main: './src/main.ts', + tsConfig: './tsconfig.app.json', + index: './src/index.html', + styles: ['./src/styles.css'], + outputHashing: process.env['NODE_ENV'] === 'production' ? 'all' : 'none', + optimization: process.env['NODE_ENV'] === 'production', + }), + ], +}; +``` + +### NxReactWebpackPlugin + +#### Options + +##### svgr + +Type: `boolean` + +Enables or disables [React SVGR](https://react-svgr.com/). Default is `true`. + +#### Example + +```js +const { NxReactWebpackPlugin } = require('@nx/react'); +const { join } = require('path'); + +module.exports = { + // ... + plugins: [ + new NxReactWebpackPlugin({ + svgr: false, + }), + ], +}; +``` + +## Nx-enhanced plugins + +The Nx-enhanced plugins work with `@nx/webpack:webpack` executor and receive the target options and context from the +executor. These are used prior to Nx 18, and are still used when using [Module Federation](/concepts/module-federation/module-federation-and-nx). + +The plugins are used in conjunction with `composePlugins` utility to generate a final Webpack configuration object, once all of the plugins have applied their changes. + +```js {% fileName="webpack.config.js" %} +const { composePlugins } = require('@nx/webpack'); + +function myCustomPlugin() { + // `options` and `context` are the target options and + // `@nx/webpack:webpack` executor context respectively. + return (webpackConfig, { options, context }) => { + // Do something with the config. + return webpackConfig; + }; +} + +module.export = composePlugins(withNx(), withReact(), myCustomPlugin()); +``` + +### withNx + +The `withNx` plugin provides common configuration for the build, including TypeScript support and linking workspace +libraries (via tsconfig paths). + +#### Options + +##### skipTypeChecking Type: `boolean` Disable type checks (useful to speed up builds). -### Example +#### Example ```js const { composePlugins, withNx } = require('@nx/webpack'); @@ -35,31 +381,33 @@ module.exports = composePlugins(withNx(), (config) => { }); ``` -## withWeb +### withWeb -The `withWeb` plugin adds support for CSS/SASS/Less stylesheets, assets (such as images and fonts), and `index.html` processing. +The `withWeb` plugin adds support for CSS/SASS/Less stylesheets, assets (such as images and fonts), and `index.html` +processing. -### Options +#### Options -#### baseHref +##### baseHref Type: `string` Base URL for the application being built. -#### crossOrigin +##### crossOrigin Type: `'none' | 'anonymous' | 'use-credentials'` -"The `crossorigin` attribute to use for generated javascript script tags. One of 'none' | 'anonymous' | 'use-credentials'." +"The `crossorigin` attribute to use for generated javascript script tags. One of 'none' | 'anonymous' | ' +use-credentials'." -#### deployUrl +##### deployUrl Type: `string` URL where the application will be deployed. -#### extractCss +##### extractCss Type: `boolean` @@ -69,39 +417,42 @@ Extract CSS into a `.css` file. Type: `boolean` -Generates `index.html` file to the output path. This can be turned off if using a webpack plugin to generate HTML such as `html-webpack-plugin`. +Generates `index.html` file to the output path. This can be turned off if using a webpack plugin to generate HTML such +as `html-webpack-plugin`. -#### index +##### index Type: `string` HTML File which will be contain the application. -#### postcssConfig +##### postcssConfig Type: `string` -Set a path (relative to workspace root) to a PostCSS config that applies to the app and all libs. Defaults to `undefined`, which auto-detects postcss.config.js files in each `app`. +Set a path (relative to workspace root) to a PostCSS config that applies to the app and all libs. Defaults +to `undefined`, which auto-detects postcss.config.js files in each `app`. -#### scripts +##### scripts Type: `string[]` Paths to scripts (relative to workspace root) which will be included before the main application entry. -#### stylePreprocessorOptions +##### stylePreprocessorOptions Type: `{ includePaths: string[] }` -Options to pass to style preprocessors. `includePaths` is a list of paths that are included (e.g. workspace libs with stylesheets). +Options to pass to style preprocessors. `includePaths` is a list of paths that are included (e.g. workspace libs with +stylesheets). -#### styles +##### styles Type: `string[]` Paths to stylesheets (relative to workspace root) which will be included with the application. -#### subresourceIntegrity +##### subresourceIntegrity Type: `boolean` @@ -126,21 +477,22 @@ module.exports = composePlugins( ); ``` -## withReact +### withReact -The `withReact` plugin adds support for React JSX, [SVGR](https://react-svgr.com/), and [Fast Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin) +The `withReact` plugin adds support for React JSX, [SVGR](https://react-svgr.com/), +and [Fast Refresh](https://github.com/pmmmwh/react-refresh-webpack-plugin) -### Options +#### Options The options are the same as [`withWeb`](#withweb) plus the following. -#### svgr +##### svgr Type: `undefined|false` SVGR allows SVG files to be imported as React components. Set this to `false` to disable this behavior. -### Example +#### Example ```js const { composePlugins, withNx } = require('@nx/webpack'); @@ -160,36 +512,40 @@ module.exports = composePlugins( ); ``` -## withModuleFederation and withModuleFederationForSSR +### withModuleFederation and withModuleFederationForSSR -The `withModuleFederation` and `withModuleFederationForSSR` plugins add module federation support to the webpack build. These plugins use +The `withModuleFederation` and `withModuleFederationForSSR` plugins add module federation support to the webpack build. +These plugins use [`ModuleFederationPlugin`](https://webpack.js.org/concepts/module-federation/) and provide a simpler API through Nx. -For more information, refer to the [Module Federation recipe](/concepts/module-federation/faster-builds-with-module-federation). +For more information, refer to +the [Module Federation recipe](/concepts/module-federation/faster-builds-with-module-federation). -### Options +#### Options -Both `withModuleFederation` and `withModuleFederationForSSR` share the same options. The `withModuleFederation` plugin is for the browser, and the `withModuleFederationForSSR` plugin is used on the server-side (Node). +Both `withModuleFederation` and `withModuleFederationForSSR` share the same options. The `withModuleFederation` plugin +is for the browser, and the `withModuleFederationForSSR` plugin is used on the server-side (Node). -#### name +##### name Type: `string` The name of the host/remote application. -#### remotes +##### remotes Type: `Aray` -For _host_ to specify all _remote_ applications. If a string is used, Nx will match it with a matching remote in the workspace. +For _host_ to specify all _remote_ applications. If a string is used, Nx will match it with a matching remote in the +workspace. Use `[, ]` to specify the exact URL of the remote, rather than what's in the remote's `project.json` file. -#### library +##### library Type: `{ type: string; name: string }` -#### exposes +##### exposes Type: `Record` @@ -199,25 +555,32 @@ e.g. ```js exposes: { - './Module': '/src/remote-entry.ts', -}, + './Module' +: + '/src/remote-entry.ts', +} +, ``` -#### shared +##### shared Type: `Function` -Takes a library name and the current [share configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints), and returns one of +Takes a library name and the +current [share configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints), and returns one +of - `false` - Exclude this library from shared. - `undefined` - Keep Nx sharing defaults. -- `SharedLibraryConfig` - Override Nx sharing defaults with [custom configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints). +- `SharedLibraryConfig` - Override Nx sharing defaults + with [custom configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints). -#### additionalShared +##### additionalShared Type: `Array` -Shared libraries in addition to the ones that Nx detects automatically. Items match [`ModuleFederationPlugin`'s sharing configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints). +Shared libraries in addition to the ones that Nx detects automatically. Items +match [`ModuleFederationPlugin`'s sharing configuration](https://webpack.js.org/plugins/module-federation-plugin/#sharing-hints). {% tabs %} {% tab label="React Module Federation" %} diff --git a/docs/shared/plugins/intro.md b/docs/shared/plugins/intro.md index 80319e67ca294..cbaae96741ef3 100644 --- a/docs/shared/plugins/intro.md +++ b/docs/shared/plugins/intro.md @@ -1,6 +1,6 @@ # Getting Started with Plugins -Nx plugins contain [generators](/core-features/plugin-features/use-code-generators) and [executors](/core-features/plugin-features/use-task-executors) that extend the capabilities of an Nx workspace. They can be shared as npm packages or referenced locally within the same repo. +Nx plugins contain [generators](/features/generate-code) and [executors](/concepts/executors-and-configurations) that extend the capabilities of an Nx workspace. They can be shared as npm packages or referenced locally within the same repo. {% cards cols="4" %} @@ -18,8 +18,8 @@ Nx plugins help you scaffold new projects, pre-configure tooling, follow best pr {% cards cols="3" %} {% card title="Browse Existing Plugins" description="Find a plugin to use" url="/plugin-registry" /%} -{% card title="Use Task Executors" description="Run operations on your code" url="/core-features/plugin-features/use-task-executors" /%} -{% card title="Use Code Generators" description="Create or modify code" url="/core-features/plugin-features/use-code-generators" /%} +{% card title="Use Task Executors" description="Run operations on your code" url="/concepts/executors-and-configurations" /%} +{% card title="Generate Code" description="Create or modify code" url="/features/generate-code" /%} {% /cards %} diff --git a/docs/shared/react-standalone-tutorial/react-standalone.md b/docs/shared/react-standalone-tutorial/react-standalone.md index 76fcf792d51da..f0b2cc09e57eb 100644 --- a/docs/shared/react-standalone-tutorial/react-standalone.md +++ b/docs/shared/react-standalone-tutorial/react-standalone.md @@ -29,22 +29,15 @@ Here's the source code of the final result for this tutorial. -{% youtube -src="https://www.youtube.com/embed/OQ-Zc5tcxJE" -title="Tutorial: Standalone React Application" -/%} - ## Creating a new React App -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=64" /%} - Create a new standalone React application with the following command: ```{% command="npx create-nx-workspace@latest myreactapp --preset=react-standalone" path="~" %} ✔ Which bundler would you like to use? · vite ✔ Test runner to use for end to end (E2E) tests · cypress ✔ Default stylesheet format · css -✔ Do you want Nx Cloud to make your CI fast? · Yes +✔ Set up CI with caching, distribution and test deflaking · github ``` You can choose any bundler you like. In this tutorial we're going to use Vite. The above command generates the following structure: @@ -85,20 +78,18 @@ The setup includes.. Let me explain a couple of things that might be new to you. -| File | Description | -| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `nx.json` | This is where we fine-tune how Nx works. We define what [cacheable operations](/core-features/cache-task-results) there are, and configure our [task pipeline](/concepts/task-pipeline-configuration). More on that soon. | -| `project.json` | This file contains the targets that can be invoked for the `myreactapp` project. It is like a more evolved version of simple `package.json` scripts with more metadata attached. You can read more about it [here](/reference/project-configuration). | +| File | Description | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `nx.json` | This is where we fine-tune how Nx works. We define what [cacheable operations](/features/cache-task-results) there are, and configure our [task pipeline](/concepts/task-pipeline-configuration). More on that soon. | +| `project.json` | This file is where you can modify the inferred tasks for the `myreactapp` project. More about this later. | ## Serving the App -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=207" /%} - The most common tasks are already mapped in the `package.json` file: ```json {% fileName="package.json" %} { - "name": "reactutorial", + "name": "myreactapp", "scripts": { "start": "nx serve", "build": "nx build", @@ -120,70 +111,93 @@ Nx uses the following syntax to run tasks: ![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) -All targets, such as `serve`, `build`, `test` or your custom ones, are defined in the `project.json` file. +### Inferred Tasks -```json {% fileName="project.json"} -{ - "name": "myreactapp", - ... - "targets": { - "serve": { ... }, - "build": { ... }, - "preview": { ... }, - "test": { ... }, - "lint": { ... }, - "serve-static": { ... }, - }, -} -``` +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/features/integrate-with-editors) project detail view or run: -{% callout type="info" title="You can also use the package.json" %} - -Note that Nx can pick up tasks from both, the `package.json` as well as the `project.json`. [Read more](/core-features/run-tasks) - -{% /callout %} +```shell +nx show project myreactapp --web +``` -Each target contains a configuration object that tells Nx how to run that target. +{% project-details title="Project Details View (Simplified)" height="100px" %} -```json {% fileName="project.json"} +```json { - "name": "myreactapp", - ... - "targets": { - "serve": { - "executor": "@nx/vite:dev-server", - "defaultConfiguration": "development", - "options": { - "buildTarget": "reactutorial:build" - }, - "configurations": { - "development": { - "buildTarget": "reactutorial:build:development", - "hmr": true - }, - "production": { - "buildTarget": "reactutorial:build:production", - "hmr": false + "project": { + "name": "myreactapp", + "data": { + "root": ".", + "includedScripts": [], + "name": "myreactapp", + "targets": { + "build": { + "options": { + "cwd": ".", + "command": "vite build" + }, + "cache": true, + "dependsOn": ["^build"], + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["vite"] + } + ], + "outputs": ["{projectRoot}/build/myreactapp"], + "executor": "nx:run-commands", + "configurations": {} } - } - }, - ... + }, + "sourceRoot": "./src", + "projectType": "application", + "$schema": "node_modules/nx/schemas/project-schema.json", + "tags": [], + "implicitDependencies": [] + } }, + "sourceMap": { + "root": ["project.json", "nx/core/project-json"], + "includedScripts": ["package.json", "nx/core/package-json-workspaces"], + "name": ["project.json", "nx/core/project-json"], + "targets": ["project.json", "nx/core/project-json"], + "targets.build": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.command": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.options": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.cache": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.dependsOn": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.inputs": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.outputs": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.options.cwd": ["vite.config.ts", "@nx/vite/plugin"], + "sourceRoot": ["project.json", "nx/core/project-json"], + "projectType": ["project.json", "nx/core/project-json"], + "$schema": ["project.json", "nx/core/project-json"], + "tags": ["project.json", "nx/core/project-json"] + } } ``` -The most critical parts are: +{% /project-details %} -- `executor` - this is of the syntax `:`, where the `plugin` is an NPM package containing an [Nx Plugin](/extending-nx/intro/getting-started) and `` points to a function that runs the task. In this case, the `@nx/vite` plugin contains the `dev-server` executor which serves the React app using Vite. -- `options` - these are additional properties and flags passed to the executor function to customize it +If you expand the `build` task, you can see that it was created by the `@nx/vite` plugin by analyzing your `vite.config.ts` file. Notice the outputs are defined as `{projectRoot}/dist/myreactapp`. This value is being read from the `build.outDir` defined in your `vite.config.ts` file. Let's change that value in your `vite.config.ts` file: -Learn more about how to [run tasks with Nx](/core-features/run-tasks). +```ts {% fileName="vite.config.ts" %} +export default defineConfig({ + // ... + build: { + outDir: './build/myreactapp', + // ... + }, +}); +``` -## Testing and Linting - Running Multiple Tasks +Now if you look at the project details view, the outputs for the build target will say `{projectRoot}/build/myreactapp`. This feature ensures that Nx will always cache the correct files. -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=410" /%} +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. + +## Testing and Linting - Running Multiple Tasks -Our current setup doesn't just come with targets for serving and building the React application, but also has targets for unit testing, e2e testing and linting. Again, these are defined in the `project.json` file. We can use the same syntax as before to run these tasks: +Our current setup doesn't just come with targets for serving and building the React application, but also has targets for unit testing, e2e testing and linting. We can use the same syntax as before to run these tasks: ```bash nx test # runs tests using Vitest (or you can configure it to use Jest) @@ -207,7 +221,7 @@ More conveniently, we can also run them in parallel using the following syntax: ### Caching -One thing to highlight is that Nx is able to [cache the tasks you run](/core-features/cache-task-results). +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. @@ -225,15 +239,13 @@ Note that all of these targets are automatically cached by Nx. If you re-run a s Nx read the output from the cache instead of running the command for 10 out of 10 tasks. ``` -Not all tasks might be cacheable though. You can configure the `cache` properties in the targets under `targetDefaults` in the `nx.json` file. You can also [learn more about how caching works](/core-features/cache-task-results). +Not all tasks might be cacheable though. You can configure the `cache` properties in the targets under `targetDefaults` in the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). ## Nx Plugins? Why? -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=598" /%} +One thing you might be curious about is the [inferred tasks](/concepts/inferred-tasks). You may wonder why we are detecting tasks from your tooling configuration instead of directly defining them in `package.json` scripts or in the `project.json` file. -One thing you might be curious about is the project.json. You may wonder why we define tasks inside the `project.json` file instead of using the `package.json` file with scripts that directly launch Vite. - -Nx understands and supports both approaches, allowing you to define targets either in your `package.json` or `project.json` files. While both serve a similar purpose, the `project.json` file can be seen as an advanced form of `package.json` scripts, providing additional metadata and capabilities. In this tutorial, we utilize the `project.json` approach primarily because we take advantage of Nx Plugins. +Nx understands and supports both approaches, allowing you to define tasks in your `package.json` and `project.json` files or have Nx plugins automatically detect them. The inferred tasks give you the benefit of automatically setting the Nx cache settings for you based on your tooling configuration. In this tutorial, we take advantage of those inferred tasks to demonstrate the full value of Nx plugins. So, what are Nx Plugins? Nx Plugins are optional packages that extend the capabilities of Nx, catering to various specific technologies. For instance, we have plugins tailored to React (e.g., `@nx/react`), Vite (`@nx/vite`), Cypress (`@nx/cypress`), and more. These plugins offer additional features, making your development experience more efficient and enjoyable when working with specific tech stacks. @@ -241,9 +253,7 @@ So, what are Nx Plugins? Nx Plugins are optional packages that extend the capabi ## Creating New Components -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=706" /%} - -You can just create new React components as you normally would. However, Nx plugins usually also ship [generators](/core-features/plugin-features/use-code-generators). They allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin ships, run the following command and inspect the output: +You can just create new React components as you normally would. However, Nx plugins usually also ship [generators](/features/generate-code). They allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin ships, run the following command and inspect the output: ```{% command="npx nx list @nx/react" path="myreactapp" %} @@ -267,6 +277,7 @@ You can just create new React components as you normally would. However, Nx plug component-test : Generate a Cypress component test for a React component setup-tailwind : Set up Tailwind configuration for a project. setup-ssr : Set up SSR configuration for a project. + federate-module : Federate a module. EXECUTORS/BUILDERS @@ -278,7 +289,7 @@ You can just create new React components as you normally would. However, Nx plug If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. -More info can be found in [the integrate with editors article](/core-features/integrate-with-editors). +More info can be found in [the integrate with editors article](/features/integrate-with-editors). {% /callout %} @@ -317,8 +328,6 @@ export default HelloWorld; ## Building the App for Deployment -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=856" /%} - If you're ready and want to ship your application, you can build it using ```{% command="npx nx build" path="myreactapp" %} @@ -338,8 +347,6 @@ All the required files will be placed in the `dist/myreactapp` folder and can be ## You're ready to go! -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=906" /%} - In the previous sections you learned about the basics of using Nx, running tasks and navigating an Nx workspace. You're ready to ship features now! But there's more to learn. You have two possibilities here: @@ -349,8 +356,6 @@ But there's more to learn. You have two possibilities here: ## Modularizing your React App with Local Libraries -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=986" /%} - When you develop your React application, usually all your logic sits in the `app` folder. Ideally separated by various folder names which represent your "domains". As your app grows, this becomes more and more monolithic though. ``` @@ -380,8 +385,6 @@ Nx allows you to separate this logic into "local libraries". The main benefits i ### Creating Local Libraries -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=1041" /%} - Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for each of these areas using the React library generator: ``` @@ -439,14 +442,13 @@ Running the above commands should lead to the following directory structure: Each of these libraries -- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `nx test orders`) +- has a project details view where you can see the available tasks (e.g. running tests for just orders: `nx test orders`) +- has its own `project.json` file where you can customize targets - has a dedicated `index.ts` file which is the "public API" of the library - is mapped in the `tsconfig.base.json` at the root of the workspace ### Importing Libraries into the React Application -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=1245" /%} - All libraries that we generate automatically have aliases created in the root-level `tsconfig.base.json`. ```json {% fileName="tsconfig.base.json" %} @@ -601,9 +603,7 @@ export default App; ## Visualizing your Project Structure -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=1416" /%} - -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/core-features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/core-features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: @@ -680,8 +680,6 @@ Exercise for you: change the codebase such that `ui` is used by `orders` and `pr ## Imposing Constraints with Module Boundary Rules -{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=1456" /%} - Once you modularize your codebase you want to make sure that the modules are not coupled to each other in an uncontrolled way. Here are some examples of how we might want to guard our small demo workspace: - we might want to allow `orders` to import from `ui` but not the other way around @@ -838,7 +836,7 @@ If you have the ESLint plugin installed in your IDE you should immediately see a ![ESLint module boundary error](/shared/images/tutorial-react-standalone/react-standalone-module-boundaries.png) -Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries). +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Migrating to a Monorepo @@ -854,7 +852,7 @@ Here's some more things you can dive into next: - Learn how to [migrate your CRA app to Nx](/recipes/react/migration-cra) - [Learn how to setup Tailwind](/recipes/react/using-tailwind-css-in-react) - [Setup Storybook for our shared UI library](/recipes/storybook/overview-react) -- [Speed up CI: Run only tasks for project that got changed](/core-features/run-tasks#run-tasks-affected-by-a-pr)] +- [Speed up CI: Run only tasks for project that got changed](/features/run-tasks#run-tasks-affected-by-a-pr)] - [Speed up CI: Share your cache](/ci/features/remote-cache)] - [Speed up CI: Distribute your tasks across machines](/ci/features/distribute-task-execution) diff --git a/docs/shared/react-tutorial/react-monorepo.md b/docs/shared/react-tutorial/react-monorepo.md index b3f1be6e40016..35791c2bd2405 100644 --- a/docs/shared/react-tutorial/react-monorepo.md +++ b/docs/shared/react-tutorial/react-monorepo.md @@ -29,9 +29,8 @@ Nx Plugins are optional packages that extend the capabilities of Nx, catering to Features of an integrated monorepo: - [Install dependencies at the root by default](/concepts/more-concepts/dependency-management#single-version-policy) -- [Scaffold new code with generators](/core-features/plugin-features/use-code-generators) -- [Run tasks with executors](/core-features/plugin-features/use-task-executors) -- [Updates dependencies with automated migrations](/core-features/automate-updating-dependencies) +- [Scaffold new code with generators](/features/generate-code) +- [Updates dependencies with automated migrations](/features/automate-updating-dependencies) Visit our ["Why Nx" page](/getting-started/why-nx) for more details. @@ -123,64 +122,115 @@ Nx uses the following syntax to run tasks: ![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) -All targets, such as `serve`, `build`, `test` or your custom ones, are defined in the `project.json` file. +### Inferred Tasks -```json {% fileName="apps/react-store/project.json"} -{ - "name": "react-store", - ... - "targets": { - "serve": { ... }, - "build": { ... }, - "preview": { ... }, - "test": { ... }, - "lint": { ... }, - "serve-static": { ... }, - }, -} +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/features/integrate-with-editors) project detail view or run: + +```shell +nx show project react-store --web ``` -Each target contains a configuration object that tells Nx how to run that target. +{% project-details title="Project Details View (Simplified)" height="100px" %} -```json {% fileName="project.json"} +```json { - "name": "react-store", - ... - "targets": { - "serve": { - "executor": "@nx/vite:dev-server", - "defaultConfiguration": "development", - "options": { - "buildTarget": "react-store:build" - }, - "configurations": { - "development": { - "buildTarget": "react-store:build:development", - "hmr": true - }, - "production": { - "buildTarget": "react-store:build:production", - "hmr": false + "project": { + "name": "react-store", + "data": { + "root": "apps/react-store", + "includedScripts": [], + "name": "react-store", + "targets": { + "build": { + "options": { + "cwd": "apps/react-store", + "command": "vite build" + }, + "cache": true, + "dependsOn": ["^build"], + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["vite"] + } + ], + "outputs": ["{workspaceRoot}/dist/apps/react-store"], + "executor": "nx:run-commands", + "configurations": {} } - } - }, - ... + }, + "sourceRoot": "apps/react-store/src", + "projectType": "application", + "$schema": "node_modules/nx/schemas/project-schema.json", + "tags": [], + "implicitDependencies": [] + } }, + "sourceMap": { + "root": ["apps/react-store/project.json", "nx/core/project-json"], + "targets": ["apps/react-store/project.json", "nx/core/project-json"], + "targets.build": ["apps/react-store/vite.config.ts", "@nx/vite/plugin"], + "targets.build.command": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.cache": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.dependsOn": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.inputs": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.outputs": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options.cwd": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "name": ["apps/react-store/project.json", "nx/core/project-json"], + "$schema": ["apps/react-store/project.json", "nx/core/project-json"], + "sourceRoot": ["apps/react-store/project.json", "nx/core/project-json"], + "projectType": ["apps/react-store/project.json", "nx/core/project-json"], + "tags": ["apps/react-store/project.json", "nx/core/project-json"] + } } ``` -The most critical parts are: +{% /project-details %} -- `executor` - this is of the syntax `:`, where the `plugin` is an NPM package containing an [Nx Plugin](/extending-nx/intro/getting-started) and `` points to a function that runs the task. In this case, the `@nx/vite` plugin contains the `dev-server` executor which serves the React app using Vite. -- `options` - these are additional properties and flags passed to the executor function to customize it +If you expand the `build` task, you can see that it was created by the `@nx/vite` plugin by analyzing your `vite.config.ts` file. Notice the outputs are defined as `{workspaceRoot}/dist/apps/react-store`. This value is being read from the `build.outDir` defined in your `vite.config.ts` file. Let's change that value in your `vite.config.ts` file: -Learn more about how to [run tasks with Nx](/core-features/run-tasks). We'll [revisit running tasks](#testing-and-linting-running-multiple-tasks) later in this tutorial. +```ts {% fileName="apps/react-store/vite.config.ts" %} +export default defineConfig({ + // ... + build: { + outDir: './build/react-store', + // ... + }, +}); +``` + +Now if you look at the project details view, the outputs for the build target will say `{workspaceRoot}/build/react-store`. This feature ensures that Nx will always cache the correct files. + +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. ## Adding Another Application -Nx plugins usually provide [generators](/core-features/plugin-features/use-code-generators) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin provides, run the following command and inspect the output: +Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin provides, run the following command and inspect the output: ```{% command="npx nx list @nx/react" path="react-monorepo" %} @@ -204,6 +254,7 @@ Nx plugins usually provide [generators](/core-features/plugin-features/use-code- setup-ssr : Set up SSR configuration for a project. host : Generate a host react application remote : Generate a remote react application + federate-module : Federate a module. EXECUTORS/BUILDERS @@ -215,7 +266,7 @@ Nx plugins usually provide [generators](/core-features/plugin-features/use-code- If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. -More info can be found in [the integrate with editors article](/core-features/integrate-with-editors). +More info can be found in [the integrate with editors article](/features/integrate-with-editors). {% /callout %} @@ -226,7 +277,7 @@ Run the following command to generate a new `inventory` application. Note how we ✔ Would you like to add React Router to this application? (y/N) · false ✔ Which E2E test runner would you like to use? · cypress -A custom environment was provided: undefined. You need to install it manually. +✔ What should be the project name and where should it be generated? · inventory @ apps/inventory CREATE apps/inventory/index.html CREATE apps/inventory/public/favicon.ico CREATE apps/inventory/src/app/app.spec.tsx @@ -239,17 +290,17 @@ CREATE apps/inventory/src/app/app.tsx CREATE apps/inventory/src/styles.css CREATE apps/inventory/tsconfig.json CREATE apps/inventory/project.json -CREATE apps/inventory/vite.config.ts CREATE apps/inventory/tsconfig.spec.json +CREATE apps/inventory/vite.config.ts CREATE apps/inventory/.eslintrc.json -CREATE apps/inventory-e2e/cypress.config.ts +CREATE apps/inventory-e2e/project.json CREATE apps/inventory-e2e/src/e2e/app.cy.ts -CREATE apps/inventory-e2e/src/fixtures/example.json CREATE apps/inventory-e2e/src/support/app.po.ts -CREATE apps/inventory-e2e/src/support/commands.ts CREATE apps/inventory-e2e/src/support/e2e.ts +CREATE apps/inventory-e2e/src/fixtures/example.json +CREATE apps/inventory-e2e/src/support/commands.ts +CREATE apps/inventory-e2e/cypress.config.ts CREATE apps/inventory-e2e/tsconfig.json -CREATE apps/inventory-e2e/project.json CREATE apps/inventory-e2e/.eslintrc.json NOTE: The "dryRun" flag means no changes were made. @@ -349,7 +400,8 @@ Running the above commands should lead to the following directory structure: Each of these libraries -- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `nx test orders`) +- has a project details view where you can see the available tasks (e.g. running tests for just orders: `nx test orders`) +- has its own `project.json` file where you can customize targets - has the name you specified in the generate command; you can find the name in the corresponding `project.json` file - has a dedicated `index.ts` file which is the "public API" of the library - is mapped in the `tsconfig.base.json` at the root of the workspace @@ -377,7 +429,7 @@ All libraries that we generate automatically have aliases created in the root-le Hence we can easily import them into other libraries and our React application. As an example, let's create and expose a `ProductList` component from our `libs/products` library. Either create it by hand or run ```shell -nx g @nx/react:component product-list --project=products +nx g @nx/react:component product-list --project=products --directory="libs/products/src/lib/product-list" ``` We don't need to implement anything fancy as we just want to learn how to import it into our main React application. @@ -526,7 +578,7 @@ export default App; -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/core-features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/core-features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: @@ -647,7 +699,7 @@ nx run-many -t test ### Caching -One thing to highlight is that Nx is able to [cache the tasks you run](/core-features/cache-task-results). +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. @@ -665,7 +717,7 @@ Note that all of these targets are automatically cached by Nx. If you re-run a s Nx read the output from the cache instead of running the command for 10 out of 10 tasks. ``` -Not all tasks might be cacheable though. You can configure `cacheableOperations` in the `nx.json` file. You can also [learn more about how caching works](/core-features/cache-task-results). +Not all tasks might be cacheable though. You can configure the `cache` settings in the `targetDefaults` property of the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). ### Testing Affected Projects @@ -830,7 +882,7 @@ You can even create your own `deploy` task that sends the build output to your h { "targets": { "deploy": { - "dependsOn": "build", + "dependsOn": ["build"], "command": "netlify deploy --dir=dist/react-store" } } @@ -839,7 +891,7 @@ You can even create your own `deploy` task that sends the build output to your h Replace the `command` with whatever terminal command you use to deploy your site. -The `"dependsOn": "build"` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. +The `"dependsOn": ["build"]` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. With the `deploy` tasks defined, you can deploy a single application with `nx deploy react-store` or deploy any applications affected by the current changes with: @@ -1013,7 +1065,7 @@ If you have the ESLint plugin installed in your IDE you should immediately see a ![ESLint module boundary error](/shared/images/tutorial-react-standalone/react-standalone-module-boundaries.png) -Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries). +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Setting Up CI @@ -1047,7 +1099,7 @@ Here's some more things you can dive into next: - Learn how to [migrate your CRA app to Nx](/recipes/react/migration-cra) - [Learn how to setup Tailwind](/recipes/react/using-tailwind-css-in-react) - [Setup Storybook for our shared UI library](/recipes/storybook/overview-react) -- [Speed up CI: Run only tasks for project that got changed](/core-features/run-tasks#run-tasks-affected-by-a-pr) +- [Speed up CI: Run only tasks for project that got changed](/features/run-tasks#run-tasks-affected-by-a-pr) - [Speed up CI: Share your cache](/ci/features/remote-cache) - [Speed up CI: Distribute your tasks across machines](/ci/features/distribute-task-execution) diff --git a/docs/shared/recipes/add-stack/add-astro.md b/docs/shared/recipes/add-stack/add-astro.md index 748fef3315efe..1ab40255d4f89 100644 --- a/docs/shared/recipes/add-stack/add-astro.md +++ b/docs/shared/recipes/add-stack/add-astro.md @@ -8,17 +8,16 @@ The code for this example is available on GitHub: Because we are not using an Nx plugin for Astro, there are few items we'll have to configure manually. We'll have to configure our own build system. There are no pre-created Astro-specific code generators. And we'll have to take care of updating any framework dependencies as needed. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Remote Caching{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} {% pill url="/recipes/enforce-module-boundaries" %}✅ Enforce Project Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}🚫 Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}🚫 Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/generate-code" %}🚫 Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} ## Create an astro app @@ -38,7 +37,7 @@ We can leverage [`nx init`](/recipes/adopting-nx/adding-to-existing-project#inst ✔ Which of the following scripts are cacheable? (Produce the same output given the same input, e.g. build, test and lint usually are, serve and start are not). You can use spacebar to select one or more scripts. · build -✔ Does the "build" script create any outputs? If not, leave blank, otherwise provide a path (e.g. dist, lib, build, coverage) · dist + ✔ Would you like remote caching to make your build faster? · Yes > NX 📦 Installing dependencies @@ -49,7 +48,7 @@ We can leverage [`nx init`](/recipes/adopting-nx/adding-to-existing-project#inst - Learn more at https://nx.dev/recipes/adopting-nx/adding-to-existing-project. ``` -You can add a task as cacheable after the fact by updating the `cacheableOperations` in the `nx.json` file. Learn more about [caching task results](/recipes/adopting-nx/adding-to-existing-project#installing-nx-on-a-non-monorepo-project) or [how caching works](/core-features/cache-task-results). +You can add a task as cacheable after the fact by updating the `cacheableOperations` in the `nx.json` file. Learn more about [caching task results](/recipes/adopting-nx/adding-to-existing-project#installing-nx-on-a-non-monorepo-project) or [how caching works](/features/cache-task-results). ## Running Tasks @@ -83,48 +82,29 @@ Install `@nx/js` plugin. > Note: you should make sure any first party, `@nx/` scoped, plugins match the `nx` package version -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -DE @nx/js@ -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -DE @nx/js@ +nx add @nx/js@ ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -DE @nx/js@ -``` - -{% /tab %} -{% /tabs %} - Then generate a project {% callout type="note" title="Directory Flag Behavior Changes" %} The command below uses the `as-provided` directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the `derived` option, omit the `--directory` flag. See the [as-provided vs. derived documentation](/deprecated/as-provided-vs-derived) for more details. {% /callout %} -```{% command="nx g @nx/js:lib ui --directory=libs/ui --simpleName --minimal"%} +```{% command="nx g @nx/js:lib ui --directory=libs/ui --simpleName --minimal" path="~/astro-app"} > NX Generating @nx/js:library ✔ Which unit test runner would you like to use? · none ✔ Which bundler would you like to use to build the library? Choose 'none' to skip build setup. · none -CREATE ui/tsconfig.json -CREATE ui/src/index.ts -CREATE ui/src/lib/ui.ts -CREATE ui/tsconfig.lib.json -CREATE ui/project.json -CREATE ui/.eslintrc.json +CREATE libs/ui/tsconfig.json +CREATE libs/ui/README.md +CREATE libs/ui/src/index.ts +CREATE libs/ui/src/lib/ui.ts +CREATE libs/ui/tsconfig.lib.json +CREATE libs/ui/project.json +CREATE libs/ui/.eslintrc.json UPDATE tsconfig.json ``` diff --git a/docs/shared/recipes/add-stack/add-deno.md b/docs/shared/recipes/add-stack/add-deno.md index 663831739e5aa..51534e00f6f40 100644 --- a/docs/shared/recipes/add-stack/add-deno.md +++ b/docs/shared/recipes/add-stack/add-deno.md @@ -4,17 +4,16 @@ Because we are using an Nx plugin for Deno, all the features of Nx are available. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Install the Deno Plugin @@ -22,30 +21,10 @@ Because we are using an Nx plugin for Deno, all the features of Nx are available Make sure you have Deno installed on your machine. Consult the [Deno docs for more details](https://deno.com/manual/getting_started/installation) {% /callout %} -{% tabs %} -{%tab label="npm"%} - -```shell -npm add -D @nx/deno -``` - -{% /tab %} -{%tab label="yarn"%} - ```shell -yarn add -D @nx/deno +nx add @nx/deno ``` -{% /tab %} -{%tab label="pnpm"%} - -```shell -pnpm add -D @nx/deno -``` - -{% /tab %} -{% /tabs %} - ## Create an Application {% callout type="note" title="Directory Flag Behavior Changes" %} diff --git a/docs/shared/recipes/add-stack/add-dotnet.md b/docs/shared/recipes/add-stack/add-dotnet.md index 28d98665f8d1b..4008281d1529d 100644 --- a/docs/shared/recipes/add-stack/add-dotnet.md +++ b/docs/shared/recipes/add-stack/add-dotnet.md @@ -4,17 +4,16 @@ Because we are using an Nx plugin for .NET, all the features of Nx are available. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Install the @nx-dotnet/core Plugin diff --git a/docs/shared/recipes/add-stack/add-express.md b/docs/shared/recipes/add-stack/add-express.md index 373d1d213ce9e..514c990b79398 100644 --- a/docs/shared/recipes/add-stack/add-express.md +++ b/docs/shared/recipes/add-stack/add-express.md @@ -4,17 +4,16 @@ Because we are using an Nx plugin for Express, all the features of Nx are available. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Install the Express Plugin @@ -22,30 +21,10 @@ Because we are using an Nx plugin for Express, all the features of Nx are availa Make sure to install the `@nx/express` version that matches the version of `nx` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -{% tabs %} -{%tab label="npm"%} - -```shell -npm add -D @nx/express -``` - -{% /tab %} -{%tab label="yarn"%} - ```shell -yarn add -D @nx/express +nx add @nx/express ``` -{% /tab %} -{%tab label="pnpm"%} - -```shell -pnpm add -D @nx/express -``` - -{% /tab %} -{% /tabs %} - ## Create an Application Use the `app` generator to create a new Express app. diff --git a/docs/shared/recipes/add-stack/add-fastify.md b/docs/shared/recipes/add-stack/add-fastify.md index e4d9faf4e2f22..44d77ad8efe3a 100644 --- a/docs/shared/recipes/add-stack/add-fastify.md +++ b/docs/shared/recipes/add-stack/add-fastify.md @@ -9,17 +9,16 @@ width="100%" /%} Because we are using an Nx plugin for Fastify, all the features of Nx are available. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Create a New Workspace with a Fastify App @@ -35,30 +34,10 @@ If you are adding Fastify to an existing repo, continue to the next section. ## Install the Node Plugin -{% tabs %} -{%tab label="npm"%} - -```shell -npm add -D @nx/node -``` - -{% /tab %} -{%tab label="yarn"%} - ```shell -yarn add -D @nx/node +nx add @nx/node ``` -{% /tab %} -{%tab label="pnpm"%} - -```shell -pnpm add -D @nx/node -``` - -{% /tab %} -{% /tabs %} - ## Create an Application Use the `app` generator to create a new Fastify app. diff --git a/docs/shared/recipes/add-stack/add-lit.md b/docs/shared/recipes/add-stack/add-lit.md index 9b2d9ca8f4614..d36eb3ae1d3bb 100644 --- a/docs/shared/recipes/add-stack/add-lit.md +++ b/docs/shared/recipes/add-stack/add-lit.md @@ -8,17 +8,16 @@ The code for this example is available on GitHub: Because we are not using an Nx plugin for Lit, there are few items we'll have to configure manually. We'll have to configure our own build system. There are no pre-created Lit-specific code generators. And we'll have to take care of updating any framework dependencies as needed. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}🚫 Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}🚫 Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}🚫 Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} ## Install Lit and Other Dependencies @@ -28,21 +27,24 @@ Install all the dependencies we need: {%tab label="npm"%} ```shell -npm add -D @nx/node lit http-server +nx add @nx/node +npm add -D lit http-server ``` {% /tab %} {%tab label="yarn"%} ```shell -yarn add -D @nx/node lit http-server +nx add @nx/node +yarn add -D lit http-server ``` {% /tab %} {%tab label="pnpm"%} ```shell -pnpm add -D @nx/node lit http-server +nx add @nx/node +pnpm add -D lit http-server ``` {% /tab %} diff --git a/docs/shared/recipes/add-stack/add-qwik.md b/docs/shared/recipes/add-stack/add-qwik.md index 05f8d4ccc31a6..eaa6943b2b9f0 100644 --- a/docs/shared/recipes/add-stack/add-qwik.md +++ b/docs/shared/recipes/add-stack/add-qwik.md @@ -8,17 +8,16 @@ The code for this example is available on GitHub: We'll be using an Nx Plugin for Qwik called [qwik-nx](https://github.com/qwikifiers/qwik-nx). -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Install the qwik-nx Plugin diff --git a/docs/shared/recipes/add-stack/add-rust.md b/docs/shared/recipes/add-stack/add-rust.md index c7c3677b25d68..25d411e8d2147 100644 --- a/docs/shared/recipes/add-stack/add-rust.md +++ b/docs/shared/recipes/add-stack/add-rust.md @@ -9,17 +9,16 @@ The code for this example is available on GitHub: We'll be using an Nx Plugin for Rust called [@monodon/rust](https://github.com/cammisuli/monodon/tree/main/packages/rust). -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}✅ Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}✅ Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}✅ Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Framework Dependencies{% /pill %} ## Create the workspace with the `@monodon/rust` preset diff --git a/docs/shared/recipes/add-stack/add-solid.md b/docs/shared/recipes/add-stack/add-solid.md index 8dd12323fb1b2..a0a94dfc3fd20 100644 --- a/docs/shared/recipes/add-stack/add-solid.md +++ b/docs/shared/recipes/add-stack/add-solid.md @@ -10,17 +10,16 @@ Because we are not using an Nx plugin for Solid, there are a few items we'll hav configure our own build system. There are no pre-created Solid-specific code generators. And we'll have to take care of updating any framework dependencies as needed. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}🚫 Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}🚫 Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}🚫 Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} ## Install Solid and Other Dependencies @@ -29,7 +28,8 @@ updating any framework dependencies as needed. ```shell npm add solid-js -npm add -D @nx/web solid-devtools vite-plugin-solid +npm add -D solid-devtools vite-plugin-solid +nx add @nx/web ``` {% /tab %} @@ -37,7 +37,8 @@ npm add -D @nx/web solid-devtools vite-plugin-solid ```shell yarn add solid-js -yarn add -D @nx/web solid-devtools vite-plugin-solid +yarn add -D solid-devtools vite-plugin-solid +nx add @nx/web ``` {% /tab %} @@ -45,7 +46,8 @@ yarn add -D @nx/web solid-devtools vite-plugin-solid ```shell pnpm add solid-js -pnpm add -D @nx/web solid-devtools vite-plugin-solid +pnpm add -D solid-devtools vite-plugin-solid +nx add @nx/web ``` {% /tab %} diff --git a/docs/shared/recipes/add-stack/add-svelte.md b/docs/shared/recipes/add-stack/add-svelte.md index 07df761c6710c..3293acd9c4bdb 100644 --- a/docs/shared/recipes/add-stack/add-svelte.md +++ b/docs/shared/recipes/add-stack/add-svelte.md @@ -8,17 +8,16 @@ The code for this example is available on GitHub: Because we are not using a Nx plugin for Svelte, there are a few items we'll have to configure manually. We'll have to configure our own build system. There are no pre-created Svelte-specific code generators. And we'll have to take care of updating any framework dependencies as needed. -{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} -{% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} +{% pill url="/features/run-tasks" %}✅ Run Tasks{% /pill %} +{% pill url="/features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/ci/features/remote-cache" %}✅ Share Your Cache{% /pill %} -{% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} +{% pill url="/features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/ci/features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} -{% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} -{% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} -{% pill url="/core-features/plugin-features/use-task-executors" %}🚫 Use Task Executors{% /pill %} -{% pill url="/core-features/plugin-features/use-code-generators" %}🚫 Use Code Generators{% /pill %} -{% pill url="/core-features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} +{% pill url="/features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} +{% pill url="/features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} +{% pill url="/features/generate-code" %}🚫 Use Code Generators{% /pill %} +{% pill url="/features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %} ## Setup workspace @@ -58,21 +57,24 @@ Make sure to install the `@nx/vite` and `@nx/js` versions that matches the versi {%tab label="npm"%} ```shell -npm add -D @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +npm add -D vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +nx add @nx/vite @nx/js ``` {% /tab %} {%tab label="yarn"%} ```shell -yarn add -D @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +yarn add -D vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +nx add @nx/vite @nx/js ``` {% /tab %} {%tab label="pnpm"%} ```shell -pnpm add -D @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +pnpm add -D vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte +nx add @nx/vite @nx/js ``` {% /tab %} @@ -181,45 +183,29 @@ Change your `tsconfig.lib.json` to `tsconfig.app.json`. It should look like this } ``` -Navigate to `project.json` and update it with the following content: +Navigate to `nx.json` it should contain the following: ```json {% fileName="/project.json" %} { - "targets": { - "build": { - "executor": "@nx/vite:build", - "outputs": ["{options.outputPath}"], - "defaultConfiguration": "production", + // ... other config + "plugins": [ + { + "plugin": "@nx/eslint/plugin", "options": { - "outputPath": "dist/acme" - }, - "configurations": { - "development": { - "mode": "development" - }, - "production": { - "mode": "production" - } + "targetName": "lint" } }, - "serve": { - "executor": "@nx/vite:dev-server", - "defaultConfiguration": "development", + { + "plugin": "@nx/vite/plugin", "options": { - "buildTarget": "acme:build" - }, - "configurations": { - "development": { - "buildTarget": "acme:build:development", - "hmr": true - }, - "production": { - "buildTarget": "acme:build:production", - "hmr": false - } + "buildTargetName": "build", + "previewTargetName": "preview", + "testTargetName": "test", + "serveTargetName": "serve", + "serveStaticTargetName": "serve-static" } } - } + ] } ``` diff --git a/docs/shared/recipes/advanced-update.md b/docs/shared/recipes/advanced-update.md index 8c27af28c992c..47084cdfac298 100644 --- a/docs/shared/recipes/advanced-update.md +++ b/docs/shared/recipes/advanced-update.md @@ -1,10 +1,10 @@ # Advanced update process -This guide describes advanced scenarios when it comes to updating Nx and the workspaces dependencies. It starts with a summary of the [standard update process](/core-features/automate-updating-dependencies) and continues with those advanced use cases. +This guide describes advanced scenarios when it comes to updating Nx and the workspaces dependencies. It starts with a summary of the [standard update process](/features/automate-updating-dependencies) and continues with those advanced use cases. ## Updating to the latest Nx version -The following steps are a summary of the [standard update process](/core-features/automate-updating-dependencies). For more information on each step, please visit that page. +The following steps are a summary of the [standard update process](/features/automate-updating-dependencies). For more information on each step, please visit that page. ### Step 1: Updating dependencies and generating migrations diff --git a/docs/shared/recipes/console-project-details.md b/docs/shared/recipes/console-project-details.md new file mode 100644 index 0000000000000..385fa8b900639 --- /dev/null +++ b/docs/shared/recipes/console-project-details.md @@ -0,0 +1,12 @@ +# Nx Console Project Details View + +Nx Console provides seamless integration with the [Project Details View](features/explore-graph#explore-projects-in-your-workspace). +You can learn more about your project, run tasks or navigate the task graph with just a few clicks! + +![console-pdv-example.png](/shared/images/nx-console/console-pdv-example.png) + +You can access the integrated Project Details View in multiple ways: + +- By clicking on the Preview icon to the top right of your `project.json`, `package.json` or any file that modifies targets (for example `jest.config.ts` or `cypress.config.ts`) +- By using the codelenses in any of these files +- By running the `Nx: Open Project Details to Side` action while any file in a project is open diff --git a/docs/shared/recipes/deployment/deno-deploy.md b/docs/shared/recipes/deployment/deno-deploy.md index e21cac019bebd..b175cb9718d55 100644 --- a/docs/shared/recipes/deployment/deno-deploy.md +++ b/docs/shared/recipes/deployment/deno-deploy.md @@ -18,30 +18,10 @@ This creates a single Deno application. You can also add a new Deno application to an existing Nx monorepo workspace. Make sure you have the `@nx/deno` package installed: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/deno -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/deno +nx add @nx/deno ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/deno -``` - -{% /tab %} -{% /tabs %} - {% callout type="note" title="Directory Flag Behavior Changes" %} The command below uses the `as-provided` directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the `derived` option, omit the `--directory` flag. See the [as-provided vs. derived documentation](/deprecated/as-provided-vs-derived) for more details. {% /callout %} diff --git a/docs/shared/recipes/deployment/deno-netlify-edge-functions.md b/docs/shared/recipes/deployment/deno-netlify-edge-functions.md index 4a25740da9f38..5ac3a976c525f 100644 --- a/docs/shared/recipes/deployment/deno-netlify-edge-functions.md +++ b/docs/shared/recipes/deployment/deno-netlify-edge-functions.md @@ -16,30 +16,10 @@ This creates a single Deno application. You can also add a new Deno application to an existing Nx monorepo workspace. Make sure you have the `@nx/deno` package installed: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/deno -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/deno +nx add @nx/deno ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/deno -``` - -{% /tab %} -{% /tabs %} - {% callout type="note" title="Directory Flag Behavior Changes" %} The command below uses the `as-provided` directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the `derived` option, omit the `--directory` flag. See the [as-provided vs. derived documentation](/deprecated/as-provided-vs-derived) for more details. {% /callout %} diff --git a/docs/shared/recipes/deployment/node-aws-lambda.md b/docs/shared/recipes/deployment/node-aws-lambda.md index 7b29fb60c63ea..45acaa327aa8e 100644 --- a/docs/shared/recipes/deployment/node-aws-lambda.md +++ b/docs/shared/recipes/deployment/node-aws-lambda.md @@ -21,30 +21,10 @@ npx create-nx-workspace@latest my-functions --preset=@nx/aws-lambda First, make sure you have `@nx/aws-lambda` installed. -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/aws-lambda -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/aws-lambda +nx add @nx/aws-lambda ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/aws-lambda -``` - -{% /tab %} -{% /tabs %} - Next, use the corresponding Nx generator to add the AWS Lambda configuration to an existing project: ```shell diff --git a/docs/shared/recipes/deployment/node-serverless-functions-netlify.md b/docs/shared/recipes/deployment/node-serverless-functions-netlify.md index 532d3821888c5..5bb1b5d6e8cb9 100644 --- a/docs/shared/recipes/deployment/node-serverless-functions-netlify.md +++ b/docs/shared/recipes/deployment/node-serverless-functions-netlify.md @@ -23,30 +23,10 @@ npx create-nx-workspace@latest my-functions --preset=@nx/netlify --site=my-site You will need to install `@nx/netlify` if you haven't already. -{% tabs %} -{% tab label="npm" %} - -```shell -npm add -D @nx/netlify -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add -D @nx/netlify +nx add @nx/netlify ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add -D @nx/netlify -``` - -{% /tab %} -{% /tabs %} - Next add the Netlify serverless configuration by running the following command: ```shell diff --git a/docs/shared/recipes/generators/local-generators.md b/docs/shared/recipes/generators/local-generators.md index 6626fa50abfa0..c6fcf389e6367 100644 --- a/docs/shared/recipes/generators/local-generators.md +++ b/docs/shared/recipes/generators/local-generators.md @@ -14,33 +14,11 @@ caption="Demoes how to use Nx generators in a PNPM workspace to automate the cre If you don't already have a local plugin, use Nx to generate one: -{% tabs %} -{% tab label="npm" %} - -```shell -npm add @nx/plugin@latest -nx g @nx/plugin:plugin my-plugin -``` - -{% /tab %} -{% tab label="yarn" %} - ```shell -yarn add @nx/plugin@latest +nx add @nx/plugin nx g @nx/plugin:plugin my-plugin ``` -{% /tab %} -{% tab label="pnpm" %} - -```shell -pnpm add @nx/plugin@latest -nx g @nx/plugin:plugin my-plugin -``` - -{% /tab %} -{% /tabs %} - Note that `latest` should match the version of the `nx` plugins installed in your workspace. Use the Nx CLI to generate the initial files needed for your generator. diff --git a/docs/shared/recipes/module-federation-with-ssr.md b/docs/shared/recipes/module-federation-with-ssr.md index 4665055f4f9b0..5815b77238f3c 100644 --- a/docs/shared/recipes/module-federation-with-ssr.md +++ b/docs/shared/recipes/module-federation-with-ssr.md @@ -30,7 +30,7 @@ Make sure to install the `@nx/angular` or `@nx/react` versions that matches the {% tab label="Angular" %} -```{% command="npm add -D @nx/angular" path="~/myorg" %} +```{% command="nx add @nx/angular" path="~/myorg" %} ``` @@ -38,7 +38,7 @@ Make sure to install the `@nx/angular` or `@nx/react` versions that matches the {% tab label="React" %} -```{% command="npm add -D @nx/react" path="~/myorg" %} +```{% command="nx add @nx/react" path="~/myorg" %} ``` diff --git a/docs/shared/recipes/nx-release/get-started-with-nx-release.md b/docs/shared/recipes/nx-release/get-started-with-nx-release.md index 6e931196b1fb6..a7ff1174c3394 100644 --- a/docs/shared/recipes/nx-release/get-started-with-nx-release.md +++ b/docs/shared/recipes/nx-release/get-started-with-nx-release.md @@ -18,7 +18,7 @@ nx add @nx/js ### Configure Projects to Release -Nx Release uses Nx's powerful [Project Graph](/core-features/explore-graph) to understand your projects and their dependencies. +Nx Release uses Nx's powerful [Project Graph](/features/explore-graph) to understand your projects and their dependencies. If you want to release all of the projects in your workspace, such as when dealing with a series of npm library packages, no configuration is required. diff --git a/docs/shared/recipes/plugins/create-preset.md b/docs/shared/recipes/plugins/create-preset.md index a88bb579367b1..e1bb9c7a60c60 100644 --- a/docs/shared/recipes/plugins/create-preset.md +++ b/docs/shared/recipes/plugins/create-preset.md @@ -11,7 +11,7 @@ title="Develop a Nx Preset for your Nx Plugin" ## What is a preset? -At its core, a preset is a special [generator](/core-features/plugin-features/use-code-generators) that is shipped as part of an Nx Plugin package. +At its core, a preset is a special [generator](/features/generate-code) that is shipped as part of an Nx Plugin package. All first-party Nx presets are built into Nx itself, but you can [create your own plugin](/extending-nx/intro/getting-started) and create a generator with the magic name: `preset`. Once you've [published your plugin](/extending-nx/tutorials/publish-plugin) on npm, you can now run the `create-nx-workspace` command with the preset option set to the name of your published package. diff --git a/docs/shared/recipes/plugins/local-executors.md b/docs/shared/recipes/plugins/local-executors.md index 2ae29cdf6ba86..f3a1043a2a369 100644 --- a/docs/shared/recipes/plugins/local-executors.md +++ b/docs/shared/recipes/plugins/local-executors.md @@ -1,6 +1,6 @@ # Local Executors -Creating Executors for your workspace standardizes scripts that are run during your development/building/deploying tasks in order to provide guidance in the terminal with `--help` and when invoking with [Nx Console](/core-features/integrate-with-editors) +Creating Executors for your workspace standardizes scripts that are run during your development/building/deploying tasks in order to provide guidance in the terminal with `--help` and when invoking with [Nx Console](/features/integrate-with-editors) This guide shows you how to create, run, and customize executors within your Nx workspace. The examples use the trivial use-case of an `echo` command. @@ -9,8 +9,7 @@ This guide shows you how to create, run, and customize executors within your Nx If you don't already have a local plugin, use Nx to generate one: ```shell -# replace `latest` with the version that matches your Nx version -npm install @nx/plugin@latest +nx add @nx/plugin nx g @nx/plugin:plugin my-plugin ``` diff --git a/docs/shared/recipes/plugins/project-graph-plugins.md b/docs/shared/recipes/plugins/project-graph-plugins.md index 214814c659026..1851a25e271ed 100644 --- a/docs/shared/recipes/plugins/project-graph-plugins.md +++ b/docs/shared/recipes/plugins/project-graph-plugins.md @@ -256,7 +256,7 @@ This functionality is available in Nx 17 or higher. ## Visualizing the Project Graph -You can then visualize the project graph as described [here](/core-features/explore-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`. +You can then visualize the project graph as described [here](/features/explore-graph). However, there is a cache that Nx uses to avoid recalculating the project graph as much as possible. As you develop your project graph plugin, it might be a good idea to set the following environment variable to disable the project graph cache: `NX_CACHE_PROJECT_GRAPH=false`. It might also be a good idea to ensure that the dep graph is not running on the nx daemon by setting `NX_DAEMON=false`, as this will ensure you will be able to see any `console.log` statements you add as you're developing. diff --git a/docs/shared/recipes/repo-types/integrated-in-package-based.md b/docs/shared/recipes/repo-types/integrated-in-package-based.md index d868eca84f309..046cf9a1e7d60 100644 --- a/docs/shared/recipes/repo-types/integrated-in-package-based.md +++ b/docs/shared/recipes/repo-types/integrated-in-package-based.md @@ -11,7 +11,7 @@ The integrated project is now ready to use. Next, we'll discuss some of the chan ## package.json dependencies -All the dependencies that are required for an integrated project are maintained in the root `package.json` file. In order to use the plugin's [Automate Updating Framework Dependencies](/core-features/automate-updating-dependencies) feature, we recommend using a [Single Version Policy](/concepts/more-concepts/dependency-management#single-version-policy) for integrated projects. +All the dependencies that are required for an integrated project are maintained in the root `package.json` file. In order to use the plugin's [Automate Updating Framework Dependencies](/features/automate-updating-dependencies) feature, we recommend using a [Single Version Policy](/concepts/more-concepts/dependency-management#single-version-policy) for integrated projects. ## tsconfig.base.json @@ -19,7 +19,7 @@ Even if the project you added only uses javascript, a `tsconfig.base.json` file ## project.json -The project itself will have a `project.json` file that defines all the tasks that can be run on the project. This includes tasks like `build`, `serve` and `test`. See [Use Task Executors](/core-features/plugin-features/use-task-executors) for more information. +The project itself will have a `project.json` file that defines all the tasks that can be run on the project. This includes tasks like `build`, `serve` and `test`. See [Executors and Configurations](/concepts/executors-and-configurations) for more information. ## Other Configuration Files @@ -27,7 +27,7 @@ Depending on the type of integrated project you created, there may be other conf ## Code Generators -The Nx plugin you installed provides code generators that you can use to scaffold out your application quickly and in a consistent way. See [Use Code Generators](/core-features/plugin-features/use-code-generators) for more information. +The Nx plugin you installed provides code generators that you can use to scaffold out your application quickly and in a consistent way. See [Use Code Generators](/features/generate-code) for more information. ## Summary diff --git a/docs/shared/recipes/running-tasks/configure-inputs.md b/docs/shared/recipes/running-tasks/configure-inputs.md new file mode 100644 index 0000000000000..2e59a1de2ac75 --- /dev/null +++ b/docs/shared/recipes/running-tasks/configure-inputs.md @@ -0,0 +1,222 @@ +--- +title: Configure Inputs for Task Caching +description: 'Learn how to optimize when Nx restores from the cache by customizing what should be taken into consideration when calculating computation hashes for tasks' +--- + +# Configure Inputs for Task Caching + +When Nx [computes the hash for a given operation](/concepts/how-caching-works), it takes into account the `inputs` of the target. +The `inputs` are a list of **file sets**, **runtime** inputs and **environment variables** that affect the output of the target. +If any of the `inputs` change, the cache is invalidated and the target is re-run. + +Nx errs on the side of caution when using inputs. Ideally, the "perfect" configuration of inputs will allow Nx to never re-run something when it does not need to. In practice though, it is better to play it safe and include more than strictly necessary in the inputs of a task. Forgetting to consider something during computation hash calculation may lead to negative consequences for end users. Start safe and fine-tune your inputs when there are clear opportunities to improve the cache hit rate. + +For an overview of all the possible [types of inputs](/reference/inputs) and how to reuse sets of inputs as [named inputs](/reference/inputs#named-inputs), see the reference documentation. + +Throughout this recipe, the following project structure of a simple workspace will be used as an example to help understand inputs better. + +{% graph height="450px" %} + +```json +{ + "projects": [ + { + "name": "myreactapp", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "shared-ui", + "type": "lib", + "data": { + "tags": [] + } + } + ], + "dependencies": { + "myreactapp": [ + { "source": "myreactapp", "target": "shared-ui", "type": "static" } + ], + "shared-ui": [] + }, + "workspaceLayout": { "appsDir": "", "libsDir": "" }, + "affectedProjectIds": [], + "focus": null, + "groupByFolder": false +} +``` + +{% /graph %} + +## View the Inputs of a Task + +You can view the configuration for a task of a project by adding the `--graph` flag when running the command: + +```shell +nx build myreactapp --graph +``` + +This will show the task graph executed by Nx when running the command. + +Clicking the task will open a tooltip which lists out all of the inputs of the task. A button within the tooltip will also reveal more details about the configuration for the project which the task belongs to. + +[//]: # 'TODO: add gif here' + +Doing so will show a view such as the one below: + +{% project-details jsonFile="shared/concepts/myreactapp.json"%} +{% /project-details %} + +Nx Console has a button which will show a preview of this screen when a project level configuration file (`project.json` or `package.json`) is opened in the IDE. + +Another way of accessing this information is to run `nx show project myreactapp --web` and the view above will be opened in a browser. + +Use this tool to help understand what inputs are being used by Nx in your workspace. + +{% callout title="Note" type="info" %} +If no `inputs` are specified at all, Nx will default to looking at all files of a project and its dependencies. This is a rather cautious approach. This might cause Nx to re-run a task in some cases where the cache could have been used instead but it will always give you correct output. +{% /callout %} + +## Configure Inputs + +The tasks you run in your workspace will likely already have `inputs` defined. +Be sure to [view the existing inputs](#viewing-the-inputs-of-a-task) and start from there. + +Inputs of a task are configured in the `inputs` array on the target. This can be done in several different places: + +- As of Nx 18, Nx Plugins often [infer inputs for tasks](/concepts/inferred-tasks) which run other tools. + - In doing so, they will also define some reasonable defaults for the `inputs` of those tasks. +- The `inputs` array in the `targetDefaults` for a set of targets in `nx.json`. +- The `inputs` array for a specific target in the project configuration file. + +{% callout title="Copy the existing inputs before modifying inputs for a task" %} +To override the `inputs` of a task, start by copying over the entire array shown when [viewing the project details](#viewing-the-inputs-of-a-task) and then add/modify/remove inputs as needed. +{% /callout %} + +As you configure `inputs`, keep the project details screen open and it will refresh as changes are made. Check to make sure that the intended configuration is shown. + +### Workspace Level Inputs + +[Target Defaults](/reference/nx-json#target-defaults) defined in `nx.json` apply to a set of targets. Defining `inputs` here one time will apply to a set of similar targets. + +```jsonc {% fileName="nx.json" highlightLines=[4] %} +{ + "targetDefaults": { + "build": { + "inputs": ["production", "^production"] + } + } +} +``` + +The above specifies that all targets with the name `build` will use the `inputs` specified. +This configuration will override any `inputs` inferred by Nx Plugins as you have more direct control in your `nx.json` than the behavior of the Nx Plugin. +The configuration defined here completely overwrites any `inputs` inferred by Nx Plugins and is not merged in any way. +This configuration may be overridden by configuration in project-specific configuration files. + +### Project Level Inputs + +Defining `inputs` of a target in `project.json` or `package.json` will apply only to tasks of the specific project. + +{% tabs %} +{% tab label="project.json" %} + +```jsonc {% fileName="apps/myreactapp/project.json" highlightLines=[5] %} +{ + "name": "myreactapp", + "targets": { + "build": { + "inputs": ["production", "^production"] + } + } +} +``` + +{% /tab %} +{% tab label="package.json" %} + +```jsonc {% fileName="apps/myreactapp/package.json" highlightLines=[9] %} +{ + "name": "myreactapp", + "dependencies": {}, + "devDependencies": {}, + ... + "nx": { + "targets": { + "build": { + "inputs": ["production", "^production"] + } + ... + } + } +} +``` + +{% /tab %} +{% /tabs %} + +The above specifies that the `build` target of the `myreactapp` project will use the `inputs` specified. +This configuration will override any `inputs` inferred by Nx Plugins as well as any `inputs` defined in the [Target Defaults](/reference/nx-json#target-defaults) in the `nx.json` file as this is more specific than those other methods of configuring `inputs`. +The configuration defined here completely overwrites any `inputs` inferred by Nx Plugins or in target defaults and is not merged in any way. + +## Common Inputs + +### Test and Config Files + +Often, projects include some files with runtime behavior and other files for unit testing. When running the `build` task, we do not want Nx to consider test files so updating the test files does not invalidate the cache for `build` tasks. + +Plugins which define compile or bundling tasks such as `@nx/webpack/plugin` and `@nx/vite/plugin` will use the following inputs: + +```jsonc +"inputs": [ + "production", // All files in a project including test files + "^production" // Inputs of a dependencies which may affect behavior of projects which depend on them +] +``` + +Plugins which define testing tasks such as `@nx/cypress/plugin`, `@nx/playwright/plugin`, `@nx/jest/plugin` and `@nx/vite/plugin` will infer the following inputs for tasks: + +```jsonc +"inputs": [ + "default", // All files in a project including test files + "^production" // Inputs of a dependencies which may affect behavior of projects which depend on them +] +``` + +Given the above configurations, exclude the test and config files from the `production` named input: + +```jsonc {% fileName="nx.json" highlightLines=["4-8"] %} +{ + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], + "production": [ + "default", + "!{projectRoot}/jest.config.ts", + "!{projectRoot}/**/?(*.)+(spec|test).ts" + ] + } +} +``` + +With the above named inputs, Nx will behave in the following way: + +- When only test files are changed, Nx will restore previous compilation results from the cache and re-run the tests for the projects containing the test files +- When any production files are changed, Nx will re-run the tests for the project as well as any projects which depend on it + +### Consider the Version of a Language for all Tasks + +Many times, the version of the programming language being used will affect the behavior of all tasks for the workspace. +A runtime input can be added to the `sharedGlobals` named input to consider it for the hash of every task. + +For example, to consider the version of Node.js in the hash of every task, add `node --version` as an input. + +```jsonc {% fileName="nx.json" highlightLines=["4"] %} +{ + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], + "sharedGlobals": [{ "runtime": "node --version" }] + } +} +``` diff --git a/docs/shared/recipes/running-tasks/configure-outputs.md b/docs/shared/recipes/running-tasks/configure-outputs.md new file mode 100644 index 0000000000000..04ed8021d54d3 --- /dev/null +++ b/docs/shared/recipes/running-tasks/configure-outputs.md @@ -0,0 +1,143 @@ +--- +title: Configure Outputs for Task Caching +description: 'Learn how to optimize what Nx restores from the cache' +--- + +# Configure Outputs for Task Caching + +Whenever Nx runs a cacheable task, it will store the results of that task in the cache. +When Nx runs the task again, if the [inputs for that task](/recipes/running-tasks/configure-inputs) have not changed, it will restore the results from the cache instead of spending the time to run the task again. + +## Types of Outputs + +### Terminal Output + +The terminal output of a task is replayed whenever a task is pulled from cache. Nx will always cache the terminal output of tasks which are cached. + +### Output Files + +Targets can define which files are produced when a task is run. Nx will cache these files so that it can restore them when the task is pulled from cache. + +These outputs files can be specified in several ways: + +```jsonc +"outputs": [ + "{projectRoot}/dist/libs/mylib", // A directory + "{workspaceRoot}/dist/{projectRoot}", // A directory based on the project's root + "{workspaceRoot}/dist/{projectName}", // A directory based on the project's name + "{workspaceRoot}/test-results.xml", // A file + "{projectRoot}/dist/libs/mylib/**/*.js", // A glob pattern matching a set of files + "{options.outputPath}", // A path defined in the options of a task +] +``` + +All outputs explicitly specifying paths must be prefixed with either `{projectRoot}` or `{workspaceRoot}` to distinguish where the path is resolved from. `{workspaceRoot}` should only appear in the beginning of an `output` but `{projectRoot}` and `{projectName}` can be specified later in the `output` to interpolate the root or name of the a project into the output location. + +Outputs can also be determined from the `options` of running a task via the `{options.[propertyName]}` syntax. +This is useful when an option for the task determines the output location and could be modified when the task is run. +This path is resolved from the root of the workspace. + +If an output file or directory does not exist, it will be ignored. + +## View Outputs of a Task + +The outputs of a task can be viewed by adding the `--graph` flag to the command: + +```shell +nx build myapp --graph +``` + +This will open the task graph in the browser. +Clicking on a task in the graph will open a tooltip with a link to see details about the project. +View the project's configuration to see a list of the outputs which are defined for each target. + +## Configure Outputs + +The tasks you run in your workspace will likely already have `outputs` defined. +Be sure to [view the existing outputs](#viewing-outputs-of-a-task) and start from there. + +As of Nx 18, Nx Plugins often [infer outputs for tasks](/concepts/inferred-tasks) which run other tools. +Nx Plugins will look at the configuration files and/or command-line-arguments of the tools in your workspace to understand the outputs of running those tools. +In most cases, this inference will be inline with the outputs of the tool. +Nx will reflect changes to the configuration or command-line arguments of your tools without any additional changes. + +In some cases, Nx plugins may not infer the outputs of a task as you expect, they can be configured in the `outputs` array on the target. This can be done in several different places: + +- The `outputs` array in the `targetDefaults` for a set of targets in `nx.json`. +- The `outputs` array for a specific target in the project configuration file. + +{% callout title="Copy the existing outputs before modifying outputs for a task" %} +To override the `outputs` of a task, start by copying over the entire array shown when [viewing the project details](#viewing-the-outputs-of-a-task) and then add/modify/remove outputs as needed. +{% /callout %} + +As you configure `outputs`, keep the project details screen open and it will refresh as changes are made. Check to make sure that the intended configuration is shown. + +### Workspace Level Outputs + +[Target Defaults](/reference/nx-json#target-defaults) defined in `nx.json` apply to a set of targets. Defining `outputs` here one time will apply to a set of similar targets. + +```jsonc {% fileName="nx.json" highlightLines=[4] %} +{ + "targetDefaults": { + "build": { + "outputs": ["{projectRoot}/dist"] + } + } +} +``` + +The above specifies Nx will cache the `dist` directory under all project roots for all targets with the name `build`. +This configuration will override any `outputs` inferred by Nx Plugins as you have more direct control in your `nx.json` than the behavior of the Nx Plugin. +The configuration defined here completely overwrites any `outputs` inferred by Nx Plugins and is not merged in any way. +This configuration may be overwritten by configuration in project-specific configuration files. + +{% callout title="Warning" type="warning" %} +Specifying the same output location for multiple tasks often causes unintentional behavior. While sometimes this is intentional, try and ensure that a set of targets will yield unique output locations for the tasks belonging to different projects. Use the `{projectRoot}` and `{projectName}` notation to include unique characteristics of a project in the output. +{% /callout %} + +### Project Level Outputs + +Defining `outputs` of a target in `project.json` or `package.json` will apply only to tasks of the specific project. + +{% tabs %} +{% tab label="project.json" %} + +```jsonc {% fileName="apps/myreactapp/project.json" highlightLines=[5] %} +{ + "name": "myreactapp", + "targets": { + "build": { + "outputs": ["{projectRoot}/dist"] + } + } +} +``` + +{% /tab %} +{% tab label="package.json" %} + +The `package.json` file may include configuration for a specific Nx project. Defining `outputs` of a target here will apply only to tasks of the specific project. + +```jsonc {% fileName="apps/myreactapp/package.json" highlightLines=[9] %} +{ + "name": "myreactapp", + "dependencies": {}, + "devDependencies": {}, + ... + "nx": { + "targets": { + "build": { + "outputs": ["{projectRoot}/dist"] + } + ... + } + } +} +``` + +{% /tab %} +{% /tabs %} + +The above specifies that the `build` target of the `myreactapp` project will use the `outputs` specified. +This configuration will override any `outputs` inferred by Nx Plugins as well as any `outputs` defined in the [Target Defaults](/reference/nx-json#target-defaults) in the `nx.json` file as this is more specific than those other methods of configuring `outputs`. +The configuration defined here completely overwrites any `outputs` inferred by Nx Plugins or in target defaults and is not merged in any way. diff --git a/docs/shared/recipes/running-tasks/customizing-inputs.md b/docs/shared/recipes/running-tasks/customizing-inputs.md deleted file mode 100644 index c88d5e6c5fcac..0000000000000 --- a/docs/shared/recipes/running-tasks/customizing-inputs.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -title: Fine-tuning Caching with Inputs -description: 'Learn how to optimize cache results by customizing what should be taken into account when invalidating the cache' ---- - -# Fine-tuning Caching with Inputs - -When Nx [computes the hash for a given operation](/concepts/how-caching-works), it takes into account the `inputs` of the target. The `inputs` are a list of **file sets**, **runtime** inputs and **environment variables** that affect the output of the target. If any of the `inputs` change, the cache is invalidated and the target is re-run. - -To understand some of the examples below, let's imagine the following simple workspace. - -{% graph height="450px" %} - -```json -{ - "projects": [ - { - "name": "myreactapp", - "type": "app", - "data": { - "tags": [] - } - }, - { - "name": "shared-ui", - "type": "lib", - "data": { - "tags": [] - } - } - ], - "dependencies": { - "myreactapp": [ - { "source": "myreactapp", "target": "shared-ui", "type": "static" } - ], - "shared-ui": [] - }, - "workspaceLayout": { "appsDir": "", "libsDir": "" }, - "affectedProjectIds": [], - "focus": null, - "groupByFolder": false -} -``` - -{% /graph %} - -## Global vs per-project inputs - -Tasks can have `inputs` defined for them [globally in the `nx.json` file](/reference/nx-json#inputs-&-namedinputs) or [on a per-project basis in the project configuration](/reference/project-configuration#inputs-&-namedinputs). - -{% tabs %} -{% tab label="Global" %} - -```json {% fileName="nx.json" highlightLines=[4] %} -{ - "targetDefaults": { - "build": { - "inputs": ["..."] - } - } -} -``` - -{% /tab %} -{% tab label="Project Level (project.json)" %} - -```json {% fileName="packages/some-project/project.json" highlightLines=[6] %} -{ - "name": "some-project", - ... - "targets": { - "build": { - "inputs": ["..."], - ... - } - ... - } -} -``` - -{% /tab %} - -{% tab label="Project Level (package.json)" %} - -```json {% fileName="packages/some-project/package.json" highlightLines=[9] %} -{ - "name": "some-project", - "dependencies": {}, - "devDependencies": {}, - ... - "nx": { - "targets": { - "build": { - "inputs": ["..."], - ... - } - ... - } - } -} -``` - -{% /tab %} - -## Include all project files and dependencies in cache hash - -The following definition includes all files of the project itself as well as all of its dependencies in the cache hash, hence telling Nx to invalidate the cache whenever - -- any file of the project itself changes -- any file of any dependency changes - -```jsonc {% fileName="nx.json" %} -{ - "namedInputs": { - "default": ["{projectRoot}/**/*"] - }, - "targetDefaults": { - "build": { - "inputs": ["default", "^default"] - } - } -} -``` - -This definition is the default behavior of Nx, even if you don't specify any `inputs` at all. This is a rather cautious approach. It will always give you correct output, but it might re-run a task in some cases where the cache could have been used instead. - -Note, Nx uses the [minimatch](https://github.com/isaacs/minimatch) library to process glob patterns. - -{% callout title="Replacements" %} - -Note how you can use `{projectRoot}` and `{workspaceRoot}` as placeholders to simplify writing glob definitions. - -{% /callout %} - -If you're wondering what `namedInputs` are, read the next section. - -## Reusing inputs definitions with namedInputs - -If you find yourself reusing the same `inputs` definitions, you can instead create a `namedInput`. It is like a variable definition which can then be reused in the `inputs` array. - -```jsonc {% fileName="nx.json" highlightLines=[3, 7] %} -{ - "namedInputs": { - "default": ["{projectRoot}/**/*"] - }, - "targetDefaults": { - "build": { - "inputs": ["default", "^default"] - } - } -} -``` - -The `^` character at the beginning of the `^default` string means this entry applies to the project dependencies of the project, not the project itself. In our example `myreactapp` depends on `shared-ui`, so if we run - -```shell -nx build myreactapp -``` - -...then because we defined - -- `"inputs": ["default",...]` - it will invalidate the cache of `myreactapp` whenever some src file of `myreactapp` itself changes -- `"inputs": [..., "^default"]` - it will in addition invalidate the cache of `myreactapp` whenever a file of `shared-ui` (or any of its dependencies) changes - -## Exclude files from invalidating cache - -Sometimes you might want to exclude specific project files so that they don't invalidate the cache for a given target. For example, we want spec/test files to invalidate the `test` target (by explicitly including `*.spec.ts` files), but we might want to optimize and exclude them from our `build` target. Hence, whenever we just change a test file, our `build` cache would still be working. - -Here's how we could define that, starting from our default situation: - -```jsonc {% fileName="nx.json" highlightLines=[4, 5, 6, 7, 11] %} -{ - "namedInputs": { - "default": ["{projectRoot}/**/*"], - "production": ["default", "!{projectRoot}/**/?(*.)+(spec|test).ts"] - }, - "targetDefaults": { - "build": { - "inputs": ["production", "^production"] - } - } -} -``` - -Note how we define a new `production` named input which uses the `default` named input and then excludes (note the `!`) all spec related files. As a result, if a spec file changes either in `myreactapp` or in `shared-ui`, the `build` target cache will not be invalidated. - -## Include environment variables in cache hash - -You can also include environment variables in the cache hash key calculation in order to invalidate the cache if the environment variable value changes. - -```jsonc {% fileName="nx.json" highlightLines=[12] %} -{ - "namedInputs": { - "default": ["{projectRoot}/**/*"] - }, - "targetDefaults": { - "build": { - "inputs": [ - "default", - "^default", - - // this will include the value of API_KEY in the cache hash - { "env": "API_KEY" } - ] - } - } -} -``` - -## Include Runtime Information in the Cache Hash - -Sometimes you might also want to consider runtime information as part of your hash. Assume you have a deploy target for the `myreactapp` and assume we use [Fly](https://fly.io/) for it. We might want to make sure to just use the cache if the Fly version matches. - -You can define it globally in the `nx.json` but these targets are usually defined right where the project is, so here's an example of a `package.json` and `project.json` definition. - -{% tabs %} -{% tab label="package.json" %} - -```jsonc {% fileName="apps/myreactapp/package.json" highlightLines=[15] %} -{ - "name": "myreactapp", - "dependencies": {}, - "scripts": { - "deploy": "fly deploy" - }, - ... - "nx": { - "targets": { - "deploy": { - "inputs": [ - ... - - // includes the value of running "fly version" in the cache hash - { "runtime": "fly version" } - ], - "dependsOn": ["build"], - } - } - } -} -``` - -{% /tab %} -{% tab label="project.json" %} - -```jsonc {% fileName="apps/myreactapp/project.json" highlightLines=[13] %} -{ - "name": "reactapp", - ... - "sourceRoot": "apps/reactapp/src", - "projectType": "application", - "targets": { - "deploy": { - "command": "fly deploy", - "inputs": [ - ... - - // includes the value of running "fly version" in the cache hash - { "runtime": "fly version" } - ], - "cwd": "dist/{projectRoot}", - "dependsOn": ["build"] - }, - ... - } -} -``` - -{% /tab %} - -## Include or Exclude External NPM dependencies from the Cache - -You can also get more fine-grained when it comes to external dependencies. In our example of the Fly.io deployment, we don't really rely on any NPM packages for the deployment step, so we could ignore all of them. This can be done by using the `externalDependencies` property. - -{% tabs %} -{% tab label="package.json" %} - -```jsonc {% fileName="apps/myreactapp/package.json" highlightLines=[14] %} -{ - "name": "myreactapp", - "dependencies": {}, - "scripts": { - "deploy": "fly deploy" - }, - ... - "nx": { - "targets": { - "deploy": { - "inputs": [ - ..., - // this explicitly tells the hasher to ignore all external packages when calculating the hash - { "externalDependencies": [] }, - - // includes the value of running "fly version" in the cache hash - { "runtime": "fly version" } - ], - "dependsOn": ["build"], - } - } - } -} -``` - -{% /tab %} -{% tab label="project.json" %} - -```jsonc {% fileName="apps/myreactapp/project.json" highlightLines=[12] %} -{ - "name": "reactapp", - ... - "sourceRoot": "apps/reactapp/src", - "projectType": "application", - "targets": { - "deploy": { - "command": "fly deploy", - "inputs": [ - ..., - // this explicitly tells the hasher to ignore all external packages when calculating the hash - { "externalDependencies": [] }, - - // includes the value of running "fly version" in the cache hash - { "runtime": "fly version" } - ], - "cwd": "dist/{projectRoot}", - "dependsOn": ["build"] - }, - ... - } -} -``` - -{% /tab %} - -By explicitly providing an empty array, we ignore all changes to external NPM packages. Similarly we could have another example, where we depend on just one specific NPM package. Like if we use [Lerna](https://lerna.js.org) for publishing, we can define it like this: - -```jsonc {% fileName="apps/myreactapp/project.json" highlightLines=[8] %} -{ - "targets": { - "publish": { - "command": "lerna publish", - "inputs": [ - "production", - // we explicitly say that our run-commands depends on lerna only - { "externalDependencies": ["lerna"] } - ], - "dependsOn": ["build"], - "cwd": "dist/{projectRoot}" - } - } -} -``` diff --git a/docs/shared/recipes/running-tasks/defining-task-pipeline.md b/docs/shared/recipes/running-tasks/defining-task-pipeline.md index 6f0b54c815202..8cbdaa6f2c578 100644 --- a/docs/shared/recipes/running-tasks/defining-task-pipeline.md +++ b/docs/shared/recipes/running-tasks/defining-task-pipeline.md @@ -87,7 +87,7 @@ Or they can be [defined per-project](/reference/project-configuration#dependson) ## Visualize task dependencies -You can also visualize the actual task graph (alongside the projects) using [Nx graph](/core-features/explore-graph). This can be useful for debugging purposes. +You can also visualize the actual task graph (alongside the projects) using [Nx graph](/features/explore-graph). This can be useful for debugging purposes. To view the task graph in your browser, run: @@ -99,7 +99,7 @@ And then select "Tasks" from the top-left dropdown, choose the target (e.g. `bui ![Task graph of the Playwright Nx plugin in the nx repo being rendered in the browser](/shared/recipes/running-tasks/task-graph-playwright-nx.webp) -Alternatively you can use the [Nx Console](/core-features/integrate-with-editors) extension in VSCode or IntelliJ, right-click on the project and select: +Alternatively you can use the [Nx Console](/features/integrate-with-editors) extension in VSCode or IntelliJ, right-click on the project and select: ![Selecting "Focus task in Nx Graph" from the context menu in VS Code](/shared/recipes/running-tasks/task-graph-context-menu.webp) diff --git a/docs/shared/plugin-features/use-task-executors.md b/docs/shared/recipes/running-tasks/executors-and-configurations.md similarity index 67% rename from docs/shared/plugin-features/use-task-executors.md rename to docs/shared/recipes/running-tasks/executors-and-configurations.md index 879d44e6c5b14..b8cde07aaa0ae 100644 --- a/docs/shared/plugin-features/use-task-executors.md +++ b/docs/shared/recipes/running-tasks/executors-and-configurations.md @@ -1,18 +1,10 @@ -# Use Task Executors +# Executors and Configurations -Executors perform actions on your code. This can include building, linting, testing, serving and many other actions. +Executors are pre-packaged node scripts that can be used to run tasks in a consistent way. -There are two main differences between an executor and a shell script or an npm script: +In order to use an executor, you need to install the plugin that contains the executor and then configure the executor in the project's `project.json` file. -1. Executors encourage a consistent methodology for performing similar actions on unrelated projects. i.e. A developer switching between teams can be confident that `nx build project2` will build `project2` with the default settings, just like `nx build project1` built `project1`. -2. Nx can leverage this consistency to run the same target across multiple projects. i.e. `nx affected -t test` will run the `test` executor associated with the `test` target on every project that is affected by the current code change. -3. Executors provide metadata to define the available options. This metadata allows the Nx CLI to show prompts in the terminal and Nx Console to generate a GUI for the executor. - -## Executor definitions - -Executors are associated with specific targets in a project's `project.json` file. - -```jsonc {% fileName="project.json" %} +```jsonc {% fileName="apps/cart/project.json" %} { "root": "apps/cart", "sourceRoot": "apps/cart/src", @@ -24,12 +16,6 @@ Executors are associated with specific targets in a project's `project.json` fil "options": { "outputPath": "dist/apps/cart", ... - }, - "configurations": { - "production": { - "sourceMap": false, - ... - } } }, "test": { @@ -44,47 +30,22 @@ Executors are associated with specific targets in a project's `project.json` fil Each project has targets configured to run an executor with a specific set of options. In this snippet, `cart` has two targets defined - `build` and `test`. -{% callout type="note" title="More details" %} -`build` and `test` can be any strings you choose. For the sake of consistency, we make `test` run unit tests for every project and `build` produce compiled code for the projects which can be built. -{% /callout %} - Each executor definition has an `executor` property and, optionally, an `options` and a `configurations` property. - `executor` is a string of the form `[package name]:[executor name]`. For the `build` executor, the package name is `@nx/webpack` and the executor name is `webpack`. - `options` is an object that contains any configuration defaults for the executor. These options vary from executor to executor. - `configurations` allows you to create presets of options for different scenarios. All the configurations start with the properties defined in `options` as a baseline and then overwrite those options. In the example, there is a `production` configuration that overrides the default options to set `sourceMap` to `false`. -## Running executors - -The [`nx run`](/nx-api/nx/documents/run) cli command (or the shorthand versions) can be used to run executors. - -```shell -nx run [project]:[command] -nx run cart:build -``` - -As long as your command name doesn't conflict with an existing nx cli command, you can use this short hand: +Once configured, you can run an executor the same way you would [run any target](/features/run-tasks): ```shell nx [command] [project] nx build cart ``` -You can also use a specific configuration preset like this: +Browse the executors that are available in the [plugin registry](/plugin-registry). -```shell -nx [command] [project] --configuration=[configuration] -nx build cart --configuration=production -``` - -Or you can overwrite individual executor options like this: - -```shell -nx [command] [project] --[optionNameInCamelCase]=[value] -nx build cart --outputPath=some/other/path -``` - -## Running a single command +## Run a Terminal Command from an Executor If defining a new target that needs to run a single shell command, there is a shorthand for the `nx:run-commands` executor that can be used. @@ -104,7 +65,20 @@ If defining a new target that needs to run a single shell command, there is a sh For more info, see the [run-commands documentation](/nx-api/nx/executors/run-commands) -## Use Executor Configurations +## Build your own Executor + +Nx comes with a Devkit that allows you to build your own executor to automate your Nx workspace. Learn more about it in the [docs page about creating a local executor](/extending-nx/recipes/local-executors). + +## Running executors with a configuration + +You can use a specific configuration preset like this: + +```shell +nx [command] [project] --configuration=[configuration] +nx build cart --configuration=production +``` + +## Use Task Configurations The `configurations` property provides extra sets of values that will be merged into the options map. @@ -170,7 +144,3 @@ For example, running e2e tests for multiple environments. By default it would ma When running `nx e2e my-app-e2e`, the _dev_ configuration will be used. In this case using the local dev server for `my-app`. You can always run the other configurations by explicitly providing the configuration i.e. `nx e2e my-app-e2e --configuration=qa` or `nx run my-app-e2e:e2e:qa` - -## Build your own Executor - -Nx comes with a Devkit that allows you to build your own executor to automate your Nx workspace. Learn more about it in the [docs page about creating a local executor](/extending-nx/recipes/local-executors). diff --git a/docs/shared/recipes/running-tasks/root-level-scripts.md b/docs/shared/recipes/running-tasks/root-level-scripts.md index 613525c867a0a..fb998242a0a30 100644 --- a/docs/shared/recipes/running-tasks/root-level-scripts.md +++ b/docs/shared/recipes/running-tasks/root-level-scripts.md @@ -96,7 +96,7 @@ Documentation site generated in /docs Nx read the output from the cache instead of running the command for 1 out of 1 tasks. ``` -Read more about [cacheableOperations](/core-features/cache-task-results) and fine-tuning caching with [task inputs](/recipes/running-tasks/customizing-inputs). +Read more about [cacheableOperations](/features/cache-task-results) and fine-tuning caching with [task inputs](/recipes/running-tasks/configure-inputs). ## Keep using NPM to run scripts rather than Nx diff --git a/docs/shared/recipes/storybook/plugin-angular.md b/docs/shared/recipes/storybook/plugin-angular.md index 86cee12a2a8d6..d20cbe390dd58 100644 --- a/docs/shared/recipes/storybook/plugin-angular.md +++ b/docs/shared/recipes/storybook/plugin-angular.md @@ -146,7 +146,7 @@ Notice the interaction test on the second story, inside the `play` function. Thi ## More Documentation - [Set up Compodoc for Storybook on Nx](/recipes/storybook/angular-storybook-compodoc) -- [Information about the `storybook` targets](/deprecated/storybook/angular-storybook-targets) +- [Information about the `storybook` tasks](/deprecated/storybook/angular-storybook-targets) - [Configuring styles and preprocessor options](/recipes/storybook/angular-configuring-styles) - [The `browserTarget`](/deprecated/storybook/angular-browser-target) diff --git a/docs/shared/recipes/tips-n-tricks/compile-multiple-formats.md b/docs/shared/recipes/tips-n-tricks/compile-multiple-formats.md index a44a240e2c93f..7e1107e5a1b40 100644 --- a/docs/shared/recipes/tips-n-tricks/compile-multiple-formats.md +++ b/docs/shared/recipes/tips-n-tricks/compile-multiple-formats.md @@ -11,30 +11,10 @@ It can be difficult to set up a typescript library to compile to ESM and CommonJ If you do not use Rollup already, install the corresponding Nx plugin as follows: -{% tabs %} -{%tab label="npm"%} - -```shell -npm add -D @nx/rollup -``` - -{% /tab %} -{%tab label="yarn"%} - ```shell -yarn add -D @nx/rollup +nx add @nx/rollup ``` -{% /tab %} -{%tab label="pnpm"%} - -```shell -pnpm add -D @nx/rollup -``` - -{% /tab %} -{% /tabs %} - Make sure the version of `@nx/rollup` matches your other `@nx/*` package versions. You can then configure Rollup to compile your library by adding a `build` target to your `project.json` or `package.json` file. Here's an example: diff --git a/docs/shared/recipes/tips-n-tricks/keep-nx-versions-in-sync.md b/docs/shared/recipes/tips-n-tricks/keep-nx-versions-in-sync.md index 6d69cbe649f0f..dff1c39857b9d 100644 --- a/docs/shared/recipes/tips-n-tricks/keep-nx-versions-in-sync.md +++ b/docs/shared/recipes/tips-n-tricks/keep-nx-versions-in-sync.md @@ -6,7 +6,7 @@ If your Nx plugin versions do not match the version of `nx` in your repository, 2. Run `nx report` and identify the minimum and maximum version numbers for all the packages that need to by in sync. 3. Run `nx migrate --from=[minimumVersion] --to=[maximumVersion]`. Note that all the official Nx plugin migration generators are designed to be idempotent - meaning that running them multiple times is equivalent to running them once. This allows you to run the migrations for all plugins without being concerned about re-running a migration that was already run. -Review the [nx migrate](/core-features/automate-updating-dependencies) documentation for more options. +Review the [nx migrate](/features/automate-updating-dependencies) documentation for more options. ## Prevention diff --git a/docs/shared/recipes/troubleshoot-cache-misses.md b/docs/shared/recipes/troubleshoot-cache-misses.md index bd62b5c190cf1..00f933e38e2f0 100644 --- a/docs/shared/recipes/troubleshoot-cache-misses.md +++ b/docs/shared/recipes/troubleshoot-cache-misses.md @@ -11,7 +11,7 @@ Problem: A task is being executed when you expect it to be replayed from the cac - To check your input glob patterns file-by-file, you can get a list of all the files associated with each project by running `nx graph --file=output.json` or by clicking on a task in the task graph in the `nx graph` visualization. 1. Use the Nx Cloud troubleshooting tools - - Make sure your repo is [connected to Nx Cloud](/core-features/cache-task-results#remote-computation-caching) + - Make sure your repo is [connected to Nx Cloud](/features/cache-task-results#remote-computation-caching) - Click on the run details link that is printed in the terminal after you run a task - Expand a task that had a cache miss - Click "Check For Near Misses" to see other similar tasks diff --git a/docs/shared/reference/glossary.md b/docs/shared/reference/glossary.md index 1d3b1c3589e50..409c846aab8a4 100644 --- a/docs/shared/reference/glossary.md +++ b/docs/shared/reference/glossary.md @@ -20,25 +20,25 @@ A [library](#library) that has a `build` [target](#target). Some libraries can b A mechanism for saving the output of a calculation so it can be replayed later without actually performing the calculation again. -> See: [Cache Task Results](/core-features/cache-task-results) +> See: [Cache Task Results](/features/cache-task-results) ### Cache Hit When the [cache inputs](#cache-inputs) for a [task](#task) match an existing entry in the [cache](#cache) and the [cache outputs](#cache-outputs) can be replayed without actually running the task. -> See: [Cache Task Results](/core-features/cache-task-results) +> See: [Cache Task Results](/features/cache-task-results) ### Cache Inputs Everything that might change the output of a [task](#task). This may include source code, task options, environment variables and other settings determined at run time. These values are combined as a hash to serve as a key for an entry in the [cache](#cache). -> See: [Customizing Inputs and Named Inputs](/recipes/running-tasks/customizing-inputs) +> See: [Customizing Inputs and Named Inputs](/recipes/running-tasks/configure-inputs) ### Cache Miss When the [cache inputs](#cache-inputs) for a [task](#task) do not match an existing entry in the [cache](#cache) and the task needs to be executed. -> See: [Cache Task Results](/core-features/cache-task-results) +> See: [Cache Task Results](/features/cache-task-results) ### Cache Outputs @@ -50,13 +50,13 @@ The terminal output and any file artifacts created by running a [task](#task). T Anything you run in the terminal. An example command that invokes a [task](#task) is `nx build my-app`. -> See: [Run Tasks](/core-features/run-tasks) +> See: [Run Tasks](/features/run-tasks) ### Configurations A set of preconfigured options for a [target](#target) that should be enabled altogether. For example, a `production` configuration would set all the options needed for a build that could be deployed to production. -> See: [Use Executor Configurations](/core-features/plugin-features/use-task-executors#use-executor-configurations) +> See: [Use Task Configurations](/concepts/executors-and-configurations#use-task-configurations) ### Remote Cache @@ -74,19 +74,19 @@ A system for running [tasks](#task) in CI across multiple agent processes in the A script that performs some action on your code. This can include building, linting, testing, serving and many other actions. A [target](#target) configuration specifies an executor and a set of options. Executors can be found in [plugins](#plugin). -> See: [Use Task Executors](/core-features/plugin-features/use-task-executors) +> See: [Executors and Configurations](/concepts/executors-and-configurations) ### Generator A script that creates or modifies your code. Generators can be found in [plugins](#plugin). -> See: [Use Code Generators](/core-features/plugin-features/use-code-generators) +> See: [Use Code Generators](/features/generate-code) ### Graph A computer science concept that consists of nodes connected by edges. In the Nx context, there are two graphs: the [project](#project) graph which describes dependencies between projects and the [task](#task) graph which describes dependencies between tasks. -> See: [Explore the Graph](/core-features/explore-graph) +> See: [Explore the Graph](/features/explore-graph) ### Integrated Repository @@ -166,13 +166,13 @@ A repository with a single [application](#application) at the [root level](#root The name of an action taken on a [project](#project). -> See: [Run Tasks](/core-features/run-tasks) +> See: [Run Tasks](/features/run-tasks) ### Task An invocation of a [target](#target) on a specific [project](#project). -> See: [Run Tasks](/core-features/run-tasks) +> See: [Run Tasks](/features/run-tasks) ### Task Pipeline diff --git a/docs/shared/reference/inputs.md b/docs/shared/reference/inputs.md new file mode 100644 index 0000000000000..435c6dff6f28a --- /dev/null +++ b/docs/shared/reference/inputs.md @@ -0,0 +1,249 @@ +# Inputs and Named Inputs + +When Nx [computes the hash for a given operation](/concepts/how-caching-works), it takes into account the `inputs` of the target. +The `inputs` are a list of **file sets**, **runtime** inputs and **environment variables** that affect the output of the target. +If any of the `inputs` change, the cache is invalidated and the target is re-run. + +## Types of Inputs + +Nx can consider the following types of Inputs when computing the hash for a given operation. + +### Project Configuration + +Nx always considers the configuration of the project of a task and its dependencies when calculating the hash of a task. + +### Command Arguments + +Passing different arguments to an Nx command will often change the behavior of a task. Nx will filter out arguments which are for Nx itself and do not have any effect on running of tasks such as `--parallel` or `--projects`. + +For example, running `nx build myreactapp --prod` will not reuse the cached output of running `nx build myreactapp`. + +### Source Files + +Changing source code will often change the behavior of a task. Nx can consider the contents of files matching a pattern when calculating the computation hash. +Source file inputs are defined like this: + +```jsonc +"inputs": { + "{projectRoot}/**/*", // All files in a project + "{workspaceRoot}/.gitignore", // A specific file in the workspace + "{projectRoot}/**/*.ts", // A glob pattern for files + "!{projectRoot}/**/*.spec.ts", // Excluding files matching a glob pattern +} +``` + +Source file inputs must be prefixed with either `{projectRoot}` or `{workspaceRoot}` to distinguish where the paths should be resolved from. + +Prefixing a source file input with `!` will exclude the files matching the pattern from the set of files used to calculate the hash. +Prefixing a source file input with `^` means this entry applies to the project dependencies of the project, not the project itself. + +By default, Nx will use all files in a project as well as all files in the project's dependencies when computing a hash for tasks belonging to the project. +This may cause Nx to rerun some tasks even when files irrelevant to the task have changed but it ensures that by default, Nx always re-runs the task when it should. + +See the [Common Input Sets section](#common-inputs) to see some common examples of source file inputs + +### Environment Variables + +Tools and scripts will often use some environment variables to change their behavior. Nx can consider the value of environment variables when calculating the computation hash in order to invalidate the cache if the environment variable value changes. Environment variable inputs are defined like this: + +```jsonc +"inputs": [ + { "env": "API_KEY" } // this will include the value of $API_KEY in the cache hash +] +``` + +### Runtime Inputs + +You can use a Runtime input to provide a script which will output the information you want to include in the computation hash. Runtime inputs are defined like this: + +```jsonc +"inputs": [ + { "runtime": "node --version" } +] +``` + +This kind of input is often used to include versions of tools used to run the task. You should ensure that these scripts work on any platform where the workspace is used. Avoid using `.sh` or `.bat` files as these will not work across Windows and \*nix operating systems. + +### External Dependencies + +Source code often imports from external dependencies installed through package managers. For example, a React application will likely import `react`. It is not needed to configure those `externalDependencies` directly. Nx will always consider external dependencies depended upon by any source code within the project. + +External dependencies can also be tools used to run tasks. Updating the versions of those tools will change the behavior of those tasks. External dependencies inputs are defined like this: + +```jsonc +"inputs": [ + { "externalDependencies": ["jest"] } +] +``` + +By default, if no external dependencies inputs are specified, Nx will include the hash of all external dependencies of the workspace in the computation hash. +For many targets, Nx does not know which external dependencies are used and which are not. +By considering all external dependencies, Nx will always re-run tasks when necessary even though in some cases, it might have been able to restore from cache. + +For example, when defining a target to run `eslint .`, Nx does not know which ESLint plugins are used by the eslint config. +To be safe, it will consider all external dependencies, including all ESLint plugins, to ensure that the `lint` task is re-run when any of the plugins have been updated. +The drawback of this assumption is that Nx will re-run the `lint` task even when external dependencies not used by ESLint are updated. + +```jsonc +"targets": { + "lint": { + "command": "eslint ." + } +} +``` + +This default behavior can be overridden by adding any external dependency inputs and enables Nx to use cached results more often. + +```jsonc {% highlightLines=[6] %} +"targets": { + "lint": { + "command": "eslint .", + "inputs": [ + "default", + { "externalDependencies": ["eslint", "eslint-config-airbnb"] } + ] + } +} +``` + +Targets which use an executor from a Nx Plugin maintained by the Nx Team will have the correct set of external dependencies considered when calculating the hash. + +### Outputs of Dependent Tasks + +When a task depends on another task, it is possible that the outputs of the dependent task will affect the behavior of the task. The Nx caching mechanism can consider the contents of files produced by dependent tasks that match a pattern. Use outputs of dependent tasks as inputs like this: + +```jsonc +"inputs": [ + { "dependentTasksOutputFiles": "**/*.d.ts" }, + { "dependentTasksOutputFiles": "**/*.d.ts", "transitive": true } +] +``` + +The pattern will be matched with outputs of tasks which this task depends on. Setting `transitive` to `true` will also include outputs of all task dependencies of this task in the [task pipeline](/concepts/task-pipeline-configuration). + +### A subset of the root `tsconfig.json` or `tsconfig.base.json` + +When a root `tsconfig.json` or `tsconfig.base.json` is present, Nx will always consider parts of the file which apply to the project of a task being run. +This includes the full `compilerOptions` section and particular path mappings in the `compilerOptions.paths` property. +This allows Nx to to not invalidate every single task when a path mapping is added or removed from the root `tsconfig.json` file + +## Named Inputs + +Many tasks will utilize the same sets of inputs with minor differences. Nx allows you to define these sets in the `namedInputs` section of the `nx.json` file. + +These sets of inputs can then be referenced and reused in the `inputs` array of targets. You can think of these as variables which can be used in the `inputs` array. + +Named Inputs can be defined for the entire workspace in `nx.json` or for a specific project in `project.json`/`package.json`. + +### Workspace Level Named Inputs + +Named inputs defined in `nx.json` can be used by any project in the workspace in the `inputs` array. The following example shows how to define named inputs for the entire workspace in `nx.json`. + +```jsonc {% fileName="nx.json" highlightLines=["2-4"] %} +{ + "namedInputs": { + "default": ["{projectRoot}/**/*"] // Default Inputs + } +} +``` + +### Project Level Named Inputs + +Named inputs defined in `package.json` or `project.json` define the value of the named input for tasks belonging to that specific project. + +Naming a set of inputs with the same name as a set of inputs defined for the workspace in `nx.json` will override the meaning of that set for the project. + +{% tabs %} +{% tab label="project.json" %} + +```jsonc {% fileName="project.json" highlightLines=["2-6"] %} +{ + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], // Default Inputs + "production": ["default", "!{projectRoot}/jest.config.ts"], // Production Inputs + "sharedGlobals": [] // Shared Global Inputs + }, + "targets": { ... } +} +``` + +{% /tab %} +{% tab label="Project Level (package.json)" %} + +```jsonc {% fileName="package.json" highlightLines=["3-7"] %} +{ + "dependencies": { ... } + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], // Default Inputs + "production": ["default", "!{projectRoot}/jest.config.ts"], // Production Inputs + "sharedGlobals": [] // Shared Global Inputs + }, +} +``` + +{% /tab %} +{% /tabs %} + +### Named Input Conventions + +By default, Nx Workspaces are generated with the following named inputs: + +```jsonc {% fileName="nx.json" highlightLines=["2-6"] %} +{ + "namedInputs": { + "default": ["{projectRoot}/**/*", "sharedGlobals"], // Default Inputs + "production": ["default", "!{projectRoot}/jest.config.ts"], // Production Inputs + "sharedGlobals": [] // Shared Global Inputs + }, + "targetDefaults": { + "inputs": ["default", "^default"] + } +} +``` + +The above inputs follow a convention that Nx recommends for named inputs. Nx generates these by default but you can also introduce your own conventions. + +#### Default Inputs + +The `default` inputs include all files in a project as well as any shared global inputs which should be considered for all tasks. Defaulting to the set of everything that matters ensures that Nx will always re-run tasks when necessary by default. + +#### Shared Global Inputs + +The `sharedGlobal` inputs include things that Nx should always look at when determining computation hashes. For instance, this could be the OS where the command is being run or the version of Node. + +#### Production Inputs + +The `production` inputs only include the set of files in a project which will affect behavior of the project in production. +For instance, the `main.ts` of an application will be compiled as the main application logic and will affect the end user experience while files such as `.eslintrc.json` only affect the tools used by the developers and have no direct impact on the end user experience. +In general, it is best to define the `production` inputs as the `default` inputs (everything) excluding the specific files which are known not to affect end user experience. This makes it so that by default, all files are considered to affect end user behavior unless excluded from the `production` fileset. + +### Using Named Inputs on Project Dependencies + +It is common for most tasks to consider a set of inputs for the project it belongs to and a set of inputs for dependencies of the project. For instance, running the tests of a project should consider all files of the project being tested but only production files of its dependencies. The following `inputs` configuration uses named inputs in two different ways: + +```jsonc {% fileName="project.json" highlightLines=["5"] %} +{ + "name": "myreactapp", + "targets": { + "test": { + "inputs": ["default", "^production", "{projectRoot}/jest.config.js"] + } + } +} +``` + +1. `default` tells Nx to consider all files within the project root of `myreactapp` when running the `test` task. +2. `^production` is prefixed with `^` and applies the to projects which `myreactapp` depends on. +3. You can add other modifications to the inputs set directly without defining them as named inputs. + +All of the above inputs are taken into consideration when the following command is run: + +```shell +nx test myreactapp +``` + +{% cards %} +{% card title="nx.json reference" type="documentation" description="namedInputs can be defined in nx.json" url="/reference/nx-json#inputs-&-namedinputs" /%} +{% card title="Project configuration reference" type="documentation" description="inputs and namedInputs can be defined in project configuration" url="/reference/nx-json#inputs-&-namedinputs" /%} +{% card title="Configure Inputs for Task Caching" type="documentation" description="This recipes walks you through a few examples of how to configure inputs and namedInputs" url="/recipes/running-tasks/configure-inputs" /%} +{% /cards %} diff --git a/docs/shared/reference/nx-json.md b/docs/shared/reference/nx-json.md index e2db7a2e16cce..72d5723d41a50 100644 --- a/docs/shared/reference/nx-json.md +++ b/docs/shared/reference/nx-json.md @@ -2,19 +2,23 @@ The `nx.json` file configures the Nx CLI and project defaults. The full [machine readable schema](https://github.com/nrwl/nx/blob/master/packages/nx/schemas/nx-schema.json) is available on GitHub. -The following is an expanded example showing all options. Your `nx.json` will likely be much shorter. For a more intuitive understanding of the roles of each option, you can highlight the options in the excerpt below that relate to different categories. +The following is an expanded example showing all options. Your `nx.json` will likely be much shorter. -```json {% fileName="nx.json" lineGroups={ Caching:[11,12,13,14,17,23,27], Orchestration:[3,4,5,18], Execution:[19,20,21,22] } %} +```json {% fileName="nx.json" %} { - "extends": "nx/presets/npm.json", + "plugins": [ + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + } + ], + "parallel": 4, + "cacheDirectory": "tmp/my-nx-cache", "affected": { "defaultBase": "main" }, - "generators": { - "@nx/js:library": { - "buildable": true - } - }, "namedInputs": { "default": ["{projectRoot}/**/*"], "production": ["!{projectRoot}/**/*.spec.tsx"] @@ -30,8 +34,6 @@ The following is an expanded example showing all options. Your `nx.json` will li "cache": true } }, - "parallel": 4, - "cacheDirectory": "tmp/my-nx-cache", "release": { "version": { "generatorOptions": { @@ -49,31 +51,96 @@ The following is an expanded example showing all options. Your `nx.json` will li }, "projectChangelogs": true } - } + }, + "generators": { + "@nx/js:library": { + "buildable": true + } + }, + "extends": "nx/presets/npm.json" } ``` -### Extends +## Plugins -Some presets use the `extends` property to hide some default options in a separate json file. The json file specified in the `extends` property is located in your `node_modules` folder. The Nx preset files are specified in [the `nx` package](https://github.com/nrwl/nx/tree/master/packages/nx/presets). +Nx plugins improve the experience of using different tools with Nx. One key feature of plugins is that they can [automatically configure the way Nx runs tasks](/concepts/inferred-tasks) for a tool based on that tool's configuration. In order for a plugin to configure tasks for Nx, it needs to be registered in the `plugins` array. If a plugin has no options, it can be listed as a string. Otherwise, it should be listed as an object with a `plugin` property and an `options` property. + +Every plugin behaves differently, so consult the plugin's own documentation for information about what it does. You can browse the [plugin registry](/plugin-registry) for available plugins. + +To learn about creating your own plugin read about [extending Nx](/extending-nx/intro/getting-started). + +```json {% fileName="nx.json" %} +{ + "plugins": [ + "@my-org/graph-plugin", + { + "plugin": "@nx/eslint/plugin", + "options": { + "targetName": "lint" + } + } + ] +} +``` + +## Task Options -### NPM Scope +The following properties affect the way Nx runs tasks and can be set at the root of `nx.json`. -The `npmScope` property of the `nx.json` file is deprecated as of version 16.2.0. `npmScope` was used as a prefix for the names of newly created projects. The new recommended way to define the organization prefix is to set the `name` property in the root `package.json` file to `@my-org/root`. Then `@my-org/` will be used as a prefix for all newly created projects. +| Property | Description | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| parallel | defines the max number of targets run in parallel | +| captureStderr | defines whether the cache captures stderr or just stdout | +| skipNxCache | defines whether the Nx Cache should be skipped (defaults to `false`) | +| cacheDirectory | defines where the local cache is stored (defaults to `node_modules/.cache/nx`) | +| encryptionKey | (when using `"nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable | +| selectivelyHashTsConfig | only hash the path mapping of the active project in the `tsconfig.base.json` (e.g., adding/removing projects doesn't affect the hash of existing projects) (defaults to `false`) | + +You can configure `parallel` in `nx.json`, but you can also set a `--parallel` flag in the terminal `nx run-many -t test --parallel=5`. + +### Multiple Tasks Runners + +Tasks runners are invoked when you run `nx test`, `nx build`, `nx run-many`, `nx affected`, and so on. + +There is a tasks runner created from the task options defined at the root of `nx.json` named `default`. You can register another tasks runner by adding it to `nx.json` like this: + +```json {% fileName="nx.json" %} +{ + "tasksRunnerOptions": { + "another": { + "runner": "nx/tasks-runners/default", + "options": {} + } + } +} +``` -In Nx 16, if the `npmScope` property is present, it will be used as a prefix. If the `npmScope` property is not present, the `name` property of the root `package.json` file will be used to infer the prefix. +Then you can run a task with the new runner using the `--runner` flag: + +```shell +nx run-many -t build --runner=another +``` -In Nx 17, the `npmScope` property is ignored. +The official types of `runner` supported by Nx are `"nx/tasks-runners/default"` and `"nx-cloud"`. -### Affected +## Affected Tells Nx which branch and HEAD to use when calculating affected projects. -- `defaultBase` defines the default base branch, defaulted to `main`. +- `defaultBase` defines the default base branch, defaults to `main`. + +## Target Defaults + +Target defaults provide ways to set common options for a particular target in your workspace. When building your project's configuration, we merge it with up to 1 default from this map. For a given target, we look at its name and its executor. We then check target defaults for any of the following combinations: + +- `` `${executor}` `` +- `` `${targetName}` `` + +Whichever of these we find first, we use as the base for that target's configuration. Some common scenarios for this follow. ### inputs & namedInputs -Named inputs defined in `nx.json` are merged with the named inputs defined in each project's project.json. In other words, every project has a set of named inputs, and it's defined as: `{...namedInputsFromNxJson, ...namedInputsFromProjectsProjectJson}`. +Named inputs defined in `nx.json` are merged with the named inputs defined in [project level configuration](/reference/project-configuration). In other words, every project has a set of named inputs, and it's defined as: `{...namedInputsFromNxJson, ...namedInputsFromProjectsProjectJson}`. Defining `inputs` for a given target would replace the set of inputs for that target name defined in `nx.json`. Using pseudocode `inputs = projectJson.targets.build.inputs || nxJson.targetDefaults.build.inputs`. @@ -102,18 +169,11 @@ And projects can define their `production` inputs, without having to redefine th In this case Nx will use the right `production` input for each project. {% cards %} -{% card title="Project Configuration reference" type="documentation" description="inputs and namedInputs are also described in the project configuration reference" url="/reference/project-configuration#inputs-&-namedinputs" /%} -{% card title="Customizing inputs and namedInputs" type="documentation" description="This guide walks through a few examples of how to customize inputs and namedInputs" url="/recipes/running-tasks/customizing-inputs" /%} +{% card title="Inputs and Named Inputs Reference" type="documentation" description="Learn about all the possible settings for `inputs` and `namedInputs`" url="/reference/inputs" /%} +{% card title="Configure Inputs for Task Caching" type="documentation" description="This recipes walks you through a few examples of how to configure `inputs` and `namedInputs`" url="/recipes/running-tasks/configure-inputs" /%} {% /cards %} -### Target Defaults - -Target defaults provide ways to set common options for a particular target in your workspace. When building your project's configuration, we merge it with up to 1 default from this map. For a given target, we look at its name and its executor. We then check target defaults for any of the following combinations: - -- `` `${executor}` `` -- `` `${targetName}` `` - -Whichever of these we find first, we use as the base for that target's configuration. Some common scenarios for this follow. +### Task Pipelines 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 `project.json` can be used to define the list of dependencies of an @@ -134,11 +194,13 @@ defining `targetDefaults` in `nx.json` is helpful. The configuration above is identical to adding `{"dependsOn": ["^build"]}` to every build target of every project. -For full documentation of the `dependsOn` property, see the [project configuration reference](/reference/project-configuration#dependson). {% cards %} {% card title="Project Configuration reference" type="documentation" description="For full documentation of the `dependsOn` property, see the project configuration reference" url="/reference/project-configuration#dependson" /%} +{% card title="What is a Task Pipeline" type="documentation" description="This guide describes how to think about task pipelines" url="/concepts/task-pipeline-configuration" /%} {% /cards %} +### Outputs + Another target default you can configure is `outputs`: ```json {% fileName="nx.json" %} @@ -181,7 +243,11 @@ When defining any options or configurations inside of a target default, you may Note that the inputs and outputs are respecified on the @nx/js:tsc default configuration. This is **required**, as when reading target defaults Nx will only ever look at one key. If there is a default configuration based on the executor used, it will be read first. If not, Nx will fall back to looking at the configuration based on target name. For instance, running `nx build project` will read the options from `targetDefaults[@nx/js:tsc]` if the target configuration for build uses the @nx/js:tsc executor. It **would not** read any of the configuration from the `build` target default configuration unless the executor does not match. {% /callout %} -#### Cache +{% cards %} +{% card title="Configure Outputs for Task Caching" type="documentation" description="This recipe walks you through how to set outputs" url="/recipes/running-tasks/configure-outputs" /%} +{% /cards %} + +### Cache In Nx 17 and higher, caching is configured by specifying `"cache": true` in a target's configuration. This will tell Nx that it's ok to cache the results of a given target. For instance, if you have a target that runs tests, you can specify `"cache": true` in the target default configuration for `test` and Nx will cache the results of running tests. @@ -195,98 +261,21 @@ In Nx 17 and higher, caching is configured by specifying `"cache": true` in a ta } ``` -{% callout type="warning" title="Per Project Caching + DTE" %} +{% callout type="warning" title="Per Project Caching + Distribution" %} -If you are using distributed task execution and disable caching for a given target, you will not be able to use distributed task execution for that target. This is because distributed task execution requires caching to be enabled. This means that the target you have disabled caching for, and any targets which depend on that target will fail the pipeline if you try to run them with DTE enabled. +If you are using distributed task execution and disable caching for a given target, you will not be able to use distributed task execution for that target. This is because distributed task execution requires caching to be enabled. This means that the target you have disabled caching for, and any targets which depend on that target will fail the pipeline if you try to run them with Nx Agents enabled. {% /callout %} -### Plugins - -Nx plugins can provide generators, executors, as well as modifying the project graph. Any plugin that modifies the project graph must be listed in the `plugins` array in `nx.json`. Plugins which modify the project graph generally either add nodes or dependencies to the graph. - -This can be read about in more detail in the [plugins guide](/extending-nx/recipes/project-graph-plugins). - -Inside `nx.json`, these plugins are either listed by their module path, or an object that references the plugin's module path and options that should be passed to it. - -```json {% fileName="nx.json" %} -{ - "plugins": [ - "@my-org/graph-plugin", - { - "plugin": "@my-org/other-plugin", - "options": { - "someOption": true - } - } - ] -} -``` - -### Generators - -Default generator options are configured in `nx.json` as well. For instance, the following tells Nx to always -pass `--buildable=true` when creating new libraries. - -```json {% fileName="nx.json" %} -{ - "generators": { - "@nx/js:library": { - "buildable": true - } - } -} -``` - -### Tasks Runner Options - -> A task is an invocation of a target. - -Tasks runners are invoked when you run `nx test`, `nx build`, `nx run-many`, `nx affected`, and so on. The tasks runner -named "default" is used by default. Specify a different one like this `nx run-many -t build --runner=another`. - -To register a tasks runner, add it to `nx.json` like this: - -```json {% fileName="nx.json" %} -{ - "tasksRunnerOptions": { - "another": { - "runner": "nx/tasks-runners/default", - "options": {} - } - } -} -``` - -Tasks runners can accept different options. The following are the options supported -by `"nx/tasks-runners/default"` and `"nx-cloud"`. - -{% callout type="note" title="Define these properties at the root" %} -As of Nx 17, if you only use one tasks runner, you can specify these properties at the root of `nx.json` instead of inside the `tasksRunnerOptions` property. -{% /callout %} - -| Property | Description | -| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| cacheableOperations | In Nx < 17, defined the list of targets/operations that were cached by Nx. In Nx 17, use the `cache` property in `targetDefaults` or individual target definitions | -| parallel | defines the max number of targets ran in parallel (in older versions of Nx you had to pass `--parallel --maxParallel=3` instead of `--parallel=3`) | -| captureStderr | defines whether the cache captures stderr or just stdout | -| skipNxCache | defines whether the Nx Cache should be skipped (defaults to `false`) | -| cacheDirectory | defines where the local cache is stored (defaults to `node_modules/.cache/nx`) | -| encryptionKey | (when using `"nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable | -| selectivelyHashTsConfig | only hash the path mapping of the active project in the `tsconfig.base.json` (e.g., adding/removing projects doesn't affect the hash of existing projects) (defaults to `false`) | - -You can configure `parallel` in `nx.json`, but you can also pass them in the -terminal `nx run-many -t test --parallel=5`. - -### Release +## Release The `release` property in `nx.json` configures the `nx release` command. It is an optional property, as `nx release` is capable of working with zero config, but when present it is used to configure the versioning, changelog, and publishing phases of the release process. -For more information on how `nx release` works, see [manage releases](/core-features/manage-releases). +For more information on how `nx release` works, see [manage releases](/features/manage-releases). The full list of configuration options available for `"release"` can be found here: [https://github.com/nrwl/nx/blob/master/packages/nx/src/config/nx-json.ts](https://github.com/nrwl/nx/blob/master/packages/nx/src/config/nx-json.ts) under `NxReleaseConfiguration`. -#### Projects +### Projects If you want to limit the projects that `nx release` targets, you can use the `projects` property in `nx.json` to do so. This property is either a string, or an array of strings. The strings can be project names, glob patterns, directories, tag references or anything else that is supported by the `--projects` filter you may know from other commands such as `nx run`. @@ -300,7 +289,7 @@ If you want to limit the projects that `nx release` targets, you can use the `pr } ``` -#### Projects Relationship +### Projects Relationship The `projectsRelationship` property tells Nx whether to release projects independently or together. By default Nx will release all your projects together in lock step, which is an equivalent of `"projectRelationships": "fixed"`. If you want to release projects independently, you can set `"projectsRelationship": "independent"`. @@ -314,7 +303,7 @@ The `projectsRelationship` property tells Nx whether to release projects indepen } ``` -#### Release Tag Pattern +### Release Tag Pattern Optionally override the git/release tag pattern to use. This field is the source of truth for changelog generation and release tagging, as well as for conventional commits parsing. @@ -334,7 +323,7 @@ The default `"releaseTagPattern"` for independent releases at the project level } ``` -#### Version +### Version The `version` property configures the versioning phase of the release process. It is used to determine the next version of your projects, and update any projects that depend on them to use the new version. @@ -362,7 +351,7 @@ It is therefore a common requirement to be able to tweak the options given to th For a full reference of the available options for the `@nx/js:release-version` generator, see the [release version generator reference](/nx-api/js/generators/release-version). -#### Changelog +### Changelog The `changelog` property configures the changelog phase of the release process. It is used to generate a changelog for your projects, and commit it to your repository. @@ -374,7 +363,7 @@ There are two types of possible changelog that can be generated: The `changelog` property is used to configure both of these changelogs. -##### Workspace Changelog +#### Workspace Changelog The `changelog.workspaceChangelog` property configures the workspace changelog. It is used to determine if and how the workspace changelog is generated. @@ -405,7 +394,7 @@ The `changelog.workspaceChangelog` property configures the workspace changelog. } ``` -##### Project Changelogs +#### Project Changelogs The `changelog.projectChangelogs` property configures the project changelogs. It is used to determine if and how the project changelogs are generated. @@ -437,7 +426,7 @@ The `changelog.projectChangelogs` property configures the project changelogs. It } ``` -#### Git +### Git The `git` property configures the automated git operations that take place as part of the release process. @@ -455,3 +444,22 @@ The `git` property configures the automated git operations that take place as pa } } ``` + +## Generators + +Default generator options can be configured in `nx.json`. For instance, the following tells Nx to always +pass `--buildable=true` when creating new libraries with the `@nx/js` plugin. + +```json {% fileName="nx.json" %} +{ + "generators": { + "@nx/js:library": { + "buildable": true + } + } +} +``` + +## Extends + +Some presets use the `extends` property to hide some default options in a separate json file. The json file specified in the `extends` property is located in your `node_modules` folder. The Nx preset files are specified in [the `nx` package](https://github.com/nrwl/nx/tree/master/packages/nx/presets). diff --git a/docs/shared/reference/project-configuration.md b/docs/shared/reference/project-configuration.md index 8ac20b8b194c7..78a343432fb71 100644 --- a/docs/shared/reference/project-configuration.md +++ b/docs/shared/reference/project-configuration.md @@ -1,7 +1,59 @@ # Project Configuration -Projects can be configured in `package.json` (if you use npm scripts and not Nx executors) and `project.json` (if you -[use task executors](/core-features/plugin-features/use-task-executors)). Both `package.json` and `project.json` files are located in each project's folder. Nx merges the two +A project's configuration is constructed by Nx from three sources: + +1. [Tasks inferred by Nx plugins](/concepts/inferred-tasks) from tooling configuration +2. [Workspace `targetDefaults`](/reference/nx-json#target-defaults) defined in the `nx.json` file +3. Individual project level configuration files (`package.json` and `project.json`) + +Each source will overwrite the previous source. That means `targetDefaults` will overwrite inferred tasks and project level configuration will overwrite both `targetDefaults` and inferred tasks. The combined project configuration can be viewed in the project details view by using [Nx Console](/features/integrate-with-editors) in your IDE or by running: + +```shell +nx show project myproject --web +``` + +{% project-details title="Project Details View" height="100px" %} + +```json +{ + "project": { + "name": "demo", + "data": { + "root": " packages/demo", + "projectType": "application", + "targets": { + "dev": { + "executor": "nx:run-commands", + "options": { + "command": "vite dev" + } + }, + "build": { + "executor": "nx:run-commands", + "inputs": ["production", "^production"], + "outputs": ["{projectRoot}/dist"], + "options": { + "command": "vite build" + } + } + } + } + }, + "sourceMap": { + "targets": ["packages/demo/vite.config.ts", "@nx/vite"], + "targets.dev": ["packages/demo/vite.config.ts", "@nx/vite"], + "targets.build": ["packages/demo/vite.config.ts", "@nx/vite"] + } +} +``` + +{% /project-details %} + +The project details view also shows where each setting is defined so that you know where to change it. + +## Project Level Configuration Files + +If you need to edit your project settings or modify an inferred task, you can do so in either `package.json` or `project.json` files. The examples on this page show both styles, and the only functional difference is that tasks that use executors must be defined in a `project.json`. Nx merges the two files to get each project's configuration. The full [machine readable schema](https://github.com/nrwl/nx/blob/master/packages/nx/schemas/project-schema.json) is available on GitHub. The following configuration creates `build` and `test` targets for Nx. @@ -47,7 +99,7 @@ The following configuration creates `build` and `test` targets for Nx. You can invoke `nx build mylib` or `nx test mylib` without any extra configuration. -Below are some more complete examples of project configuration files. For a more intuitive understanding of the roles of each option, you can highlight the options in the excerpt below that relate to different categories. +Below are some more complete examples of project configuration files. For a more intuitive understanding of the roles of each option, you can highlight the options in the excerpt below that relate to different categories. Orchestration settings control the way [Nx runs tasks](/features/run-tasks). Execution settings control the actual task that is run. Caching settings control when [Nx caches a task](/features/cache-task-results) and what is actually cached. {% tabs %} {% tab label="package.json" %} @@ -118,174 +170,56 @@ Below are some more complete examples of project configuration files. For a more {% /tab %} {% /tabs %} -### inputs & namedInputs - -The `inputs` array tells Nx what to consider to determine whether a particular invocation of a script should be a cache -hit or not. There are three types of inputs: - -#### Filesets - -Examples: +## Task Definitions (Targets) -- `{projectRoot}/**.*.ts` -- same as `{fileset: "{projectRoot}/**/*.ts"}` -- `{workspaceRoot}/jest.config.ts` -- same as `{fileset: "{workspaceRoot}/jest.config.ts}` +A large portion of project configuration is related to defining the tasks for the project. In addition, to defining what the task actually does, a task definition also has properties that define the way that Nx should run that task. Those properties are described in detail below. -{% callout type="note" title="inputs syntax" %} +### Cache -The `inputs` and `namedInputs` are parsed with the following rules: - -1. `{projectRoot}` and `{workspaceRoot}` are replaced with the appropriate path -2. A `^` character at the beginning of the string means this entry applies to the project dependencies of the project, not the project itself. -3. Everything else is processed with the [minimatch](https://github.com/isaacs/minimatch) library - -{% /callout %} - -#### Runtime Inputs - -Nx will execute the command specified by `runtime` inputs and use the result when calculating hashes. - -Example: - -``` -{ - "targets": { - "build": { - "executor" : "@nx/js:tsc", - "inputs" : [{"runtime": "node -v"}] - } - } -} -``` - -Note: the result is hashed, so it is never displayed. - -#### Env Variables - -Nx will read the environment variable specified by `env` inputs and use it when calculating hashes. - -Example: +In Nx 17 and higher, caching is configured by specifying `"cache": true` in a target's configuration. This will tell Nx that it's ok to cache the results of a given target. For instance, if you have a target that runs tests, you can specify `"cache": true` in the target default configuration for `test` and Nx will cache the results of running tests. -``` +```json {% fileName="project.json" %} { "targets": { - "build": { - "executor" : "@nx/js:tsc", - "inputs" : [{"env": "DEMO_VAR"}] + "test": { + "cache": true } } } ``` -Note: the value is hashed, so it is never displayed. - -#### External Dependencies - -For official plugins, Nx intelligently finds a set of external dependencies which it hashes for the target. `nx:run-commands` is an exception to this. -Because you may specify any command to be run, it is not possible to determine which, if any, external dependencies are used by the target. -To be safe, Nx assumes that updating any external dependency invalidates the cache for the target. - -> Note: Community plugins are also treated like `nx:run-commands` - -This input type allows you to override this cautious behavior by specifying a set of external dependencies to hash for the target. - -Examples: - -Targets that only use commands natively available in the terminal will not depend on any external dependencies. Specify an empty array to not hash any external dependencies. - -```json -{ - "targets": { - "copyFiles": { - "inputs": [ - { - "externalDependencies": [] - } - ], - "command": "cp src/assets dist" - } - } -} -``` +{% callout type="warning" title="Per Project Caching + Distribution" %} -If a target uses a command from an npm package, that package should be listed. +If you are using distributed task execution and disable caching for a given target, you will not be able to use distributed task execution for that target. This is because distributed task execution requires caching to be enabled. This means that the target you have disabled caching for, and any targets which depend on that target will fail the pipeline if you try to run them with Nx Agents enabled. -```json -{ - "targets": { - "copyFiles": { - "inputs": [ - { - "externalDependencies": ["lerna"] - } - ], - "command": "npx lerna publish" - } - } -} -``` +{% /callout %} -#### Dependent tasks output +### Inputs and Named Inputs -This input allows us to depend on the output, rather than the input of the dependent tasks. We can specify the glob pattern to match only the subset of the output files. -The `transitive` parameter defines whether the check and the pattern should be recursively applied to the dependent tasks of the child tasks. +Each cacheable task needs to define `inputs` which determine whether the task outputs can be retrieved from the cache or the task needs to be re-run. The `namedInputs` defined in `nx.json` or project level configuration are sets of reusable input definitions. -Examples: +A typical set of inputs may look like this: -```json +```jsonc {% fileName="" %} { "namedInputs": { - "default": ["{projectRoot}/**/*", "sharedGlobals"], - "production": ["default", "!{projectRoot}/**/*.spec.ts"], - "deps": [{ "dependentTasksOutputFiles": "**/*.d.ts", "transitive": true }] + "default": ["{projectRoot}/**/*"], // every file in the project + "production": ["default", "!{projectRoot}/**/*.spec.tsx"] // except test files }, - "targetDefaults": { - "build": { - "dependsOn": ["^build"], - "inputs": ["production", "deps"] - } - } -} -``` - -#### Named Inputs - -Examples: - -- `inputs: ["production"]` -- same as `"inputs": [{"input": "production", "projects": "self"}]` in versions prior to Nx 16, or `"inputs": [{"input": "production"}]` after version 16. - -Often the same glob will appear in many places (e.g., prod fileset will exclude spec files for all projects). Because -keeping them in sync is error-prone, we recommend defining `namedInputs`, which you can then reference in all of those -places. - -#### Using ^ - -Examples: - -- `inputs: ["^production"]` -- same as `inputs: [{"input": "production", "projects": "dependencies"}]` prior to Nx 16, or `"inputs": [{"input": "production", "dependencies": true }]` after version 16. - -Similar to `dependsOn`, the "^" symbols means "dependencies". This is a very important idea, so let's illustrate it with -an example. - -```json -{ "targets": { - "test": { - "inputs": ["default", "^production"] + "build": { + "inputs": [ + "production", // this project's production files + { "externalDependencies": ["vite"] } // the version of the vite package + ] } } } ``` -The configuration above means that the test target depends on all source files of a given project and only prod -sources (non-test sources) of its dependencies. In other words, it treats test sources as private. - {% cards %} -{% card title="nx.json reference" type="documentation" description="inputs and namedInputs are also described in the nx.json reference" url="/reference/nx-json#inputs-&-namedinputs" /%} -{% card title="Customizing inputs and namedInputs" type="documentation" description="This guide walks through a few examples of how to customize inputs and namedInputs" url="/recipes/running-tasks/customizing-inputs" /%} +{% card title="Inputs and Named Inputs Reference" type="documentation" description="Learn about all the possible settings for `inputs` and `namedInputs`" url="/reference/inputs" /%} +{% card title="Configure Inputs for Task Caching" type="documentation" description="This recipes walks you through a few examples of how to configure `inputs` and `namedInputs`" url="/recipes/running-tasks/configure-inputs" /%} {% /cards %} ### Outputs @@ -301,6 +235,12 @@ Specifically, by default, the following locations are cached for builds: - `{projectRoot}/dist`, - `{projectRoot}/public` +{% cards %} +{% card title="Configure Outputs for Task Caching" type="documentation" description="This recipes walks gives helpful tips to configure `outputs` for tasks" url="/recipes/running-tasks/configure-outputs" /%} +{% /cards %} + +Read the [configure outputs for task caching](/recipes/running-tasks/configure-outputs) recipe for helpful tips for setting outputs. + #### Basic Example Usually, a target writes to a specific directory or a file. The following instructs Nx to cache `dist/libs/mylib` and `build/libs/mylib/main.js`: @@ -365,26 +305,6 @@ More advanced patterns can be used to exclude files and folders in a single line } ``` -#### Cache - -In Nx 17 and higher, caching is configured by specifying `"cache": true` in a target's configuration. This will tell Nx that it's ok to cache the results of a given target. For instance, if you have a target that runs tests, you can specify `"cache": true` in the target default configuration for `test` and Nx will cache the results of running tests. - -```json {% fileName="project.json" %} -{ - "targets": { - "test": { - "cache": true - } - } -} -``` - -{% callout type="warning" title="Per Project Caching + DTE" %} - -If you are using distributed task execution and disable caching for a given target, you will not be able to use distributed task execution for that target. This is because distributed task execution requires caching to be enabled. This means that the target you have disabled caching for, and any targets which depend on that target will fail the pipeline if you try to run them with DTE enabled. - -{% /callout %} - ### dependsOn Targets can depend on other targets. This is the relevant portion of the configuration file: @@ -417,7 +337,7 @@ result in `mylib`'s dependencies being built as well. You can also express task dependencies with an object syntax: {% tabs %} -{% tab label="Version < 16" %} +{% tab label="Version 16+ (self)" %} ```json { @@ -425,7 +345,6 @@ You can also express task dependencies with an object syntax: "build": { "dependsOn": [ { - "projects": "dependencies", // "dependencies" or "self" "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } @@ -436,7 +355,7 @@ You can also express task dependencies with an object syntax: ``` {% /tab %} -{% tab label="Version 16+ (self)" %} +{% tab label="Version 16+ (dependencies)" %} ```json { @@ -444,6 +363,7 @@ You can also express task dependencies with an object syntax: "build": { "dependsOn": [ { + "dependencies": true, // Run this target on all dependencies first "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } @@ -454,7 +374,7 @@ You can also express task dependencies with an object syntax: ``` {% /tab %} -{% tab label="Version 16+ (dependencies)" %} +{% tab label="Version 16+ (specific projects)" %} ```json { @@ -462,7 +382,7 @@ You can also express task dependencies with an object syntax: "build": { "dependsOn": [ { - "dependencies": true, // Run this target on all dependencies first + "projects": ["my-app"], // Run build on "my-app" first "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } @@ -473,7 +393,7 @@ You can also express task dependencies with an object syntax: ``` {% /tab %} -{% tab label="Version 16+ (specific projects)" %} +{% tab label="Version < 16" %} ```json { @@ -481,7 +401,7 @@ You can also express task dependencies with an object syntax: "build": { "dependsOn": [ { - "projects": ["my-app"], // Run build on "my-app" first + "projects": "dependencies", // "dependencies" or "self" "target": "build", // target name "params": "ignore" // "forward" or "ignore", defaults to "ignore" } @@ -499,32 +419,32 @@ You can also express task dependencies with an object syntax: You can write the shorthand configuration above in the object syntax like this: {% tabs %} -{% tab label="Version < 16" %} +{% tab label="Version 16+" %} ```json { "targets": { "build": { - "dependsOn": [{ "projects": "dependencies", "target": "build" }] + "dependsOn": [{ "dependencies": true, "target": "build" }] // Run build on my dependencies first }, "test": { - "dependsOn": [{ "projects": "self", "target": "build" }] + "dependsOn": [{ "target": "build" }] // Run build on myself first } } } ``` {% /tab %} -{% tab label="Version 16+" %} +{% tab label="Version < 16" %} ```json { "targets": { "build": { - "dependsOn": [{ "dependencies": true, "target": "build" }] // Run build on my dependencies first + "dependsOn": [{ "projects": "dependencies", "target": "build" }] }, "test": { - "dependsOn": [{ "target": "build" }] // Run build on myself first + "dependsOn": [{ "projects": "self", "target": "build" }] } } } @@ -536,7 +456,7 @@ You can write the shorthand configuration above in the object syntax like this: With the expanded syntax, you also have a third option available to configure how to handle the params passed to the target. You can either forward them or you can ignore them (default). {% tabs %} -{% tab label="Version < 16" %} +{% tab label="Version 16+" %} ```json { @@ -544,25 +464,25 @@ With the expanded syntax, you also have a third option available to configure ho "build": { // forward params passed to this target to the dependency targets "dependsOn": [ - { "projects": "dependencies", "target": "build", "params": "forward" } + { "projects": "{dependencies}", "target": "build", "params": "forward" } ] }, "test": { // ignore params passed to this target, won't be forwarded to the dependency targets "dependsOn": [ - { "projects": "dependencies", "target": "build", "params": "ignore" } + { "projects": "{dependencies}", "target": "build", "params": "ignore" } ] }, "lint": { // ignore params passed to this target, won't be forwarded to the dependency targets - "dependsOn": [{ "projects": "dependencies", "target": "build" }] + "dependsOn": [{ "projects": "{dependencies}", "target": "build" }] } } } ``` {% /tab %} -{% tab label="Version 16+" %} +{% tab label="Version < 16" %} ```json { @@ -570,18 +490,18 @@ With the expanded syntax, you also have a third option available to configure ho "build": { // forward params passed to this target to the dependency targets "dependsOn": [ - { "projects": "{dependencies}", "target": "build", "params": "forward" } + { "projects": "dependencies", "target": "build", "params": "forward" } ] }, "test": { // ignore params passed to this target, won't be forwarded to the dependency targets "dependsOn": [ - { "projects": "{dependencies}", "target": "build", "params": "ignore" } + { "projects": "dependencies", "target": "build", "params": "ignore" } ] }, "lint": { // ignore params passed to this target, won't be forwarded to the dependency targets - "dependsOn": [{ "projects": "{dependencies}", "target": "build" }] + "dependsOn": [{ "projects": "dependencies", "target": "build" }] } } } @@ -593,30 +513,30 @@ With the expanded syntax, you also have a third option available to configure ho This also works when defining a relation for the target of the project itself using `"projects": "self"`: {% tabs %} -{% tab label="Version < 16" %} +{% tab label="Version 16+" %} ```json { "targets": { "build": { // forward params passed to this target to the project target - "dependsOn": [ - { "projects": "self", "target": "pre-build", "params": "forward" } - ] + "dependsOn": [{ "target": "pre-build", "params": "forward" }] } } } ``` {% /tab %} -{% tab label="Version 16+" %} +{% tab label="Version < 16" %} ```json { "targets": { "build": { // forward params passed to this target to the project target - "dependsOn": [{ "target": "pre-build", "params": "forward" }] + "dependsOn": [ + { "projects": "self", "target": "pre-build", "params": "forward" } + ] } } } @@ -649,6 +569,10 @@ Additionally, when using the expanded object syntax, you can specify individual This configuration is usually not needed. Nx comes with reasonable defaults (imported in `nx.json`) which implement the configuration above. +## Project Metadata + +The following properties describe the project as a whole. + ### tags You can annotate your projects with `tags` as follows: @@ -670,7 +594,7 @@ You can annotate your projects with `tags` as follows: ```jsonc {% fileName="project.json" %} { - "root": "/libs/mylib", + "root": "libs/mylib", "tags": ["scope:myteam"] } ``` @@ -678,7 +602,7 @@ You can annotate your projects with `tags` as follows: {% /tab %} {% /tabs %} -You can [configure lint rules using these tags](/core-features/enforce-module-boundaries) to, for instance, ensure that libraries +You can [configure lint rules using these tags](/features/enforce-module-boundaries) to, for instance, ensure that libraries belonging to `myteam` are not depended on by libraries belong to `theirteam`. ### implicitDependencies @@ -702,7 +626,7 @@ Nx uses powerful source-code analysis to figure out your workspace's project gra ```jsonc {% fileName="project.json" %} { - "root": "/libs/mylib", + "root": "libs/mylib", "implicitDependencies": ["anotherlib"] } ``` @@ -729,7 +653,7 @@ You can also remove a dependency as follows: ```jsonc {% fileName="project.json" %} { - "root": "/libs/mylib", + "root": "libs/mylib", "implicitDependencies": ["!anotherlib"] # regardless of what Nx thinks, "mylib" doesn't depend on "anotherlib" } ``` @@ -756,7 +680,7 @@ An implicit dependency could also be a glob pattern: ```jsonc {% fileName="project.json" %} { - "root": "/libs/mylib", + "root": "libs/mylib", "implicitDependencies": ["shop-*"] # "mylib" depends on all projects beginning with "shop-" } ``` @@ -772,8 +696,8 @@ If you want to ignore a particular `package.json` file, exclude it from those to ### Ignoring package.json scripts -Nx merges package.json scripts with your targets that are defined in project.json. -If you only wish for some scripts to be used as Nx targets, you can specify them in the `includedScripts` property of the project's package.json. +Nx merges `package.json` scripts with any targets defined in `project.json`. +If you only wish for some scripts to be used as Nx targets, you can specify them in the `includedScripts` property of the project's `package.json`. ```json {% filename="packages/my-library/package.json" } { @@ -789,7 +713,7 @@ If you only wish for some scripts to be used as Nx targets, you can specify them } ``` -{% short-embeds %} + diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 85f79c08c05f8..341477c86a5be 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -12,7 +12,6 @@ - [Angular Standalone](/getting-started/tutorials/angular-standalone-tutorial) - [Angular Monorepo](/getting-started/tutorials/angular-monorepo-tutorial) - [Vue Standalone](/getting-started/tutorials/vue-standalone-tutorial) - - [Node Standalone](/getting-started/tutorials/node-server-tutorial) - [Core Tutorial](/core-tutorial) - [1 - Create Blog](/core-tutorial/01-create-blog) - [2 - Create CLI](/core-tutorial/02-create-cli) @@ -20,35 +19,24 @@ - [4 - Build Affected Projects](/core-tutorial/04-build-affected-projects) - [5 - Automatically Detect Dependencies](/core-tutorial/05-auto-detect-dependencies) - [6 - Summary](/core-tutorial/06-summary) - - [Angular Standalone Tutorial](/angular-standalone-tutorial) - - [1 - Code Generation](/angular-standalone-tutorial/1-code-generation) - - [2 - Project Graph](/angular-standalone-tutorial/2-project-graph) - - [3 - Task Running](/angular-standalone-tutorial/3-task-running) - - [4 - Task Pipelines](/angular-standalone-tutorial/4-task-pipelines) - - [5 - Summary](/angular-standalone-tutorial/5-summary) - - [Node Server Tutorial](/node-server-tutorial) - - [1 - Code Generation](/node-server-tutorial/1-code-generation) - - [2 - Project Graph](/node-server-tutorial/2-project-graph) - - [3 - Task Running](/node-server-tutorial/3-task-running) - - [4 - Task Pipelines](/node-server-tutorial/4-task-pipelines) - - [5 - Docker Target](/node-server-tutorial/5-docker-target) - - [6 - Summary](/node-server-tutorial/6-summary) - - [Core Features](/core-features) - - [Run Tasks](/core-features/run-tasks) - - [Cache Task Results](/core-features/cache-task-results) - - [Explore the Graph](/core-features/explore-graph) - - [Automate Updating Dependencies](/core-features/automate-updating-dependencies) - - [Enforce Module Boundaries](/core-features/enforce-module-boundaries) - - [Integrate with Editors](/core-features/integrate-with-editors) - - [Manage Releases](/core-features/manage-releases) - - [Plugin Features](/core-features/plugin-features) - - [Use Task Executors](/core-features/plugin-features/use-task-executors) - - [Use Code Generators](/core-features/plugin-features/use-code-generators) + - [Features](/features) + - [Run Tasks](/features/run-tasks) + - [Cache Task Results](/features/cache-task-results) + - [Explore your Workspace](/features/explore-graph) + - [Generate Code](/features/generate-code) + - [Automate Updating Dependencies](/features/automate-updating-dependencies) + - [Enforce Module Boundaries](/features/enforce-module-boundaries) + - [Integrate with Editors](/features/integrate-with-editors) + - [Manage Releases](/features/manage-releases) + - [CI Features](/features/ci-features) - [Concepts](/concepts) - [Mental Model](/concepts/mental-model) - [How Caching Works](/concepts/how-caching-works) - - [Types of Configuration](/concepts/types-of-configuration) - [What is a Task Pipeline](/concepts/task-pipeline-configuration) + - [What Are Nx Plugins](/concepts/nx-plugins) + - [Inferred Tasks](/concepts/inferred-tasks) + - [Types of Configuration](/concepts/types-of-configuration) + - [Executors and Configurations](/concepts/executors-and-configurations) - [Integrated Repos vs. Package-Based Repos vs. Standalone Apps](/concepts/integrated-vs-package-based) - [Module Federation](/concepts/module-federation) - [Module Federation and Nx](/concepts/module-federation/module-federation-and-nx) @@ -75,10 +63,11 @@ - [How the Project Graph is Built](/concepts/more-concepts/how-project-graph-is-built) - [Recipes](/recipes) - [Tasks & Caching](/recipes/running-tasks) - - [Fine-tuning Caching with Inputs](/recipes/running-tasks/customizing-inputs) - - [Defining a Task Pipeline](/recipes/running-tasks/defining-task-pipeline) + - [Configure Inputs for Task Caching](/recipes/running-tasks/configure-inputs) + - [Configure Outputs for Task Caching](/recipes/running-tasks/configure-outputs) + - [Define a Task Pipeline](/recipes/running-tasks/defining-task-pipeline) - [Change Cache Location](/recipes/running-tasks/change-cache-location) - - [Running Custom Commands](/recipes/running-tasks/run-commands-executor) + - [Run Custom Commands](/recipes/running-tasks/run-commands-executor) - [Run Tasks in Parallel](/recipes/running-tasks/run-tasks-in-parallel) - [Run Root-Level NPM Scripts with Nx](/recipes/running-tasks/root-level-scripts) - [Workspace Watching](/recipes/running-tasks/workspace-watching) @@ -87,7 +76,6 @@ - [NPM/Yarn/PNPM workspaces](/recipes/adopting-nx/adding-to-monorepo) - [Migrate From Turborepo](/recipes/adopting-nx/from-turborepo) - [Add to any Project](/recipes/adopting-nx/adding-to-existing-project) - - [Nx and Lerna](/recipes/adopting-nx/lerna-and-nx) - [Preserving Git Histories](/recipes/adopting-nx/preserving-git-histories) - [Manual migration](/recipes/adopting-nx/manual) - [React](/recipes/react) @@ -144,7 +132,7 @@ - [Vite](/recipes/vite) - [Configure Vite on your Nx workspace](/recipes/vite/configure-vite) - [Webpack](/recipes/webpack) - - [How to configure webpack on your Nx workspace](/recipes/webpack/webpack-config-setup) + - [How to configure Webpack in your Nx workspace](/recipes/webpack/webpack-config-setup) - [Webpack plugins](/recipes/webpack/webpack-plugins) - [Module Federation](/recipes/module-federation) - [How to create a Module Federation Host Application](/recipes/module-federation/create-a-host) @@ -185,6 +173,7 @@ - [Profiling Build Performance](/recipes/troubleshooting/performance-profiling) - [Nx Console](/recipes/nx-console) - [Telemetry](/recipes/nx-console/console-telemetry) + - [Project Details View](/recipes/nx-console/console-project-details) - [Generate Command](/recipes/nx-console/console-generate-command) - [Run Command](/recipes/nx-console/console-run-command) - [Add Dependency Command](/recipes/nx-console/console-add-dependency-command) @@ -223,6 +212,7 @@ - [Reference](/reference) - [Nx Configuration](/reference/nx-json) - [Project Configuration](/reference/project-configuration) + - [Inputs and Named Inputs](/reference/inputs) - [.nxignore](/reference/nxignore) - [Environment Variables](/reference/environment-variables) - [Glossary](/reference/glossary) @@ -234,6 +224,8 @@ - [Workspace Executors](/deprecated/workspace-executors) - [defaultCollection](/deprecated/default-collection) - [runtimeCacheInputs](/deprecated/runtime-cache-inputs) + - [cacheableOperations](/deprecated/cacheable-operations) + - [npmScope](/deprecated/npm-scope) - [globalImplicitDependencies](/deprecated/global-implicit-dependencies) - [Angular Schematics and Builders](/deprecated/angular-schematics-builders) - [Storybook deprecated docs](/deprecated/storybook) @@ -275,11 +267,13 @@ - [Circle CI with Nx](/ci/intro/tutorials/circle) - [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) - [Features](/ci/features) - - [Use Remote Caching](/ci/features/remote-cache) - [Run Only Tasks Affected by a PR](/ci/features/affected) - - [Distribute Task Execution](/ci/features/distribute-task-execution) + - [Use Remote Caching (Nx Replay)](/ci/features/remote-cache) + - [Distribute Task Execution (Nx Agents)](/ci/features/distribute-task-execution) + - [Dynamically Allocate Agents](/ci/features/dynamic-agents) + - [Automatically Split E2E Tasks](/ci/features/split-e2e-tasks) + - [Identify and Re-run Flaky Tasks](/ci/features/flaky-tasks) - [Set up Nx Cloud On-Premise](/ci/features/on-premise) - - [Nx Agents](/ci/features/nx-agents) - [Concepts](/ci/concepts) - [The Building Blocks of Fast CI](/ci/concepts/building-blocks-fast-ci) - [Reduce Wasted Time in CI](/ci/concepts/reduce-waste) @@ -287,6 +281,7 @@ - [Cache Security](/ci/concepts/cache-security) - [Recipes](/ci/recipes) - [Set Up CI](/ci/recipes/set-up) + - [Connect Nx Cloud](/ci/recipes/set-up/connect-to-cloud) - [Setting up Azure Pipelines](/ci/recipes/set-up/monorepo-ci-azure) - [Setting up CircleCI](/ci/recipes/set-up/monorepo-ci-circle-ci) - [Setting up GitHub Actions](/ci/recipes/set-up/monorepo-ci-github-actions) @@ -316,6 +311,7 @@ - [Reference](/ci/reference) - [Configuration Options](/ci/reference/config) - [nx-cloud CLI](/ci/reference/nx-cloud-cli) + - [Launch Templates](/ci/reference/launch-templates) - [Environment Variables](/ci/reference/env-vars) - [Server API Reference](/ci/reference/server-api) - [Release Notes](/ci/reference/release-notes) @@ -646,7 +642,6 @@ - [storybook-configuration](/nx-api/remix/generators/storybook-configuration) - [meta](/nx-api/remix/generators/meta) - [error-boundary](/nx-api/remix/generators/error-boundary) - - [cypress](/nx-api/remix/generators/cypress) - [rollup](/nx-api/rollup) - [executors](/nx-api/rollup/executors) - [rollup](/nx-api/rollup/executors/rollup) diff --git a/docs/shared/using-nx/affected.md b/docs/shared/using-nx/affected.md index f78cf39c04e8f..991d6f021a698 100644 --- a/docs/shared/using-nx/affected.md +++ b/docs/shared/using-nx/affected.md @@ -205,7 +205,7 @@ For instance, if my PR changes `lib10`, and we then run `nx affected -t test`, N ## Visualize Affected Projects -You can also visualize the affected projects using the [Nx graph](/core-features/explore-graph). Simply run: +You can also visualize the affected projects using the [Nx graph](/features/explore-graph). Simply run: ```shell nx affected:graph @@ -213,7 +213,7 @@ nx affected:graph ## Specify Which SHAs to Use to Calculate Affected Code -To understand which projects are affected, Nx uses the Git history and the [project graph](/core-features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. +To understand which projects are affected, Nx uses the Git history and the [project graph](/features/explore-graph). Git knows which files changed, and the Nx project graph knows which projects those files belong to. The affected command takes a `base` and `head` commit. The default `base` is your `main` branch and the default `head` is your current file system. This is generally what you want when developing locally, but in CI, you need to customize these values. diff --git a/docs/shared/vue-standalone-tutorial/vue-standalone.md b/docs/shared/vue-standalone-tutorial/vue-standalone.md index d6c2e1ef93cfa..950a414ae787f 100644 --- a/docs/shared/vue-standalone-tutorial/vue-standalone.md +++ b/docs/shared/vue-standalone-tutorial/vue-standalone.md @@ -30,7 +30,7 @@ Create a new Vue application with the following command: ✔ Test runner to use for end to end (E2E) tests · cypress ✔ Default stylesheet format · css -✔ Do you want Nx Cloud to make your CI fast? · Yes +✔ Set up CI with caching, distribution and test deflaking · github > NX Creating your v17.0.0 workspace. @@ -81,10 +81,10 @@ The setup includes.. Let me explain a couple of things that might be new to you. -| File | Description | -| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `nx.json` | This is where we fine-tune how Nx works. We define what [cacheable operations](/core-features/cache-task-results) there are, and configure our [task pipeline](/concepts/task-pipeline-configuration). More on that soon. | -| `project.json` | This file contains the targets that can be invoked for the `myvueapp` project. It is like a more evolved version of simple `package.json` scripts with more metadata attached. You can read more about it [here](/reference/project-configuration). | +| File | Description | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `nx.json` | This is where we fine-tune how Nx works. We define what [cacheable operations](/features/cache-task-results) there are, and configure our [task pipeline](/concepts/task-pipeline-configuration). More on that soon. | +| `project.json` | This file is where you can modify the inferred tasks for the `myvueapp` project. More about this later. | ## Serving the App @@ -116,64 +116,94 @@ Nx uses the following syntax to run tasks: ![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) -All targets, such as `serve`, `build`, `test` or your custom ones, are defined in the `project.json` file. +### Inferred Tasks -```json {% fileName="project.json"} -{ - "name": "myvueapp", - ... - "targets": { - "lint": { ... }, - "build": { ... }, - "serve": { ... }, - "preview": { ... }, - "test": { ... }, - "serve-static": { ... }, - }, -} +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/features/integrate-with-editors) project detail view or run: + +```shell +nx show project myvueapp --web ``` -Each target contains a configuration object that tells Nx how to run that target. +{% project-details title="Project Details View (Simplified)" height="100px" %} -```json {% fileName="project.json"} +```json { - "name": "myvueapp", - ... - "targets": { - "serve": { - "executor": "@nx/vite:dev-server", - "defaultConfiguration": "development", - "options": { - "buildTarget": "myvueapp:build" - }, - "configurations": { - "development": { - "buildTarget": "myvueapp:build:development", - "hmr": true - }, - "production": { - "buildTarget": "myvueapp:build:production", - "hmr": false + "project": { + "name": "myvueapp", + "data": { + "root": ".", + "includedScripts": [], + "name": "myvueapp", + "targets": { + "build": { + "options": { + "cwd": ".", + "command": "vite build" + }, + "cache": true, + "dependsOn": ["^build"], + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["vite"] + } + ], + "outputs": ["{projectRoot}/dist/myvueapp"], + "executor": "nx:run-commands", + "configurations": {} } - } - }, - ... + }, + "sourceRoot": "./src", + "projectType": "application", + "$schema": "node_modules/nx/schemas/project-schema.json", + "implicitDependencies": [], + "tags": [] + } }, + "sourceMap": { + "root": ["project.json", "nx/core/project-json"], + "includedScripts": ["package.json", "nx/core/package-json-workspaces"], + "name": ["project.json", "nx/core/project-json"], + "targets": ["project.json", "nx/core/project-json"], + "targets.build": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.command": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.options": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.cache": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.dependsOn": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.inputs": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.outputs": ["vite.config.ts", "@nx/vite/plugin"], + "targets.build.options.cwd": ["vite.config.ts", "@nx/vite/plugin"], + "sourceRoot": ["project.json", "nx/core/project-json"], + "projectType": ["project.json", "nx/core/project-json"], + "$schema": ["project.json", "nx/core/project-json"] + } } ``` -The most critical parts are: +{% /project-details %} + +If you expand the `build` task, you can see that it was created by the `@nx/vite` plugin by analyzing your `vite.config.ts` file. Notice the outputs are defined as `{projectRoot}/dist/myvueapp`. This value is being read from the `build.outDir` defined in your `vite.config.ts` file. Let's change that value in your `vite.config.ts` file: + +```ts {% fileName="vite.config.ts" %} +export default defineConfig({ + // ... + build: { + outDir: './build/myvueapp', + // ... + }, +}); +``` -- `executor` - this is of the syntax `:`, where the `plugin` is an NPM package containing an [Nx Plugin](/extending-nx/intro/getting-started) and `` points to a function that runs the task. In this case, the `@nx/vite` plugin contains the `dev-server` executor which serves the Vue app using Vite. -- `options` - these are additional properties and flags passed to the executor function to customize it +Now if you look at the project details view, the outputs for the build target will say `{projectRoot}/build/myvueapp`. This feature ensures that Nx will always cache the correct files. -Learn more about how to [run tasks with Nx](/core-features/run-tasks). +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. ## Testing and Linting - Running Multiple Tasks -Our current setup not only has targets for serving and building the Vue application, but also has targets for unit testing, e2e testing and linting. Again, these are defined in the `project.json` file. We can use the same syntax as before to run these tasks: +Our current setup not only has targets for serving and building the Vue application, but also has targets for unit testing, e2e testing and linting. We can use the same syntax as before to run these tasks: ```bash nx test # runs tests using Jest @@ -199,7 +229,7 @@ More conveniently, we can also run them in parallel using the following syntax: -One thing to highlight is that Nx is able to [cache the tasks you run](/core-features/cache-task-results). +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. @@ -217,15 +247,15 @@ Note that all of these targets are automatically cached by Nx. If you re-run a s Nx read the output from the cache instead of running the command for 4 out of 4 tasks. ``` -Not all tasks might be cacheable though. You can mark all targets of a certain type as cacheable by setting `cache` to `true` in the `targetDefaults` of the `nx.json` file. You can also [learn more about how caching works](/core-features/cache-task-results). +Not all tasks might be cacheable though. You can mark all targets of a certain type as cacheable by setting `cache` to `true` in the `targetDefaults` of the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). ## Nx Plugins? Why? -One thing you might be curious about is the project.json. You may wonder why we define tasks inside the `project.json` file instead of using the `package.json` file with scripts that directly launch Vite. +One thing you might be curious about is the [inferred tasks](/concepts/inferred-tasks). You may wonder why we are detecting tasks from your tooling configuration instead of directly defining them in `package.json` scripts or in the `project.json` file. -Nx understands and supports both approaches, allowing you to define targets either in your `package.json` or `project.json` files. While both serve a similar purpose, the `project.json` file can be seen as an advanced form of `package.json` scripts, providing additional metadata and capabilities. In this tutorial, we utilize the `project.json` approach primarily because we take advantage of Nx Plugins. +Nx understands and supports both approaches, allowing you to define tasks in your `package.json` and `project.json` files or have Nx plugins automatically detect them. The inferred tasks give you the benefit of automatically setting the Nx cache settings for you based on your tooling configuration. In this tutorial, we take advantage of those inferred tasks to demonstrate the full value of Nx plugins. So, what are Nx Plugins? Nx Plugins are optional packages that extend the capabilities of Nx, catering to various specific technologies. For instance, we have plugins tailored to Vue (e.g., `@nx/vue`), Vite (`@nx/vite`), Cypress (`@nx/cypress`), and more. These plugins offer additional features, making your development experience more efficient and enjoyable when working with specific tech stacks. @@ -235,7 +265,7 @@ So, what are Nx Plugins? Nx Plugins are optional packages that extend the capabi -You can just create new Vue components as you normally would. However, Nx plugins usually also ship [generators](/core-features/plugin-features/use-code-generators). They allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/vue` plugin ships, run the following command and inspect the output: +You can just create new Vue components as you normally would. However, Nx plugins usually also ship [generators](/features/generate-code). They allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/vue` plugin ships, run the following command and inspect the output: ```{% command="npx nx list @nx/vue" path="myvueapp" %} @@ -256,7 +286,7 @@ You can just create new Vue components as you normally would. However, Nx plugin If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. -More info can be found in [the integrate with editors article](/core-features/integrate-with-editors). +More info can be found in [the integrate with editors article](/features/integrate-with-editors). {% /callout %} @@ -415,7 +445,8 @@ Running the above commands should lead to the following directory structure: Each of these libraries -- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `nx test orders`) +- has a project details view where you can see the available tasks (e.g. running tests for just orders: `nx test orders`) +- has its own `project.json` file where you can customize targets - has a dedicated `index.ts` file which is the "public API" of the library - is mapped in the `tsconfig.base.json` at the root of the workspace @@ -439,30 +470,36 @@ All libraries that we generate automatically have aliases created in the root-le } ``` -Hence we can easily import them into other libraries and our Vue application. For example: let's use our existing `Products` component in `modules/products/src/lib/products.vue`: +Hence we can easily import them into other libraries and our Vue application. As an example, let's create and expose a `ProductList` component from our `modules/products` library. Either create it by hand or run + +```shell +nx g @nx/vue:component product-list --directory=modules/products/src/product-list +``` -```vue {% fileName="modules/products/src/lib/products.vue" %} +We don't need to implement anything fancy as we just want to learn how to import it into our main Vue application. + +```tsx {% fileName="modules/products/src/product-list/product-list.vue" %} ``` -Make sure the `Products` component is exported via the `index.ts` file of our `products` library (which it should already be). The `modules/products/src/index.ts` file is the public API for the `products` library with the rest of the workspace. Only export what's really necessary to be usable outside the library itself. +Make sure the `ProductList` is exported via the `index.ts` file of our `products` library. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself. ```ts {% fileName="modules/products/src/index.ts" %} -export { default as Products } from './lib/products.vue'; +export { default as ProductList } from './product-list/product-list.vue'; ``` We're ready to import it into our main application now. First, let's set up the Vue Router. ```shell -npm install vue-router --legacy-peer-deps +npm add vue-router ``` Configure it in the `main.ts` file. @@ -479,7 +516,7 @@ const routes = [ { path: '/', component: NxWelcome }, { path: '/products', - component: () => import('@myvueapp/products').then((m) => m.Products), + component: () => import('@myvueapp/products').then((m) => m.ProductList), }, ]; @@ -517,11 +554,11 @@ import { RouterLink, RouterView } from 'vue-router'; ``` -If you now navigate to [http://localhost:4200/#/products](http://localhost:4200/#/products) you should see the `Products` component being rendered. +If you now navigate to [http://localhost:4200/#/products](http://localhost:4200/#/products) you should see the `ProductList` component being rendered. ![Browser screenshot of navigating to the products route](/shared/images/tutorial-vue-standalone/vue-tutorial-products-route.png) -Let's do the same process for our `orders` library. Import the `Orders` component into the `main.ts` routes: +Let's do the same process for our `orders` library. Create an `OrderList` component and import it into the `main.ts` routes: ```ts {% fileName="src/main.ts" %} import './styles.css'; @@ -535,11 +572,11 @@ const routes = [ { path: '/', component: NxWelcome }, { path: '/products', - component: () => import('@myvueapp/products').then((m) => m.Products), + component: () => import('@myvueapp/products').then((m) => m.ProductList), }, { path: '/orders', - component: () => import('@myvueapp/orders').then((m) => m.Orders), + component: () => import('@myvueapp/orders').then((m) => m.OrderList), }, ]; @@ -588,7 +625,7 @@ Note that both the `Products` component and `Orders` component are lazy loaded s -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/core-features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/core-features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: @@ -821,7 +858,7 @@ If you lint your workspace you'll get an error now: ``` -Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries). +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). ## Migrating to a Monorepo @@ -834,7 +871,7 @@ Congrats, you made it!! You now know how to leverage the Nx standalone applicati Here's some more things you can dive into next: - Learn more about the [underlying mental model of Nx](/concepts/mental-model) -- [Speed up CI: Run only tasks for project that got changed](/core-features/run-tasks#run-tasks-affected-by-a-pr) +- [Speed up CI: Run only tasks for project that got changed](/features/run-tasks#run-tasks-affected-by-a-pr) - [Speed up CI: Share your cache](/ci/features/remote-cache) - [Speed up CI: Distribute your tasks across machines](/ci/features/distribute-task-execution) diff --git a/docs/shared/workspace/creating-libraries.md b/docs/shared/workspace/creating-libraries.md index 531feb25e0f14..d6c2ebbddf840 100644 --- a/docs/shared/workspace/creating-libraries.md +++ b/docs/shared/workspace/creating-libraries.md @@ -16,7 +16,7 @@ The `nx graph` command generates a graph of how apps and libraries depend on eac ### 3. Enforcing Constraints -You can enforce constraints on how different types of libraries depend on each other [using tags](/core-features/enforce-module-boundaries). Following pre-determined conventions on what kind of code can go in different types of libraries allows your tagging system to enforce good architectural patterns. +You can enforce constraints on how different types of libraries depend on each other [using tags](/features/enforce-module-boundaries). Following pre-determined conventions on what kind of code can go in different types of libraries allows your tagging system to enforce good architectural patterns. Also, each library defines its own API, which allows for encapsulating logic that other parts of codebase can not access. You can even use a [CODEOWNERS file](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners) to assign ownership of a certain library to a user or team. diff --git a/e2e/angular-core/src/ng-add.test.ts b/e2e/angular-core/src/ng-add.test.ts index 30bc5ef938fd4..cef8af5613a72 100644 --- a/e2e/angular-core/src/ng-add.test.ts +++ b/e2e/angular-core/src/ng-add.test.ts @@ -411,14 +411,14 @@ describe('convert Angular CLI workspace to an Nx workspace', () => { let output = runCLI(`lint ${project}`); expect(output).toContain(`> nx run ${project}:lint`); - expect(output).toContain('All files pass linting.'); + expect(output).toContain('All files pass linting'); expect(output).toContain( `Successfully ran target lint for project ${project}` ); output = runCLI(`lint ${project}`); expect(output).toContain(`> nx run ${project}:lint [local cache]`); - expect(output).toContain('All files pass linting.'); + expect(output).toContain('All files pass linting'); expect(output).toContain( `Successfully ran target lint for project ${project}` ); diff --git a/e2e/angular-core/src/projects.test.ts b/e2e/angular-core/src/projects.test.ts index c30eb14951504..5e9435ba2fcb7 100644 --- a/e2e/angular-core/src/projects.test.ts +++ b/e2e/angular-core/src/projects.test.ts @@ -4,7 +4,7 @@ import { checkFilesExist, cleanupProject, getSize, - killPorts, + killPort, killProcessAndPorts, newProject, readFile, @@ -40,7 +40,7 @@ describe('Angular Projects', () => { `generate @nx/angular:app ${esbuildApp} --bundler=esbuild --no-standalone --project-name-and-root-format=as-provided --no-interactive` ); runCLI( - `generate @nx/angular:lib ${lib1} --no-standalone --add-module-spec --project-name-and-root-format=as-provided --no-interactive` + `generate @nx/angular:lib ${lib1} --project-name-and-root-format=as-provided --no-interactive` ); app1DefaultModule = readFile(`${app1}/src/app/app.module.ts`); app1DefaultComponentTemplate = readFile( @@ -89,13 +89,13 @@ describe('Angular Projects', () => { import { AppComponent } from './app.component'; import { appRoutes } from './app.routes'; import { NxWelcomeComponent } from './nx-welcome.component'; - import { ${names(lib1).className}Module } from '@${proj}/${lib1}'; + import { ${names(lib1).className}Component } from '@${proj}/${lib1}'; @NgModule({ imports: [ BrowserModule, RouterModule.forRoot(appRoutes, { initialNavigation: 'enabledBlocking' }), - ${names(lib1).className}Module + ${names(lib1).className}Component ], declarations: [AppComponent, NxWelcomeComponent], bootstrap: [AppComponent] @@ -126,13 +126,22 @@ describe('Angular Projects', () => { ); // check e2e tests + let appPort = 4958; + updateJson(join(app1, 'project.json'), (config) => { + config.targets.serve.options ??= {}; + config.targets.serve.options.port = appPort; + return config; + }); if (runE2ETests()) { - const e2eResults = runCLI(`e2e ${app1}-e2e --no-watch`); + const e2eResults = runCLI( + `e2e ${app1}-e2e --config baseUrl=http://localhost:${appPort}` + ); expect(e2eResults).toContain('All specs passed!'); - expect(await killPorts()).toBeTruthy(); + // TODO(leo): check why the port is not being killed and add assertion after fixing it + await killPort(appPort); } - const appPort = 4207; + appPort = 4207; const process = await runCommandUntil( `serve ${app1} -- --port=${appPort}`, (output) => output.includes(`listening on localhost:${appPort}`) @@ -165,7 +174,7 @@ describe('Angular Projects', () => { expect(e2eResults).toContain( `Successfully ran target e2e for project ${app}-e2e` ); - expect(await killPorts()).toBeTruthy(); + expect(await killPort(4200)).toBeTruthy(); } }, 1000000); @@ -218,7 +227,8 @@ describe('Angular Projects', () => { removeFile(`${app1}/src/app/inline-template.component.ts`); }, 1000000); - it('should build the dependent buildable lib and its child lib, as well as the app', async () => { + // TODO(crystal, @jaysoo): enable this test when buildable libs work + xit('should build the dependent buildable lib and its child lib, as well as the app', async () => { // ARRANGE const buildableLib = uniq('buildlib1'); const buildableChildLib = uniq('buildlib2'); @@ -505,13 +515,13 @@ describe('Angular Projects', () => { ); runCLI( - `generate @nx/angular:lib ${libName} --no-standalone --buildable --project-name-and-root-format=derived` + `generate @nx/angular:lib ${libName} --standalone --buildable --project-name-and-root-format=derived` ); // check files are generated with the layout directory ("libs/") checkFilesExist( `libs/${libName}/src/index.ts`, - `libs/${libName}/src/lib/${libName}.module.ts` + `libs/${libName}/src/lib/${libName}/${libName}.component.ts` ); // check build works expect(runCLI(`build ${libName}`)).toContain( @@ -535,14 +545,16 @@ describe('Angular Projects', () => { ).toThrow(); runCLI( - `generate @nx/angular:lib ${libName} --buildable --no-standalone --project-name-and-root-format=as-provided` + `generate @nx/angular:lib ${libName} --buildable --standalone --project-name-and-root-format=as-provided` ); // check files are generated without the layout directory ("libs/") and // using the project name as the directory when no directory is provided checkFilesExist( `${libName}/src/index.ts`, - `${libName}/src/lib/${libName.split('/')[1]}.module.ts` + `${libName}/src/lib/${libName.split('/')[1]}/${ + libName.split('/')[1] + }.component.ts` ); // check build works expect(runCLI(`build ${libName}`)).toContain( diff --git a/e2e/angular-extensions/src/cypress-component-tests.test.ts b/e2e/angular-extensions/src/cypress-component-tests.test.ts index bf663b82e4b82..abb9faf10d860 100644 --- a/e2e/angular-extensions/src/cypress-component-tests.test.ts +++ b/e2e/angular-extensions/src/cypress-component-tests.test.ts @@ -43,7 +43,7 @@ describe('Angular Cypress Component Tests', () => { `generate @nx/angular:cypress-component-configuration --project=${appName} --generate-tests --no-interactive` ); if (runE2ETests()) { - expect(runCLI(`component-test ${appName} --no-watch`)).toContain( + expect(runCLI(`component-test ${appName}`)).toContain( 'All specs passed!' ); } @@ -54,7 +54,7 @@ describe('Angular Cypress Component Tests', () => { `generate @nx/angular:cypress-component-configuration --project=${usedInAppLibName} --generate-tests --no-interactive` ); if (runE2ETests()) { - expect(runCLI(`component-test ${usedInAppLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${usedInAppLibName}`)).toContain( 'All specs passed!' ); } @@ -74,7 +74,7 @@ describe('Angular Cypress Component Tests', () => { `generate @nx/angular:cypress-component-configuration --project=${buildableLibName} --generate-tests --build-target=${appName}:build --no-interactive` ); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); } @@ -96,7 +96,7 @@ describe('Angular Cypress Component Tests', () => { ); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); checkFilesDoNotExist(`tmp${buildableLibName}/ct-styles.css`); @@ -112,7 +112,7 @@ describe('Angular Cypress Component Tests', () => { updateBuilableLibTestsToAssertAppStyles(appName, buildableLibName); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); } @@ -124,7 +124,7 @@ describe('Angular Cypress Component Tests', () => { checkFilesDoNotExist(`${buildableLibName}/tailwind.config.js`); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); } diff --git a/e2e/cypress/src/cypress-legacy.test.ts b/e2e/cypress/src/cypress-legacy.test.ts new file mode 100644 index 0000000000000..9977bc9c8297d --- /dev/null +++ b/e2e/cypress/src/cypress-legacy.test.ts @@ -0,0 +1,74 @@ +import { + cleanupProject, + killPort, + newProject, + runCLI, + runE2ETests, + uniq, +} from '@nx/e2e/utils'; + +const TEN_MINS_MS = 600_000; + +// TODO(crystal, @leosvelperez): Still need to investigate why this is failing on CI +xdescribe('Cypress E2E Test runner (legacy)', () => { + beforeAll(() => { + newProject({ packages: ['@nx/angular', '@nx/react'] }); + }); + + afterAll(() => cleanupProject()); + + it( + 'should run e2e in parallel', + async () => { + const ngApp1 = uniq('ng-app1'); + const ngApp2 = uniq('ng-app2'); + runCLI( + `generate @nx/angular:app ${ngApp1} --e2eTestRunner=cypress --linter=eslint --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI( + `generate @nx/angular:app ${ngApp2} --e2eTestRunner=cypress --linter=eslint --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + + if (runE2ETests('cypress')) { + const results = runCLI( + `run-many --target=e2e --parallel=2 --port=cypress-auto --output-style=stream` + ); + expect(results).toContain('Successfully ran target e2e for 2 projects'); + } + }, + TEN_MINS_MS + ); + + xit( + `should allow CT and e2e in same project - react`, + async () => { + const appName = uniq(`react-cy-app`); + runCLI( + `generate @nx/react:app ${appName} --e2eTestRunner=none --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI( + `generate @nx/react:component btn --project=${appName} --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI( + `generate @nx/react:cypress-component-configuration --project=${appName} --generate-tests --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI(`generate @nx/cypress:e2e --project=${appName} --no-interactive`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + + if (runE2ETests('cypress')) { + expect(runCLI(`run ${appName}:component-test`)).toContain( + 'All specs passed!' + ); + expect(runCLI(`run ${appName}:e2e`)).toContain('All specs passed!'); + } + expect(await killPort(4200)).toBeTruthy(); + }, + TEN_MINS_MS + ); +}); diff --git a/e2e/cypress/src/cypress.test.ts b/e2e/cypress/src/cypress.test.ts index 3996722b42f58..5a07e8b848eef 100644 --- a/e2e/cypress/src/cypress.test.ts +++ b/e2e/cypress/src/cypress.test.ts @@ -2,7 +2,6 @@ import { checkFilesExist, cleanupProject, createFile, - ensureCypressInstallation, killPort, newProject, readJson, @@ -10,16 +9,15 @@ import { runE2ETests, uniq, updateFile, - updateJson, } from '@nx/e2e/utils'; const TEN_MINS_MS = 600_000; -describe('Cypress E2E Test runner', () => { +// TODO(crystal, @leosvelperez): Still need to investigate why this is failing on CI +xdescribe('Cypress E2E Test runner', () => { const myapp = uniq('myapp'); beforeAll(() => { newProject({ packages: ['@nx/angular', '@nx/next', '@nx/react'] }); - ensureCypressInstallation(); }); afterAll(() => cleanupProject()); @@ -60,15 +58,6 @@ describe('Cypress E2E Test runner', () => { }` ); - updateJson(`apps/${myapp}-e2e/project.json`, (json) => { - json.targets.e2e.options = { - ...json.targets.e2e.options, - env: { - projectJson: 'i am from the nx project json file', - }, - }; - return json; - }); createFile( `apps/${myapp}-e2e/src/e2e/env.cy.ts`, ` @@ -83,20 +72,13 @@ describe('env vars', () => { 'i am from the cypress.env.json file' ); }); - - it('cli args should not merged project.json vars', () => { - assert.equal( - Cypress.env('projectJson'), - undefined - ); - }); });` ); - if (runE2ETests()) { + if (runE2ETests('cypress')) { // contains the correct output and works const run1 = runCLI( - `e2e ${myapp}-e2e --no-watch --env.cliArg="i am from the cli args"` + `e2e ${myapp}-e2e --config \\'{\\"env\\":{\\"cliArg\\":\\"i am from the cli args\\"}}\\'` ); expect(run1).toContain('All specs passed!'); await killPort(4200); @@ -109,8 +91,15 @@ import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; export default defineConfig({ e2e: { - ...nxE2EPreset(__dirname), - fixturesFolder: undefined, + ...nxE2EPreset(__filename, { + cypressDir: 'src', + webServerCommands: { + default: 'nx run ${myapp}:serve', + production: 'nx run ${myapp}:preview', + }, + ciWebServerCommand: 'nx run ${myapp}:serve-static', + }), + baseUrl: 'http://localhost:4200', }, env: { fromCyConfig: 'i am from the cypress config file' @@ -119,7 +108,7 @@ export default defineConfig({ ); const run2 = runCLI( - `e2e ${myapp}-e2e --no-watch --env.cliArg="i am from the cli args"` + `e2e ${myapp}-e2e --config \\'{\\"env\\":{\\"cliArg\\":\\"i am from the cli args\\"}}\\'` ); expect(run2).toContain('All specs passed!'); await killPort(4200); @@ -128,34 +117,27 @@ export default defineConfig({ updateFile( `apps/${myapp}-e2e/src/e2e/env.cy.ts`, ` -describe('env vars', () => { - it('should not have cli args', () => { - assert.equal(Cypress.env('cliArg'), undefined); - }); - - it('should have cypress.env.json vars', () => { - assert.equal( - Cypress.env('cypressEnvJson'), - 'i am from the cypress.env.json file' - ); - }); - - it('should have project.json vars', () => { - assert.equal( - Cypress.env('projectJson'), - 'i am from the nx project json file' - ); - }); - - it('should have cypress config vars', () => { - assert.equal( - Cypress.env('fromCyConfig'), - 'i am from the cypress config file' - ); - }); -});` + describe('env vars', () => { + it('should not have cli args', () => { + assert.equal(Cypress.env('cliArg'), undefined); + }); + + it('should have cypress.env.json vars', () => { + assert.equal( + Cypress.env('cypressEnvJson'), + 'i am from the cypress.env.json file' + ); + }); + + it('should have cypress config vars', () => { + assert.equal( + Cypress.env('fromCyConfig'), + 'i am from the cypress config file' + ); + }); + });` ); - const run3 = runCLI(`e2e ${myapp}-e2e --no-watch`); + const run3 = runCLI(`e2e ${myapp}-e2e`); expect(run3).toContain('All specs passed!'); expect(await killPort(4200)).toBeTruthy(); @@ -165,61 +147,58 @@ describe('env vars', () => { ); it( - 'should run e2e in parallel', + `should allow CT and e2e in same project for a next project`, async () => { - const ngAppName = uniq('ng-app'); + const appName = uniq('next-cy-app'); + runCLI( + `generate @nx/next:app ${appName} --e2eTestRunner=none --no-interactive` + ); runCLI( - `generate @nx/angular:app ${ngAppName} --e2eTestRunner=cypress --linter=eslint --no-interactive` + `generate @nx/next:component btn --project=${appName} --no-interactive` + ); + runCLI( + `generate @nx/next:cypress-component-configuration --project=${appName} --generate-tests --no-interactive` + ); + runCLI( + `generate @nx/cypress:configuration --project=${appName} --devServerTarget=${appName}:dev --baseUrl=http://localhost:3000 --no-interactive` ); - if (runE2ETests()) { - const results = runCLI( - `run-many --target=e2e --parallel=2 --port=cypress-auto --output-style=stream` + if (runE2ETests('cypress')) { + expect(runCLI(`run ${appName}:component-test`)).toContain( + 'All specs passed!' ); - expect(results).toContain('Successfully ran target e2e for 2 projects'); + expect(runCLI(`run ${appName}:e2e`)).toContain('All specs passed!'); } + expect(await killPort(4200)).toBeTruthy(); }, TEN_MINS_MS ); - it.each(['react', 'next', 'angular'])( - `should allow CT and e2e in same project - %s`, - async (framework: 'react' | 'next' | 'angular') => { - await testCtAndE2eInProject(framework); + it( + `should allow CT and e2e in same project for an angular project`, + async () => { + let appName = uniq(`angular-cy-app`); + runCLI( + `generate @nx/angular:app ${appName} --e2eTestRunner=none --no-interactive --bundler=webpack` + ); + runCLI( + `generate @nx/angular:component btn --project=${appName} --no-interactive` + ); + runCLI( + `generate @nx/angular:cypress-component-configuration --project=${appName} --generate-tests --no-interactive` + ); + runCLI( + `generate @nx/cypress:e2e --project=${appName} --baseUrl=http://localhost:4200 --no-interactive` + ); + + if (runE2ETests('cypress')) { + expect(runCLI(`run ${appName}:component-test`)).toContain( + 'All specs passed!' + ); + expect(runCLI(`run ${appName}:e2e`)).toContain('All specs passed!'); + } + expect(await killPort(4200)).toBeTruthy(); }, TEN_MINS_MS ); }); - -async function testCtAndE2eInProject( - projectType: 'react' | 'next' | 'angular' -) { - let appName = uniq(`${projectType}-cy-app`); - runCLI( - `generate @nx/${projectType}:app ${appName} --e2eTestRunner=none --no-interactive ${ - projectType === 'angular' ? '--bundler=webpack' : '' - }` - ); - runCLI( - `generate @nx/${projectType}:component btn --project=${appName} --no-interactive` - ); - - runCLI( - `generate @nx/${projectType}:cypress-component-configuration --project=${appName} --generate-tests --no-interactive` - ); - - if (runE2ETests()) { - expect(runCLI(`run ${appName}:component-test --no-watch`)).toContain( - 'All specs passed!' - ); - } - - runCLI(`generate @nx/cypress:e2e --project=${appName} --no-interactive`); - - if (runE2ETests()) { - expect(runCLI(`run ${appName}:e2e --no-watch`)).toContain( - 'All specs passed!' - ); - } - expect(await killPort(4200)).toBeTruthy(); -} diff --git a/e2e/detox/src/detox-legacy.test.ts b/e2e/detox/src/detox-legacy.test.ts new file mode 100644 index 0000000000000..5a8dd5bf88b86 --- /dev/null +++ b/e2e/detox/src/detox-legacy.test.ts @@ -0,0 +1,94 @@ +import { + checkFilesExist, + isOSX, + newProject, + runCLI, + runCLIAsync, + uniq, + killPorts, + cleanupProject, +} from '@nx/e2e/utils'; + +describe('@nx/detox (legacy)', () => { + const appName = uniq('myapp'); + + beforeAll(() => { + newProject(); + }); + + afterAll(() => cleanupProject()); + + it('should create files and run lint command for react-native apps', async () => { + runCLI( + `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + checkFilesExist(`apps/${appName}-e2e/.detoxrc.json`); + checkFilesExist(`apps/${appName}-e2e/tsconfig.json`); + checkFilesExist(`apps/${appName}-e2e/tsconfig.e2e.json`); + checkFilesExist(`apps/${appName}-e2e/test-setup.ts`); + checkFilesExist(`apps/${appName}-e2e/src/app.spec.ts`); + + const lintResults = await runCLIAsync(`lint ${appName}-e2e`); + expect(lintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + }); + + it('should create files and run lint command for expo apps', async () => { + const expoAppName = uniq('myapp'); + runCLI( + `generate @nx/expo:app ${expoAppName} --e2eTestRunner=detox --linter=eslint`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + checkFilesExist(`apps/${expoAppName}-e2e/.detoxrc.json`); + checkFilesExist(`apps/${expoAppName}-e2e/tsconfig.json`); + checkFilesExist(`apps/${expoAppName}-e2e/tsconfig.e2e.json`); + checkFilesExist(`apps/${expoAppName}-e2e/test-setup.ts`); + checkFilesExist(`apps/${expoAppName}-e2e/src/app.spec.ts`); + + const lintResults = await runCLIAsync(`lint ${expoAppName}-e2e`); + expect(lintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + }); + + it('should support generating projects with the new name and root format', async () => { + const appName = uniq('app1'); + + runCLI( + `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false --project-name-and-root-format=as-provided --interactive=false`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + + // check files are generated without the layout directory ("apps/") and + // using the project name as the directory when no directory is provided + checkFilesExist( + `${appName}-e2e/.detoxrc.json`, + `${appName}-e2e/tsconfig.json`, + `${appName}-e2e/tsconfig.e2e.json`, + `${appName}-e2e/test-setup.ts`, + `${appName}-e2e/src/app.spec.ts` + ); + + const lintResults = await runCLIAsync(`lint ${appName}-e2e`); + expect(lintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + }); + + // TODO: @xiongemi please fix or remove this test + xdescribe('React Native Detox MACOS-Tests', () => { + if (isOSX()) { + it('should test ios MACOS-Tests', async () => { + expect( + runCLI( + `test-ios ${appName}-e2e --prod --debugSynchronization=true --loglevel=trace` + ) + ).toContain('Successfully ran target test-ios'); + + await killPorts(8081); // kill the port for the serve command + }, 3000000); + } + }); +}); diff --git a/e2e/detox/src/detox-pcv3.test.ts b/e2e/detox/src/detox-pcv3.test.ts deleted file mode 100644 index 2b8a922931b0b..0000000000000 --- a/e2e/detox/src/detox-pcv3.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - runCLI, - cleanupProject, - newProject, - uniq, - readJson, - updateJson, -} from 'e2e/utils'; - -describe('@nx/detox/plugin', () => { - let project: string; - let appName: string; - - beforeAll(() => { - project = newProject(); - appName = uniq('app'); - runCLI( - `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --install=false --project-name-and-root-format=as-provided --interactive=false`, - { env: { NX_PCV3: 'true' } } - ); - updateJson(`${appName}-e2e/.detoxrc.json`, (json) => { - json.apps['e2e.debug'] = { - type: 'ios.app', - build: `echo "building ${appName}"`, - binaryPath: 'dist', - }; - json.configurations['e2e.sim.debug'] = { - device: 'simulator', - app: 'e2e.debug', - }; - return json; - }); - }); - - afterAll(() => cleanupProject()); - - it('nx.json should contain plugin configuration', () => { - const nxJson = readJson('nx.json'); - const detoxPlugin = nxJson.plugins.find( - (plugin) => plugin.plugin === '@nx/detox/plugin' - ); - expect(detoxPlugin).toBeDefined(); - expect(detoxPlugin.options).toBeDefined(); - expect(detoxPlugin.options.buildTargetName).toEqual('build'); - expect(detoxPlugin.options.testTargetName).toEqual('test'); - expect(detoxPlugin.options.startTargetName).toEqual('start'); - }); - - it('should build the app', async () => { - const result = runCLI( - `build ${appName}-e2e -- --configuration e2e.sim.debug` - ); - - expect(result).toContain(`building ${appName}`); - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }, 200_000); -}); diff --git a/e2e/detox/src/detox.test.ts b/e2e/detox/src/detox.test.ts index 5584f17ba37eb..1db9ebac4de95 100644 --- a/e2e/detox/src/detox.test.ts +++ b/e2e/detox/src/detox.test.ts @@ -1,85 +1,58 @@ import { - checkFilesExist, - isOSX, - newProject, runCLI, - runCLIAsync, - uniq, - killPorts, cleanupProject, -} from '@nx/e2e/utils'; + newProject, + uniq, + readJson, + updateJson, +} from 'e2e/utils'; -describe('Detox', () => { - const appName = uniq('myapp'); +describe('@nx/detox', () => { + let project: string; + let appName: string; beforeAll(() => { - newProject(); - }); - - afterAll(() => cleanupProject()); - - it('should create files and run lint command for react-native apps', async () => { + project = newProject(); + appName = uniq('app'); runCLI( - `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false` + `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --install=false --project-name-and-root-format=as-provided --interactive=false` ); - checkFilesExist(`apps/${appName}-e2e/.detoxrc.json`); - checkFilesExist(`apps/${appName}-e2e/tsconfig.json`); - checkFilesExist(`apps/${appName}-e2e/tsconfig.e2e.json`); - checkFilesExist(`apps/${appName}-e2e/test-setup.ts`); - checkFilesExist(`apps/${appName}-e2e/src/app.spec.ts`); - - const lintResults = await runCLIAsync(`lint ${appName}-e2e`); - expect(lintResults.combinedOutput).toContain('All files pass linting'); + updateJson(`${appName}-e2e/.detoxrc.json`, (json) => { + json.apps['e2e.debug'] = { + type: 'ios.app', + build: `echo "building ${appName}"`, + binaryPath: 'dist', + }; + json.configurations['e2e.sim.debug'] = { + device: 'simulator', + app: 'e2e.debug', + }; + return json; + }); }); - it('should create files and run lint command for expo apps', async () => { - const expoAppName = uniq('myapp'); - runCLI( - `generate @nx/expo:app ${expoAppName} --e2eTestRunner=detox --linter=eslint` - ); - checkFilesExist(`apps/${expoAppName}-e2e/.detoxrc.json`); - checkFilesExist(`apps/${expoAppName}-e2e/tsconfig.json`); - checkFilesExist(`apps/${expoAppName}-e2e/tsconfig.e2e.json`); - checkFilesExist(`apps/${expoAppName}-e2e/test-setup.ts`); - checkFilesExist(`apps/${expoAppName}-e2e/src/app.spec.ts`); + afterAll(() => cleanupProject()); - const lintResults = await runCLIAsync(`lint ${expoAppName}-e2e`); - expect(lintResults.combinedOutput).toContain('All files pass linting'); + it('nx.json should contain plugin configuration', () => { + const nxJson = readJson('nx.json'); + const detoxPlugin = nxJson.plugins.find( + (plugin) => plugin.plugin === '@nx/detox/plugin' + ); + expect(detoxPlugin).toBeDefined(); + expect(detoxPlugin.options).toBeDefined(); + expect(detoxPlugin.options.buildTargetName).toEqual('build'); + expect(detoxPlugin.options.testTargetName).toEqual('test'); + expect(detoxPlugin.options.startTargetName).toEqual('start'); }); - it('should support generating projects with the new name and root format', async () => { - const appName = uniq('app1'); - - runCLI( - `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false --project-name-and-root-format=as-provided --interactive=false` + it('should build the app', async () => { + const result = runCLI( + `build ${appName}-e2e -- --configuration e2e.sim.debug` ); - // check files are generated without the layout directory ("apps/") and - // using the project name as the directory when no directory is provided - checkFilesExist( - `${appName}-e2e/.detoxrc.json`, - `${appName}-e2e/tsconfig.json`, - `${appName}-e2e/tsconfig.e2e.json`, - `${appName}-e2e/test-setup.ts`, - `${appName}-e2e/src/app.spec.ts` + expect(result).toContain(`building ${appName}`); + expect(result).toContain( + `Successfully ran target build for project ${appName}` ); - - const lintResults = await runCLIAsync(`lint ${appName}-e2e`); - expect(lintResults.combinedOutput).toContain('All files pass linting'); - }); - - // TODO: @xiongemi please fix or remove this test - xdescribe('React Native Detox MACOS-Tests', () => { - if (isOSX()) { - it('should test ios MACOS-Tests', async () => { - expect( - runCLI( - `test-ios ${appName}-e2e --prod --debugSynchronization=true --loglevel=trace` - ) - ).toContain('Successfully ran target test-ios'); - - await killPorts(8081); // kill the port for the serve command - }, 3000000); - } - }); + }, 200_000); }); diff --git a/e2e/eslint/src/linter-legacy.test.ts b/e2e/eslint/src/linter-legacy.test.ts new file mode 100644 index 0000000000000..178aaf67cda50 --- /dev/null +++ b/e2e/eslint/src/linter-legacy.test.ts @@ -0,0 +1,205 @@ +import { + checkFilesDoNotExist, + checkFilesExist, + cleanupProject, + getSelectedPackageManager, + newProject, + readFile, + readJson, + renameFile, + runCLI, + runCreateWorkspace, + uniq, + updateFile, +} from '@nx/e2e/utils'; + +describe('Linter (legacy)', () => { + describe('Integrated', () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + + let projScope; + + beforeAll(() => { + projScope = newProject({ + packages: ['@nx/react', '@nx/js', '@nx/eslint'], + }); + runCLI(`generate @nx/react:app ${myapp} --tags=validtag`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + runCLI(`generate @nx/js:lib ${mylib}`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + }); + afterAll(() => cleanupProject()); + + describe('linting errors', () => { + let defaultEslintrc; + + beforeAll(() => { + updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`); + defaultEslintrc = readJson('.eslintrc.json'); + }); + afterEach(() => { + updateFile('.eslintrc.json', JSON.stringify(defaultEslintrc, null, 2)); + }); + + it('should check for linting errors', () => { + // create faulty file + updateFile(`apps/${myapp}/src/main.ts`, `console.log("should fail");`); + const eslintrc = readJson('.eslintrc.json'); + + // set the eslint rules to error + eslintrc.overrides.forEach((override) => { + if (override.files.includes('*.ts')) { + override.rules['no-console'] = 'error'; + } + }); + updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2)); + + // 1. linting should error when rules are not followed + let out = runCLI(`lint ${myapp}`, { silenceError: true }); + expect(out).toContain('Unexpected console statement'); + + // 2. linting should not error when rules are not followed and the force flag is specified + expect(() => runCLI(`lint ${myapp} --force`)).not.toThrow(); + + eslintrc.overrides.forEach((override) => { + if (override.files.includes('*.ts')) { + override.rules['no-console'] = undefined; + } + }); + updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2)); + + // 3. linting should not error when all rules are followed + out = runCLI(`lint ${myapp}`, { silenceError: true }); + expect(out).toContain('All files pass linting'); + }, 1000000); + + it('should print the effective configuration for a file specified using --print-config', () => { + const eslint = readJson('.eslintrc.json'); + eslint.overrides.push({ + files: ['src/index.ts'], + rules: { + 'specific-rule': 'off', + }, + }); + updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2)); + const out = runCLI(`lint ${myapp} --print-config src/index.ts`, { + silenceError: true, + }); + expect(out).toContain('"specific-rule": ['); + }, 1000000); + }); + }); + + describe('Flat config', () => { + const packageManager = getSelectedPackageManager() || 'pnpm'; + + beforeEach(() => { + process.env.NX_ADD_PLUGINS = 'false'; + }); + + afterEach(() => { + delete process.env.NX_ADD_PLUGINS; + cleanupProject(); + }); + + it('should convert integrated to flat config', () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + const mylib2 = uniq('mylib2'); + + runCreateWorkspace(myapp, { + preset: 'react-monorepo', + appName: myapp, + style: 'css', + packageManager, + bundler: 'vite', + e2eTestRunner: 'none', + }); + runCLI( + `generate @nx/js:lib ${mylib} --directory libs/${mylib} --projectNameAndRootFormat as-provided`, + { + env: { NX_ADD_PLUGINS: 'false' }, + } + ); + runCLI( + `generate @nx/js:lib ${mylib2} --directory libs/${mylib2} --projectNameAndRootFormat as-provided`, + { + env: { NX_ADD_PLUGINS: 'false' }, + } + ); + + // migrate to flat structure + runCLI(`generate @nx/eslint:convert-to-flat-config`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + checkFilesExist( + 'eslint.config.js', + `apps/${myapp}/eslint.config.js`, + `libs/${mylib}/eslint.config.js`, + `libs/${mylib2}/eslint.config.js` + ); + checkFilesDoNotExist( + '.eslintrc.json', + `apps/${myapp}/.eslintrc.json`, + `libs/${mylib}/.eslintrc.json`, + `libs/${mylib2}/.eslintrc.json` + ); + + // move eslint.config one step up + // to test the absence of the flat eslint config in the project root folder + renameFile(`libs/${mylib2}/eslint.config.js`, `libs/eslint.config.js`); + updateFile( + `libs/eslint.config.js`, + readFile(`libs/eslint.config.js`).replace( + `../../eslint.config.js`, + `../eslint.config.js` + ) + ); + + const outFlat = runCLI(`affected -t lint`, { + silenceError: true, + }); + expect(outFlat).toContain('ran target lint'); + }, 1000000); + + it('should convert standalone to flat config', () => { + const myapp = uniq('myapp'); + const mylib = uniq('mylib'); + + runCreateWorkspace(myapp, { + preset: 'react-standalone', + appName: myapp, + style: 'css', + packageManager, + bundler: 'vite', + e2eTestRunner: 'none', + }); + runCLI(`generate @nx/js:lib ${mylib}`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + + // migrate to flat structure + runCLI(`generate @nx/eslint:convert-to-flat-config`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + checkFilesExist( + 'eslint.config.js', + `${mylib}/eslint.config.js`, + 'eslint.base.config.js' + ); + checkFilesDoNotExist( + '.eslintrc.json', + `${mylib}/.eslintrc.json`, + '.eslintrc.base.json' + ); + + const outFlat = runCLI(`affected -t lint`, { + silenceError: true, + }); + expect(outFlat).toContain('ran target lint'); + }, 1000000); + }); +}); diff --git a/e2e/eslint/src/linter.test.ts b/e2e/eslint/src/linter.test.ts index c6a5b664a667c..4c4eb6dadb2dc 100644 --- a/e2e/eslint/src/linter.test.ts +++ b/e2e/eslint/src/linter.test.ts @@ -1,17 +1,12 @@ import * as path from 'path'; import { - checkFilesDoNotExist, checkFilesExist, cleanupProject, createFile, - getSelectedPackageManager, newProject, readFile, readJson, - renameFile, runCLI, - runCreateWorkspace, - setMaxWorkers, uniq, updateFile, updateJson, @@ -58,13 +53,9 @@ describe('Linter', () => { }); updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2)); - // 1. linting should error when rules are not followed let out = runCLI(`lint ${myapp}`, { silenceError: true }); expect(out).toContain('Unexpected console statement'); - // 2. linting should not error when rules are not followed and the force flag is specified - expect(() => runCLI(`lint ${myapp} --force`)).not.toThrow(); - eslintrc.overrides.forEach((override) => { if (override.files.includes('*.ts')) { override.rules['no-console'] = undefined; @@ -74,7 +65,7 @@ describe('Linter', () => { // 3. linting should not error when all rules are followed out = runCLI(`lint ${myapp}`, { silenceError: true }); - expect(out).toContain('All files pass linting'); + expect(out).toContain('Successfully ran target lint'); }, 1000000); it('should cache eslint with --cache', () => { @@ -86,20 +77,22 @@ describe('Linter', () => { } // should generate a default cache file - expect(() => checkFilesExist(`.eslintcache`)).toThrow(); + let cachePath = path.join('apps', myapp, '.eslintcache'); + expect(() => checkFilesExist(cachePath)).toThrow(); runCLI(`lint ${myapp} --cache`, { silenceError: true }); - expect(() => checkFilesExist(`.eslintcache`)).not.toThrow(); - expect(readCacheFile(`.eslintcache`)).toContain( + expect(() => checkFilesExist(cachePath)).not.toThrow(); + expect(readCacheFile(cachePath)).toContain( path.normalize(`${myapp}/src/app/app.spec.tsx`) ); // should let you specify a cache file location - expect(() => checkFilesExist(`my-cache`)).toThrow(); + cachePath = path.join('apps', myapp, 'my-cache'); + expect(() => checkFilesExist(cachePath)).toThrow(); runCLI(`lint ${myapp} --cache --cache-location="my-cache"`, { silenceError: true, }); - expect(() => checkFilesExist(`my-cache/${myapp}`)).not.toThrow(); - expect(readCacheFile(`my-cache/${myapp}`)).toContain( + expect(() => checkFilesExist(cachePath)).not.toThrow(); + expect(readCacheFile(cachePath)).toContain( path.normalize(`${myapp}/src/app/app.spec.tsx`) ); }); @@ -114,8 +107,9 @@ describe('Linter', () => { updateFile('.eslintrc.json', JSON.stringify(eslintrc, null, 2)); const outputFile = 'a/b/c/lint-output.json'; + const outputFilePath = path.join('apps', myapp, outputFile); expect(() => { - checkFilesExist(outputFile); + checkFilesExist(outputFilePath); }).toThrow(); const stdout = runCLI( `lint ${myapp} --output-file="${outputFile}" --format=json`, @@ -124,8 +118,8 @@ describe('Linter', () => { } ); expect(stdout).not.toContain('Unexpected console statement'); - expect(() => checkFilesExist(outputFile)).not.toThrow(); - const outputContents = JSON.parse(readFile(outputFile)); + expect(() => checkFilesExist(outputFilePath)).not.toThrow(); + const outputContents = JSON.parse(readFile(outputFilePath)); const outputForApp: any = Object.values(outputContents).filter( (result: any) => result.filePath.includes(path.normalize(`${myapp}/src/main.ts`)) @@ -246,21 +240,6 @@ describe('Linter', () => { 'A project tagged with "validtag" can only depend on libs tagged with "validtag"' ); }, 1000000); - - it('should print the effective configuration for a file specified using --printConfig', () => { - const eslint = readJson('.eslintrc.json'); - eslint.overrides.push({ - files: ['src/index.ts'], - rules: { - 'specific-rule': 'off', - }, - }); - updateFile('.eslintrc.json', JSON.stringify(eslint, null, 2)); - const out = runCLI(`lint ${myapp} --printConfig src/index.ts`, { - silenceError: true, - }); - expect(out).toContain('"specific-rule": ['); - }, 1000000); }); describe('workspace boundary rules', () => { @@ -423,7 +402,8 @@ describe('Linter', () => { ); }); - it('should fix noRelativeOrAbsoluteImportsAcrossLibraries', () => { + // TODO(crystal, @meeroslav): Investigate why this is failing + xit('should fix noRelativeOrAbsoluteImportsAcrossLibraries', () => { const stdout = runCLI(`lint ${libB}`, { silenceError: true, }); @@ -469,13 +449,14 @@ describe('Linter', () => { }); }); - it('should report dependency check issues', () => { + // TODO(crystal, @meeroslav): Investigate why this is failing + xit('should report dependency check issues', () => { const rootPackageJson = readJson('package.json'); const nxVersion = rootPackageJson.devDependencies.nx; const tslibVersion = rootPackageJson.dependencies['tslib']; let out = runCLI(`lint ${mylib}`, { silenceError: true }); - expect(out).toContain('All files pass linting'); + expect(out).toContain('Successfully ran target lint'); // make an explict dependency to nx updateFile( @@ -529,97 +510,6 @@ describe('Linter', () => { }); }); - describe('Flat config', () => { - const packageManager = getSelectedPackageManager() || 'pnpm'; - - afterEach(() => cleanupProject()); - - it('should convert integrated to flat config', () => { - const myapp = uniq('myapp'); - const mylib = uniq('mylib'); - const mylib2 = uniq('mylib2'); - - runCreateWorkspace(myapp, { - preset: 'react-monorepo', - appName: myapp, - style: 'css', - packageManager, - bundler: 'vite', - e2eTestRunner: 'none', - }); - runCLI( - `generate @nx/js:lib ${mylib} --directory libs/${mylib} --projectNameAndRootFormat as-provided` - ); - runCLI( - `generate @nx/js:lib ${mylib2} --directory libs/${mylib2} --projectNameAndRootFormat as-provided` - ); - - // migrate to flat structure - runCLI(`generate @nx/eslint:convert-to-flat-config`); - checkFilesExist( - 'eslint.config.js', - `apps/${myapp}/eslint.config.js`, - `libs/${mylib}/eslint.config.js`, - `libs/${mylib2}/eslint.config.js` - ); - checkFilesDoNotExist( - '.eslintrc.json', - `apps/${myapp}/.eslintrc.json`, - `libs/${mylib}/.eslintrc.json`, - `libs/${mylib2}/.eslintrc.json` - ); - - // move eslint.config one step up - // to test the absence of the flat eslint config in the project root folder - renameFile(`libs/${mylib2}/eslint.config.js`, `libs/eslint.config.js`); - updateFile( - `libs/eslint.config.js`, - readFile(`libs/eslint.config.js`).replace( - `../../eslint.config.js`, - `../eslint.config.js` - ) - ); - - const outFlat = runCLI(`affected -t lint`, { - silenceError: true, - }); - expect(outFlat).toContain('ran target lint'); - }, 1000000); - - it('should convert standalone to flat config', () => { - const myapp = uniq('myapp'); - const mylib = uniq('mylib'); - - runCreateWorkspace(myapp, { - preset: 'react-standalone', - appName: myapp, - style: 'css', - packageManager, - bundler: 'vite', - e2eTestRunner: 'none', - }); - runCLI(`generate @nx/js:lib ${mylib}`); - - // migrate to flat structure - runCLI(`generate @nx/eslint:convert-to-flat-config`); - checkFilesExist( - 'eslint.config.js', - `${mylib}/eslint.config.js`, - 'eslint.base.config.js' - ); - checkFilesDoNotExist( - '.eslintrc.json', - `${mylib}/.eslintrc.json`, - '.eslintrc.base.json' - ); - - const outFlat = runCLI(`affected -t lint`, { - silenceError: true, - }); - expect(outFlat).toContain('ran target lint'); - }, 1000000); - }); - describe('Root projects migration', () => { beforeEach(() => newProject({ @@ -630,10 +520,10 @@ describe('Linter', () => { function verifySuccessfulStandaloneSetup(myapp: string) { expect(runCLI(`lint ${myapp}`, { silenceError: true })).toContain( - 'All files pass linting' + 'Successfully ran target lint' ); expect(runCLI(`lint e2e`, { silenceError: true })).toContain( - 'All files pass linting' + 'Successfully ran target lint' ); expect(() => checkFilesExist(`.eslintrc.base.json`)).toThrow(); @@ -647,13 +537,13 @@ describe('Linter', () => { function verifySuccessfulMigratedSetup(myapp: string, mylib: string) { expect(runCLI(`lint ${myapp}`, { silenceError: true })).toContain( - 'All files pass linting' + 'Successfully ran target lint' ); expect(runCLI(`lint e2e`, { silenceError: true })).toContain( - 'All files pass linting' + 'Successfully ran target lint' ); expect(runCLI(`lint ${mylib}`, { silenceError: true })).toContain( - 'All files pass linting' + 'Successfully ran target lint' ); expect(() => checkFilesExist(`.eslintrc.base.json`)).not.toThrow(); @@ -747,7 +637,6 @@ describe('Linter', () => { runCLI( `generate @nx/node:app ${myapp} --rootProject=true --no-interactive` ); - setMaxWorkers('project.json'); verifySuccessfulStandaloneSetup(myapp); let appEslint = readJson('.eslintrc.json'); @@ -777,46 +666,6 @@ describe('Linter', () => { expect(e2eOverrides).not.toContain('plugin:@nx/typescript'); }); }); - - describe('Project Config v3', () => { - let myapp; - - beforeEach(() => { - myapp = uniq('myapp'); - newProject({ - name: uniq('eslint'), - unsetProjectNameAndRootFormat: false, - packages: ['@nx/react'], - }); - }); - - it('should lint example app', () => { - runCLI( - `generate @nx/react:app ${myapp} --directory apps/${myapp} --unitTestRunner=none --bundler=vite --e2eTestRunner=cypress --style=css --no-interactive --projectNameAndRootFormat=as-provided`, - { env: { NX_PCV3: 'true' } } - ); - - let lintResults = runCLI(`lint ${myapp}`); - expect(lintResults).toContain( - `Successfully ran target lint for project ${myapp}` - ); - lintResults = runCLI(`lint ${myapp}-e2e`); - expect(lintResults).toContain( - `Successfully ran target lint for project ${myapp}-e2e` - ); - - const { targets } = readJson(`apps/${myapp}/project.json`); - expect(targets.lint).not.toBeDefined(); - - const { plugins } = readJson('nx.json'); - expect(plugins).toContainEqual({ - plugin: '@nx/eslint/plugin', - options: { - targetName: 'lint', - }, - }); - }); - }); }); /** diff --git a/e2e/expo/src/expo-legacy.test.ts b/e2e/expo/src/expo-legacy.test.ts new file mode 100644 index 0000000000000..2ba7579f4d70f --- /dev/null +++ b/e2e/expo/src/expo-legacy.test.ts @@ -0,0 +1,286 @@ +import { + checkFilesExist, + cleanupProject, + expectTestsPass, + getPackageManagerCommand, + killPorts, + newProject, + promisifiedTreeKill, + readJson, + runCLI, + runCLIAsync, + runCommand, + runCommandUntil, + runE2ETests, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; +import { ChildProcess } from 'child_process'; +import { join } from 'path'; + +describe('@nx/expo (legacy)', () => { + let proj: string; + let appName = uniq('my-app'); + let libName = uniq('lib'); + + beforeAll(() => { + proj = newProject({ packages: ['@nx/expo'] }); + // we create empty preset above which skips creation of `production` named input + updateJson('nx.json', (nxJson) => { + nxJson.namedInputs = { + default: ['{projectRoot}/**/*', 'sharedGlobals'], + production: ['default'], + sharedGlobals: [], + }; + return nxJson; + }); + runCLI( + `generate @nx/expo:application ${appName} --e2eTestRunner=cypress --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI( + `generate @nx/expo:library ${libName} --buildable --publishable --importPath=${proj}/${libName}` + ); + }); + afterAll(() => cleanupProject()); + + it('should test and lint', async () => { + const componentName = uniq('Component'); + + runCLI( + `generate @nx/expo:component ${componentName} --project=${libName} --export --no-interactive` + ); + + updateFile(`apps/${appName}/src/app/App.tsx`, (content) => { + let updated = `// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {${componentName}} from '${proj}/${libName}';\n${content}`; + return updated; + }); + + expectTestsPass(await runCLIAsync(`test ${appName}`)); + expectTestsPass(await runCLIAsync(`test ${libName}`)); + + const appLintResults = await runCLIAsync(`lint ${appName}`); + expect(appLintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + + const libLintResults = await runCLIAsync(`lint ${libName}`); + expect(libLintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + }); + + it('should serve with metro', async () => { + let process: ChildProcess; + const port = 8081; + + try { + process = await runCommandUntil( + `serve ${appName} --interactive=false --port=${port}`, + (output) => { + return ( + output.includes(`http://localhost::${port}`) || + output.includes('Starting JS server...') + ); + } + ); + } catch (err) { + console.error(err); + } + + // port and process cleanup + try { + if (process && process.pid) { + await promisifiedTreeKill(process.pid, 'SIGKILL'); + await killPorts(port); + } + } catch (err) { + expect(err).toBeFalsy(); + } + }); + + it('should export', async () => { + const exportResults = await runCLIAsync( + `export ${appName} --no-interactive` + ); + expect(exportResults.combinedOutput).toContain( + 'Successfully ran target export for project' + ); + checkFilesExist( + `dist/apps/${appName}/index.html`, + `dist/apps/${appName}/metadata.json` + ); + }); + + it('should prebuild', async () => { + // run prebuild command with git check disable + // set a mock package name for ios and android in expo's app.json + const root = `apps/${appName}`; + const appJsonPath = join(root, `app.json`); + const appJson = await readJson(appJsonPath); + if (appJson.expo.ios) { + appJson.expo.ios.bundleIdentifier = 'nx.test'; + } + if (appJson.expo.android) { + appJson.expo.android.package = 'nx.test'; + } + updateFile(appJsonPath, JSON.stringify(appJson)); + + // run prebuild command with git check disable + process.env['EXPO_NO_GIT_STATUS'] = 'true'; + const prebuildResult = await runCLIAsync( + `prebuild ${appName} --no-interactive --install=false` + ); + expect(prebuildResult.combinedOutput).toContain( + 'Successfully ran target prebuild for project' + ); + }); + + // TODO (@xiongemi): this test is disabled due to expo requires typescript ^5.3.0 + // re-enable it when typescript is updated + xit('should install', async () => { + // run install command + const installResults = await runCLIAsync( + `install ${appName} --no-interactive` + ); + expect(installResults.combinedOutput).toContain( + 'Successfully ran target install' + ); + }); + + it('should start', async () => { + // run start command + const startProcess = await runCommandUntil( + `start ${appName} -- --port=8081`, + (output) => output.includes(`http://localhost:8081`) + ); + + // port and process cleanup + try { + await promisifiedTreeKill(startProcess.pid, 'SIGKILL'); + await killPorts(8081); + } catch (err) { + expect(err).toBeFalsy(); + } + }); + + it('should build publishable library', async () => { + expect(() => { + runCLI(`build ${libName}`); + checkFilesExist(`dist/libs/${libName}/index.esm.js`); + checkFilesExist(`dist/libs/${libName}/src/index.d.ts`); + }).not.toThrow(); + }); + + it('should tsc app', async () => { + expect(() => { + const pmc = getPackageManagerCommand(); + runCommand( + `${pmc.runUninstalledPackage} tsc -p apps/${appName}/tsconfig.app.json` + ); + checkFilesExist( + `dist/out-tsc/apps/${appName}/src/app/App.js`, + `dist/out-tsc/apps/${appName}/src/app/App.d.ts`, + `dist/out-tsc/libs/${libName}/src/index.js`, + `dist/out-tsc/libs/${libName}/src/index.d.ts` + ); + }).not.toThrow(); + }); + + it('should support generating projects with the new name and root format', () => { + const appName = uniq('app1'); + const libName = uniq('@my-org/lib1'); + + runCLI( + `generate @nx/expo:application ${appName} --project-name-and-root-format=as-provided --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + + // check files are generated without the layout directory ("apps/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${appName}/src/app/App.tsx`); + // check tests pass + const appTestResult = runCLI(`test ${appName}`); + expect(appTestResult).toContain( + `Successfully ran target test for project ${appName}` + ); + + // assert scoped project names are not supported when --project-name-and-root-format=derived + expect(() => + runCLI( + `generate @nx/expo:library ${libName} --buildable --project-name-and-root-format=derived` + ) + ).toThrow(); + + runCLI( + `generate @nx/expo:library ${libName} --buildable --project-name-and-root-format=as-provided` + ); + + // check files are generated without the layout directory ("libs/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${libName}/src/index.ts`); + // check tests pass + const libTestResult = runCLI(`test ${libName}`); + expect(libTestResult).toContain( + `Successfully ran target test for project ${libName}` + ); + }); + + it('should create storybook with application', async () => { + runCLI( + `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` + ); + checkFilesExist( + `apps/${appName}/.storybook/main.ts`, + `apps/${appName}/src/app/App.stories.tsx` + ); + }); + + it('should run e2e for cypress', async () => { + if (runE2ETests()) { + const results = runCLI(`e2e ${appName}-e2e`); + expect(results).toContain('Successfully ran target e2e'); + + // port and process cleanup + try { + await killPorts(4200); + } catch (err) { + expect(err).toBeFalsy(); + } + } + }); + + it('should run e2e for cypress with configuration ci', async () => { + if (runE2ETests()) { + const results = runCLI(`e2e ${appName}-e2e --configuration=ci`); + expect(results).toContain('Successfully ran target e2e'); + + // port and process cleanup + try { + await killPorts(4200); + } catch (err) { + expect(err).toBeFalsy(); + } + } + }); + + it('should run e2e for playwright', async () => { + const appName2 = uniq('my-app'); + runCLI( + `generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + if (runE2ETests()) { + const results = runCLI(`e2e ${appName2}-e2e`, { verbose: true }); + expect(results).toContain('Successfully ran target e2e'); + + // port and process cleanup + try { + await killPorts(4200); + } catch (err) { + expect(err).toBeFalsy(); + } + } + }); +}); diff --git a/e2e/expo/src/expo-pcv3.test.ts b/e2e/expo/src/expo-pcv3.test.ts deleted file mode 100644 index 6e78195180be0..0000000000000 --- a/e2e/expo/src/expo-pcv3.test.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { ChildProcess } from 'child_process'; -import { - runCLI, - cleanupProject, - newProject, - uniq, - readJson, - runCommandUntil, - killProcessAndPorts, - checkFilesExist, - updateFile, - runCLIAsync, - runE2ETests, - killPorts, -} from 'e2e/utils'; -import { join } from 'path'; - -describe('@nx/expo/plugin', () => { - let appName: string; - - beforeAll(() => { - newProject(); - appName = uniq('app'); - runCLI( - `generate @nx/expo:app ${appName} --project-name-and-root-format=as-provided --no-interactive`, - { env: { NX_PCV3: 'true' } } - ); - }); - - afterAll(() => cleanupProject()); - - it('nx.json should contain plugin configuration', () => { - const nxJson = readJson('nx.json'); - const expoPlugin = nxJson.plugins.find( - (plugin) => plugin.plugin === '@nx/expo/plugin' - ); - expect(expoPlugin).toBeDefined(); - expect(expoPlugin.options).toBeDefined(); - expect(expoPlugin.options.exportTargetName).toEqual('export'); - expect(expoPlugin.options.startTargetName).toEqual('start'); - }); - - it('should export the app', async () => { - const result = runCLI(`export ${appName}`); - checkFilesExist( - `${appName}/dist/index.html`, - `${appName}/dist/metadata.json` - ); - - expect(result).toContain( - `Successfully ran target export for project ${appName}` - ); - }, 200_000); - - it('should start the app', async () => { - let process: ChildProcess; - const port = 8081; - - try { - process = await runCommandUntil( - `start ${appName} -- --port=${port}`, - (output) => output.includes(`http://localhost:8081`) - ); - } catch (err) { - console.error(err); - } - - // port and process cleanup - if (process && process.pid) { - await killProcessAndPorts(process.pid, port); - } - }); - - it('should serve the app', async () => { - let process: ChildProcess; - const port = 8081; - - try { - process = await runCommandUntil( - `serve ${appName} -- --port=${port}`, - (output) => output.includes(`http://localhost:8081`) - ); - } catch (err) { - console.error(err); - } - - // port and process cleanup - if (process && process.pid) { - await killProcessAndPorts(process.pid, port); - } - }); - - it('should prebuild', async () => { - // run prebuild command with git check disable - // set a mock package name for ios and android in expo's app.json - const appJsonPath = join(appName, `app.json`); - const appJson = await readJson(appJsonPath); - if (appJson.expo.ios) { - appJson.expo.ios.bundleIdentifier = 'nx.test'; - } - if (appJson.expo.android) { - appJson.expo.android.package = 'nx.test'; - } - updateFile(appJsonPath, JSON.stringify(appJson)); - - // run prebuild command with git check disable - process.env['EXPO_NO_GIT_STATUS'] = 'true'; - const prebuildResult = await runCLIAsync( - `prebuild ${appName} --no-interactive --install=false` - ); - expect(prebuildResult.combinedOutput).toContain( - 'Successfully ran target prebuild for project' - ); - }); - - it('should run e2e for cypress', async () => { - if (runE2ETests()) { - const results = runCLI(`e2e ${appName}-e2e`); - expect(results).toContain('Successfully ran target e2e'); - - // port and process cleanup - try { - await killPorts(4200); - } catch (err) { - expect(err).toBeFalsy(); - } - } - }); - - it('should create storybook with application', async () => { - runCLI( - `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` - ); - checkFilesExist( - `${appName}/.storybook/main.ts`, - `${appName}/src/app/App.stories.tsx` - ); - }); -}); diff --git a/e2e/expo/src/expo.test.ts b/e2e/expo/src/expo.test.ts index 53fe9d79e6b39..388f5fec1660a 100644 --- a/e2e/expo/src/expo.test.ts +++ b/e2e/expo/src/expo.test.ts @@ -1,119 +1,98 @@ +import { ChildProcess } from 'child_process'; import { - checkFilesExist, + runCLI, cleanupProject, - expectTestsPass, - getPackageManagerCommand, - killPorts, newProject, - promisifiedTreeKill, + uniq, readJson, - runCLI, - runCLIAsync, - runCommand, runCommandUntil, - runE2ETests, - uniq, + killProcessAndPorts, + checkFilesExist, updateFile, - updateJson, -} from '@nx/e2e/utils'; -import { ChildProcess } from 'child_process'; + runCLIAsync, + runE2ETests, + killPorts, +} from 'e2e/utils'; import { join } from 'path'; -describe('expo', () => { - let proj: string; - let appName = uniq('my-app'); - let libName = uniq('lib'); +describe('@nx/expo', () => { + let appName: string; beforeAll(() => { - proj = newProject({ packages: ['@nx/expo'] }); - // we create empty preset above which skips creation of `production` named input - updateJson('nx.json', (nxJson) => { - nxJson.namedInputs = { - default: ['{projectRoot}/**/*', 'sharedGlobals'], - production: ['default'], - sharedGlobals: [], - }; - nxJson.targetDefaults.build.inputs = ['production', '^production']; - return nxJson; - }); + newProject(); + appName = uniq('app'); runCLI( - `generate @nx/expo:application ${appName} --e2eTestRunner=cypress --no-interactive` - ); - runCLI( - `generate @nx/expo:library ${libName} --buildable --publishable --importPath=${proj}/${libName}` + `generate @nx/expo:app ${appName} --project-name-and-root-format=as-provided --no-interactive` ); }); + afterAll(() => cleanupProject()); - it('should test and lint', async () => { - const componentName = uniq('Component'); + it('nx.json should contain plugin configuration', () => { + const nxJson = readJson('nx.json'); + const expoPlugin = nxJson.plugins.find( + (plugin) => plugin.plugin === '@nx/expo/plugin' + ); + expect(expoPlugin).toBeDefined(); + expect(expoPlugin.options).toBeDefined(); + expect(expoPlugin.options.exportTargetName).toEqual('export'); + expect(expoPlugin.options.startTargetName).toEqual('start'); + }); - runCLI( - `generate @nx/expo:component ${componentName} --project=${libName} --export --no-interactive` + it('should export the app', async () => { + const result = runCLI(`export ${appName}`); + checkFilesExist( + `${appName}/dist/index.html`, + `${appName}/dist/metadata.json` ); - updateFile(`apps/${appName}/src/app/App.tsx`, (content) => { - let updated = `// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {${componentName}} from '${proj}/${libName}';\n${content}`; - return updated; - }); + expect(result).toContain( + `Successfully ran target export for project ${appName}` + ); + }, 200_000); - expectTestsPass(await runCLIAsync(`test ${appName}`)); - expectTestsPass(await runCLIAsync(`test ${libName}`)); + it('should start the app', async () => { + let process: ChildProcess; + const port = 8081; - const appLintResults = await runCLIAsync(`lint ${appName}`); - expect(appLintResults.combinedOutput).toContain('All files pass linting.'); + try { + process = await runCommandUntil( + `start ${appName} -- --port=${port}`, + (output) => output.includes(`http://localhost:8081`) + ); + } catch (err) { + console.error(err); + } - const libLintResults = await runCLIAsync(`lint ${libName}`); - expect(libLintResults.combinedOutput).toContain('All files pass linting.'); + // port and process cleanup + if (process && process.pid) { + await killProcessAndPorts(process.pid, port); + } }); - it('should serve with metro', async () => { + it('should serve the app', async () => { let process: ChildProcess; const port = 8081; try { process = await runCommandUntil( - `serve ${appName} --interactive=false --port=${port}`, - (output) => { - return ( - output.includes(`http://localhost::${port}`) || - output.includes('Starting JS server...') - ); - } + `serve ${appName} -- --port=${port}`, + (output) => output.includes(`http://localhost:8081`) ); } catch (err) { console.error(err); } // port and process cleanup - try { - if (process && process.pid) { - await promisifiedTreeKill(process.pid, 'SIGKILL'); - await killPorts(port); - } - } catch (err) { - expect(err).toBeFalsy(); + if (process && process.pid) { + await killProcessAndPorts(process.pid, port); } }); - it('should export', async () => { - const exportResults = await runCLIAsync( - `export ${appName} --no-interactive` - ); - expect(exportResults.combinedOutput).toContain( - 'Successfully ran target export for project' - ); - checkFilesExist( - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/metadata.json` - ); - }); - it('should prebuild', async () => { // run prebuild command with git check disable // set a mock package name for ios and android in expo's app.json - const root = `apps/${appName}`; - const appJsonPath = join(root, `app.json`); + const appJsonPath = join(appName, `app.json`); const appJson = await readJson(appJsonPath); if (appJson.expo.ios) { appJson.expo.ios.bundleIdentifier = 'nx.test'; @@ -133,105 +112,6 @@ describe('expo', () => { ); }); - // TODO (@xiongemi): this test is disabled due to expo requires typescript ^5.3.0 - // re-enable it when typescript is updated - xit('should install', async () => { - // run install command - const installResults = await runCLIAsync( - `install ${appName} --no-interactive` - ); - expect(installResults.combinedOutput).toContain( - 'Successfully ran target install' - ); - }); - - it('should start', async () => { - // run start command - const startProcess = await runCommandUntil( - `start ${appName} -- --port=8081`, - (output) => output.includes(`http://localhost:8081`) - ); - - // port and process cleanup - try { - await promisifiedTreeKill(startProcess.pid, 'SIGKILL'); - await killPorts(8081); - } catch (err) { - expect(err).toBeFalsy(); - } - }); - - it('should build publishable library', async () => { - expect(() => { - runCLI(`build ${libName}`); - checkFilesExist(`dist/libs/${libName}/index.esm.js`); - checkFilesExist(`dist/libs/${libName}/src/index.d.ts`); - }).not.toThrow(); - }); - - it('should tsc app', async () => { - expect(() => { - const pmc = getPackageManagerCommand(); - runCommand( - `${pmc.runUninstalledPackage} tsc -p apps/${appName}/tsconfig.app.json` - ); - checkFilesExist( - `dist/out-tsc/apps/${appName}/src/app/App.js`, - `dist/out-tsc/apps/${appName}/src/app/App.d.ts`, - `dist/out-tsc/libs/${libName}/src/index.js`, - `dist/out-tsc/libs/${libName}/src/index.d.ts` - ); - }).not.toThrow(); - }); - - it('should support generating projects with the new name and root format', () => { - const appName = uniq('app1'); - const libName = uniq('@my-org/lib1'); - - runCLI( - `generate @nx/expo:application ${appName} --project-name-and-root-format=as-provided --no-interactive` - ); - - // check files are generated without the layout directory ("apps/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${appName}/src/app/App.tsx`); - // check tests pass - const appTestResult = runCLI(`test ${appName}`); - expect(appTestResult).toContain( - `Successfully ran target test for project ${appName}` - ); - - // assert scoped project names are not supported when --project-name-and-root-format=derived - expect(() => - runCLI( - `generate @nx/expo:library ${libName} --buildable --project-name-and-root-format=derived` - ) - ).toThrow(); - - runCLI( - `generate @nx/expo:library ${libName} --buildable --project-name-and-root-format=as-provided` - ); - - // check files are generated without the layout directory ("libs/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${libName}/src/index.ts`); - // check tests pass - const libTestResult = runCLI(`test ${libName}`); - expect(libTestResult).toContain( - `Successfully ran target test for project ${libName}` - ); - }); - - it('should create storybook with application', async () => { - runCLI( - `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` - ); - checkFilesExist( - `apps/${appName}/.storybook/main.ts`, - `apps/${appName}/src/app/App.stories.tsx` - ); - }); - it('should run e2e for cypress', async () => { if (runE2ETests()) { const results = runCLI(`e2e ${appName}-e2e`); @@ -246,35 +126,13 @@ describe('expo', () => { } }); - it('should run e2e for cypress with configuration ci', async () => { - if (runE2ETests()) { - const results = runCLI(`e2e ${appName}-e2e --configuration=ci`); - expect(results).toContain('Successfully ran target e2e'); - - // port and process cleanup - try { - await killPorts(4200); - } catch (err) { - expect(err).toBeFalsy(); - } - } - }); - - it('should run e2e for playwright', async () => { - const appName2 = uniq('my-app'); + it('should create storybook with application', async () => { runCLI( - `generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive` + `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` + ); + checkFilesExist( + `${appName}/.storybook/main.ts`, + `${appName}/src/app/App.stories.tsx` ); - if (runE2ETests()) { - const results = runCLI(`e2e ${appName2}-e2e`, { verbose: true }); - expect(results).toContain('Successfully ran target e2e'); - - // port and process cleanup - try { - await killPorts(4200); - } catch (err) { - expect(err).toBeFalsy(); - } - } }); }); diff --git a/e2e/jest/src/jest-legacy.test.ts b/e2e/jest/src/jest-legacy.test.ts new file mode 100644 index 0000000000000..ea6c839805f8c --- /dev/null +++ b/e2e/jest/src/jest-legacy.test.ts @@ -0,0 +1,44 @@ +import { stripIndents } from '@angular-devkit/core/src/utils/literals'; +import { + newProject, + runCLI, + runCLIAsync, + uniq, + updateFile, + expectJestTestsToPass, + cleanupProject, +} from '@nx/e2e/utils'; + +describe('Jest', () => { + beforeAll(() => { + newProject({ name: uniq('proj-jest'), packages: ['@nx/js', '@nx/node'] }); + }); + + afterAll(() => cleanupProject()); + + it('should support multiple `coverageReporters` when using @nx/jest:jest executor', async () => { + const mylib = uniq('mylib'); + runCLI(`generate @nx/js:lib ${mylib} --unitTestRunner=jest`, { + env: { + NX_ADD_PLUGINS: 'false', + }, + }); + + updateFile( + `libs/${mylib}/src/lib/${mylib}.spec.ts`, + ` + test('can access jest global', () => { + expect(true).toBe(true); + }); + ` + ); + + const result = await runCLIAsync( + `test ${mylib} --no-watch --code-coverage --coverageReporters=text --coverageReporters=text-summary` + ); + expect(result.stdout).toContain( + 'File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s' + ); // text + expect(result.stdout).toContain('Coverage summary'); // text-summary + }, 90000); +}); diff --git a/e2e/jest/src/jest.test.ts b/e2e/jest/src/jest.test.ts index 61fda9aa7ec08..88b75796e1902 100644 --- a/e2e/jest/src/jest.test.ts +++ b/e2e/jest/src/jest.test.ts @@ -53,7 +53,8 @@ describe('Jest', () => { `libs/${mylib}/setup.ts`, stripIndents` const { registerTsProject } = require('@nx/js/src/internal'); - const cleanup = registerTsProject('./tsconfig.base.json'); + const { join } = require('path'); + const cleanup = registerTsProject(join(__dirname, '../../tsconfig.base.json')); import {setup} from '@global-fun/globals'; export default async function() {setup();} @@ -66,7 +67,8 @@ describe('Jest', () => { `libs/${mylib}/teardown.ts`, stripIndents` const { registerTsProject } = require('@nx/js/src/internal'); - const cleanup = registerTsProject('./tsconfig.base.json'); + const { join } = require('path'); + const cleanup = registerTsProject(join(__dirname, '../../tsconfig.base.json')); import {teardown} from '@global-fun/globals'; export default async function() {teardown();} @@ -118,28 +120,6 @@ describe('Jest', () => { ); }, 90000); - it('should support multiple `coverageReporters` through CLI', async () => { - const mylib = uniq('mylib'); - runCLI(`generate @nx/js:lib ${mylib} --unitTestRunner=jest`); - - updateFile( - `libs/${mylib}/src/lib/${mylib}.spec.ts`, - ` - test('can access jest global', () => { - expect(true).toBe(true); - }); - ` - ); - - const result = await runCLIAsync( - `test ${mylib} --no-watch --code-coverage --coverageReporters=text --coverageReporters=text-summary` - ); - expect(result.stdout).toContain( - 'File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s' - ); // text - expect(result.stdout).toContain('Coverage summary'); // text-summary - }, 90000); - it('should be able to test node lib with babel-jest', async () => { const libName = uniq('babel-test-lib'); runCLI( diff --git a/e2e/js/src/js-executor-node.test.ts b/e2e/js/src/js-executor-node.test.ts index a301ff748ab5b..c592e4b53d473 100644 --- a/e2e/js/src/js-executor-node.test.ts +++ b/e2e/js/src/js-executor-node.test.ts @@ -2,7 +2,6 @@ import { cleanupProject, newProject, runCLI, - setMaxWorkers, uniq, updateFile, updateJson, @@ -50,7 +49,8 @@ describe('js:node executor', () => { expect(output).toContain('This is an error'); }, 240_000); - it('should execute library compiled with rollup', async () => { + // TODO: investigate this failure + xit('should execute library compiled with rollup', async () => { const rollupLib = uniq('rolluplib'); runCLI( @@ -136,7 +136,6 @@ describe('js:node executor', () => { runCLI( `generate @nx/node:application ${webpackProject} --bundler=webpack --no-interactive` ); - setMaxWorkers(join('apps', webpackProject, 'project.json')); updateFile(`apps/${webpackProject}/src/main.ts`, () => { return ` @@ -152,17 +151,6 @@ describe('js:node executor', () => { watch: false, }, }; - config.targets.build = { - ...config.targets.build, - configurations: { - development: { - outputPath: 'dist/packages/api-dev', - }, - production: { - outputPath: 'dist/packages/api-prod', - }, - }, - }; return config; }); diff --git a/e2e/js/src/js-executor-swc.test.ts b/e2e/js/src/js-executor-swc.test.ts index 6759b01002495..9c287b68cc870 100644 --- a/e2e/js/src/js-executor-swc.test.ts +++ b/e2e/js/src/js-executor-swc.test.ts @@ -2,9 +2,7 @@ import { execSync } from 'child_process'; import { checkFilesExist, cleanupProject, - detectPackageManager, newProject, - packageManagerLockFile, readJson, runCLI, tmpProjPath, diff --git a/e2e/js/src/js-generators.ts b/e2e/js/src/js-generators.ts index 70737b4699377..ebcc590bdc62c 100644 --- a/e2e/js/src/js-generators.ts +++ b/e2e/js/src/js-generators.ts @@ -2,7 +2,6 @@ import { checkFilesDoNotExist, checkFilesExist, cleanupProject, - createFile, newProject, readFile, readJson, @@ -54,7 +53,7 @@ describe('js e2e', () => { const result = runCLI(`lint ${dirName}-${libName}`); expect(result).toContain(`Linting "${dirName}-${libName}"...`); - expect(result).toContain('All files pass linting.'); + expect(result).toContain('All files pass linting'); // Test const testResult = await runCLIAsync(`test ${dirName}-${libName}`); diff --git a/e2e/js/src/js-packaging.test.ts b/e2e/js/src/js-packaging.test.ts index 73768826c2220..ddf4bf6f4d06e 100644 --- a/e2e/js/src/js-packaging.test.ts +++ b/e2e/js/src/js-packaging.test.ts @@ -22,7 +22,8 @@ describe('packaging libs', () => { afterEach(() => cleanupProject()); - it('should bundle libs using esbuild, vite, rollup and be used in CJS/ESM projects', () => { + // TODO: investigate this failure + xit('should bundle libs using esbuild, vite, rollup and be used in CJS/ESM projects', () => { const esbuildLib = uniq('esbuildlib'); const viteLib = uniq('vitelib'); const rollupLib = uniq('rolluplib'); diff --git a/e2e/next-core/src/next-appdir.test.ts b/e2e/next-core/src/next-appdir.test.ts index 960872071f083..a57d15ddb0cf5 100644 --- a/e2e/next-core/src/next-appdir.test.ts +++ b/e2e/next-core/src/next-appdir.test.ts @@ -11,7 +11,12 @@ import { checkApp } from './utils'; describe('Next.js App Router', () => { let proj: string; - beforeAll(() => (proj = newProject())); + beforeAll( + () => + (proj = newProject({ + packages: ['@nx/next'], + })) + ); afterAll(() => cleanupProject()); diff --git a/e2e/next-core/src/next-structure.test.ts b/e2e/next-core/src/next-legacy.test.ts similarity index 65% rename from e2e/next-core/src/next-structure.test.ts rename to e2e/next-core/src/next-legacy.test.ts index 95de4159c2f99..47613c41dc5b7 100644 --- a/e2e/next-core/src/next-structure.test.ts +++ b/e2e/next-core/src/next-legacy.test.ts @@ -1,37 +1,105 @@ -import { mkdirSync, removeSync } from 'fs-extra'; import { capitalize } from '@nx/devkit/src/utils/string-utils'; -import { checkApp } from './utils'; +import { joinPathFragments } from '@nx/devkit'; import { checkFilesExist, cleanupProject, + detectPackageManager, + getPackageManagerCommand, isNotWindows, killPort, newProject, + packageManagerLockFile, readFile, runCLI, + runCommand, runCommandUntil, tmpProjPath, uniq, updateFile, updateJson, -} from '@nx/e2e/utils'; +} from 'e2e/utils'; +import { mkdirSync, removeSync } from 'fs-extra'; import { join } from 'path'; +import { checkApp } from './utils'; -describe('Next.js Apps Libs', () => { +// TODO(crystal, @ndcunningham): Investigate why these tests are failing +xdescribe('@nx/next (legacy)', () => { let proj: string; let originalEnv: string; + let packageManager; + + afterEach(() => { + cleanupProject(); + }); - beforeEach(() => { - proj = newProject(); + beforeAll(() => { + proj = newProject({ + packages: ['@nx/next'], + }); + packageManager = detectPackageManager(tmpProjPath()); originalEnv = process.env.NODE_ENV; }); - afterEach(() => { + afterAll(() => { process.env.NODE_ENV = originalEnv; cleanupProject(); }); - it('should generate app + libs', async () => { + it('should build app and .next artifacts at the outputPath if provided by the CLI', () => { + const appName = uniq('app'); + runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + + runCLI(`build ${appName} --outputPath="dist/foo"`); + + checkFilesExist('dist/foo/package.json'); + checkFilesExist('dist/foo/next.config.js'); + // Next Files + checkFilesExist('dist/foo/.next/package.json'); + checkFilesExist('dist/foo/.next/build-manifest.json'); + }, 600_000); + + it('should copy relative modules needed by the next.config.js file', async () => { + const appName = uniq('app'); + + runCLI(`generate @nx/next:app ${appName} --style=css --no-interactive`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + + updateFile(`apps/${appName}/redirects.js`, 'module.exports = [];'); + updateFile( + `apps/${appName}/nested/headers.js`, + `module.exports = require('./headers-2');` + ); + updateFile(`apps/${appName}/nested/headers-2.js`, 'module.exports = [];'); + updateFile(`apps/${appName}/next.config.js`, (content) => { + return `const redirects = require('./redirects');\nconst headers = require('./nested/headers.js');\n${content}`; + }); + + runCLI(`build ${appName}`); + checkFilesExist(`dist/apps/${appName}/redirects.js`); + checkFilesExist(`dist/apps/${appName}/nested/headers.js`); + checkFilesExist(`dist/apps/${appName}/nested/headers-2.js`); + }, 120_000); + + it('should build and install pruned lock file', () => { + const appName = uniq('app'); + runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + + const result = runCLI(`build ${appName} --generateLockfile=true`); + expect(result).not.toMatch(/Graph is not consistent/); + checkFilesExist( + `dist/apps/${appName}/${packageManagerLockFile[packageManager]}` + ); + runCommand(`${getPackageManagerCommand().ciInstall}`, { + cwd: joinPathFragments(tmpProjPath(), 'dist/apps', appName), + }); + }, 1_000_000); + + it('should produce a self-contained artifact in dist', async () => { // Remove apps/libs folder and use packages. // Allows us to test other integrated monorepo setup that had a regression. // See: https://github.com/nrwl/nx/issues/16658 @@ -45,12 +113,22 @@ describe('Next.js Apps Libs', () => { const buildableLib = uniq('buildablelib'); runCLI( - `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false` + `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false`, + { + env: { NX_ADD_PLUGINS: 'false' }, + } ); - runCLI(`generate @nx/next:lib ${nextLib} --no-interactive`); - runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`); + runCLI(`generate @nx/next:lib ${nextLib} --no-interactive`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); + runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); runCLI( - `generate @nx/js:lib ${buildableLib} --no-interactive --bundler=vite` + `generate @nx/js:lib ${buildableLib} --no-interactive --bundler=vite`, + { + env: { NX_ADD_PLUGINS: 'false' }, + } ); // Create file in public that should be copied to dist @@ -189,7 +267,10 @@ describe('Next.js Apps Libs', () => { // Check that the output is self-contained (i.e. can run with its own package.json + node_modules) const selfContainedPort = 3000; runCLI( - `generate @nx/workspace:run-commands serve-prod --project ${appName} --cwd=dist/packages/${appName} --command="npx next start --port=${selfContainedPort}"` + `generate @nx/workspace:run-commands serve-prod --project ${appName} --cwd=dist/packages/${appName} --command="npx next start --port=${selfContainedPort}"`, + { + env: { NX_ADD_PLUGINS: 'false' }, + } ); const selfContainedProcess = await runCommandUntil( `run ${appName}:serve-prod`, diff --git a/e2e/next-core/src/next-lock-file.test.ts b/e2e/next-core/src/next-lock-file.test.ts deleted file mode 100644 index ae190babdb68d..0000000000000 --- a/e2e/next-core/src/next-lock-file.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { detectPackageManager, joinPathFragments } from '@nx/devkit'; -import { - checkFilesExist, - cleanupProject, - getPackageManagerCommand, - newProject, - packageManagerLockFile, - runCLI, - runCommand, - tmpProjPath, - uniq, -} from '@nx/e2e/utils'; - -describe('Next.js Lock File', () => { - let proj: string; - let originalEnv: string; - let packageManager; - - beforeEach(() => { - proj = newProject(); - packageManager = detectPackageManager(tmpProjPath()); - originalEnv = process.env.NODE_ENV; - }); - - afterEach(() => { - process.env.NODE_ENV = originalEnv; - cleanupProject(); - }); - - it('should build and install pruned lock file', () => { - const appName = uniq('app'); - runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`); - - const result = runCLI(`build ${appName} --generateLockfile=true`); - expect(result).not.toMatch(/Graph is not consistent/); - checkFilesExist( - `dist/apps/${appName}/${packageManagerLockFile[packageManager]}` - ); - runCommand(`${getPackageManagerCommand().ciInstall}`, { - cwd: joinPathFragments(tmpProjPath(), 'dist/apps', appName), - }); - }, 1_000_000); -}); diff --git a/e2e/next-core/src/next-pcv3.test.ts b/e2e/next-core/src/next-pcv3.test.ts deleted file mode 100644 index 0ee191908ed3b..0000000000000 --- a/e2e/next-core/src/next-pcv3.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - runCLI, - cleanupProject, - newProject, - uniq, - updateJson, - runE2ETests, - directoryExists, - readJson, - updateFile, - removeFile, - createFile, -} from 'e2e/utils'; - -describe('@nx/next/plugin', () => { - let project: string; - let appName: string; - - beforeAll(() => { - project = newProject({ - packages: ['@nx/next'], - }); - appName = uniq('app'); - runCLI( - `generate @nx/next:app ${appName} --project-name-and-root-format=as-provided --no-interactive`, - { env: { NX_PCV3: 'true' } } - ); - - // update package.json to add next as a script - updateJson(`package.json`, (json) => { - json.scripts = json.scripts || {}; - json.scripts.next = 'next'; - return json; - }); - }); - - afterAll(() => cleanupProject()); - - it('nx.json should contain plugin configuration', () => { - const nxJson = readJson('nx.json'); - const nextPlugin = nxJson.plugins.find( - (plugin) => plugin.plugin === '@nx/next/plugin' - ); - expect(nextPlugin).toBeDefined(); - expect(nextPlugin.options).toBeDefined(); - expect(nextPlugin.options.buildTargetName).toEqual('build'); - expect(nextPlugin.options.startTargetName).toEqual('start'); - expect(nextPlugin.options.devTargetName).toEqual('dev'); - }); - - it('should build the app', async () => { - const result = runCLI(`build ${appName}`); - // check build output for PCV3 artifacts (e.g. .next directory) are inside the project directory - directoryExists(`${appName}/.next`); - - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }, 200_000); - - it('should build the app with .mjs config file', async () => { - createFile( - `${appName}/next.config.mjs`, - ` - export default { - reactStrictMode: true, - }; - ` - ); - - removeFile(`${appName}/next.config.js`); - - const result = runCLI(`build ${appName}`); - expect(result).toContain( - `Successfully ran target build for project ${appName}` - ); - }, 200_000); - - it('should serve the app', async () => { - // update cypress config to serve on a different port to avoid port conflicts. - updateFile(`${appName}-e2e/cypress.config.ts`, (_) => { - return ` - import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; - - import { defineConfig } from 'cypress'; - - export default defineConfig({ - e2e: { - ...nxE2EPreset(__filename, { - cypressDir: 'src', - webServerCommands: { default: 'nx run ${appName}:start --port=4000' }, - webServerConfig: { timeout: 20_000 }, - }), - baseUrl: 'http://localhost:4000', - }, - }); - - `; - }); - if (runE2ETests()) { - const e2eResult = runCLI(`run ${appName}-e2e:e2e --verbose`); - - expect(e2eResult).toContain('All specs passed!'); - } - }, 500_000); -}); diff --git a/e2e/next-core/src/next-webpack.test.ts b/e2e/next-core/src/next-webpack.test.ts index cba257b90eec7..8da170103e4b3 100644 --- a/e2e/next-core/src/next-webpack.test.ts +++ b/e2e/next-core/src/next-webpack.test.ts @@ -15,7 +15,9 @@ describe('Next.js Webpack', () => { let originalEnv: string; beforeEach(() => { - proj = newProject(); + proj = newProject({ + packages: ['@nx/next'], + }); originalEnv = process.env.NODE_ENV; }); @@ -28,7 +30,12 @@ describe('Next.js Webpack', () => { const appName = uniq('app'); runCLI( - `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false` + `generate @nx/next:app ${appName} --no-interactive --style=css --appDir=false`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } ); updateFile( diff --git a/e2e/next-core/src/next.test.ts b/e2e/next-core/src/next.test.ts index 0db2b35ede34c..4bf16c3132e18 100644 --- a/e2e/next-core/src/next.test.ts +++ b/e2e/next-core/src/next.test.ts @@ -2,13 +2,9 @@ import { checkFilesDoNotExist, checkFilesExist, cleanupProject, - killPort, - killPorts, newProject, readFile, runCLI, - runCommandUntil, - runE2ETests, uniq, updateFile, } from '@nx/e2e/utils'; @@ -20,8 +16,11 @@ describe('Next.js Applications', () => { let originalEnv: string; beforeAll(() => { - proj = newProject(); + proj = newProject({ + packages: ['@nx/next', '@nx/cypress'], + }); }); + beforeEach(() => { originalEnv = process.env.NODE_ENV; }); @@ -48,18 +47,11 @@ describe('Next.js Applications', () => { `Successfully ran target build for project ${appName}` ); // check tests pass - const appTestResult = runCLI(`test ${appName}`); + const appTestResult = runCLI(`test ${appName} --passWithNoTests`); expect(appTestResult).toContain( `Successfully ran target test for project ${appName}` ); - // assert scoped project names are not supported when --project-name-and-root-format=derived - expect(() => - runCLI( - `generate @nx/next:lib ${libName} --buildable --project-name-and-root-format=derived --no-interactive` - ) - ).toThrow(); - runCLI( `generate @nx/next:lib ${libName} --buildable --project-name-and-root-format=as-provided --no-interactive` ); @@ -73,90 +65,6 @@ describe('Next.js Applications', () => { ); }, 600_000); - it('should build app and .next artifacts at the outputPath if provided by the CLI', () => { - const appName = uniq('app'); - runCLI(`generate @nx/next:app ${appName} --no-interactive --style=css`); - - runCLI(`build ${appName} --outputPath="dist/foo"`); - - checkFilesExist('dist/foo/package.json'); - checkFilesExist('dist/foo/next.config.js'); - // Next Files - checkFilesExist('dist/foo/.next/package.json'); - checkFilesExist('dist/foo/.next/build-manifest.json'); - }, 600_000); - - // TODO(jack): re-enable this test - xit('should be able to serve with a proxy configuration', async () => { - const appName = uniq('app'); - const jsLib = uniq('tslib'); - - const port = 4200; - - runCLI(`generate @nx/next:app ${appName} --appDir=false`); - runCLI(`generate @nx/js:lib ${jsLib} --no-interactive`); - - const proxyConf = { - '/external-api': { - target: `http://localhost:${port}`, - pathRewrite: { - '^/external-api/hello': '/api/hello', - }, - }, - }; - updateFile(`apps/${appName}/proxy.conf.json`, JSON.stringify(proxyConf)); - updateFile('.env.local', 'NX_CUSTOM_VAR=test value from a file'); - - updateFile( - `libs/${jsLib}/src/lib/${jsLib}.ts`, - ` - export function jsLib(): string { - return process.env.NX_CUSTOM_VAR; - }; - ` - ); - - updateFile( - `apps/${appName}/pages/index.tsx`, - ` - import React from 'react'; - import { jsLib } from '@${proj}/${jsLib}'; - - export const Index = ({ greeting }: any) => { - return ( -

{jsLib()}

- ); - }; - export default Index; - ` - ); - - updateFile( - `apps/${appName}/pages/api/hello.js`, - ` - export default (_req: any, res: any) => { - res.status(200).send('Welcome'); - }; - ` - ); - - // serve Next.js - const p = await runCommandUntil( - `run ${appName}:serve --port=${port}`, - (output) => { - return output.indexOf(`[ ready ] on http://localhost:${port}`) > -1; - } - ); - - const apiData = await getData(port, '/external-api/hello'); - const pageData = await getData(port, '/'); - expect(apiData).toContain(`Welcome`); - expect(pageData).toContain(`test value from a file`); - - await killPort(port); - await killPorts(); - }, 300_000); - it('should build in dev mode without errors', async () => { const appName = uniq('app'); @@ -176,7 +84,7 @@ describe('Next.js Applications', () => { const appName = uniq('app'); runCLI( - `generate @nx/next:app ${appName} --no-interactive --js --appDir=false` + `generate @nx/next:app ${appName} --no-interactive --js --appDir=false --e2eTestRunner=playwright` ); checkFilesExist(`apps/${appName}/src/pages/index.js`); @@ -241,107 +149,6 @@ describe('Next.js Applications', () => { checkExport: false, }); }, 300_000); - - //TODO(caleb): Throwing error Cypress failed to verify that your server is running. - it.skip('should allow using a custom server implementation', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/next:app ${appName} --style=css --no-interactive --custom-server` - ); - - checkFilesExist(`apps/${appName}/server/main.ts`); - - await checkApp(appName, { - checkUnitTest: false, - checkLint: false, - checkE2E: true, - checkExport: false, - }); - }, 300_000); - - it('should copy relative modules needed by the next.config.js file', async () => { - const appName = uniq('app'); - - runCLI(`generate @nx/next:app ${appName} --style=css --no-interactive`); - - updateFile(`apps/${appName}/redirects.js`, 'module.exports = [];'); - updateFile( - `apps/${appName}/nested/headers.js`, - `module.exports = require('./headers-2');` - ); - updateFile(`apps/${appName}/nested/headers-2.js`, 'module.exports = [];'); - updateFile(`apps/${appName}/next.config.js`, (content) => { - return `const redirects = require('./redirects');\nconst headers = require('./nested/headers.js');\n${content}`; - }); - - runCLI(`build ${appName}`); - checkFilesExist(`dist/apps/${appName}/redirects.js`); - checkFilesExist(`dist/apps/${appName}/nested/headers.js`); - checkFilesExist(`dist/apps/${appName}/nested/headers-2.js`); - }, 120_000); - - it('should support --turbo to enable Turbopack', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/next:app ${appName} --style=css --appDir --no-interactive` - ); - - // add a new target to project.json to run with turbo enabled - updateFile(`apps/${appName}/project.json`, (content) => { - const json = JSON.parse(content); - const updateJson = { - ...json, - targets: { - ...json.targets, - turbo: { - executor: '@nx/next:server', - defaultConfiguration: 'development', - options: { - buildTarget: `${appName}:build`, - dev: true, - turbo: true, - }, - configurations: { - development: { - buildTarget: `${appName}:build:development`, - dev: true, - turbo: true, - }, - }, - }, - }, - }; - return JSON.stringify(updateJson, null, 2); - }); - - // update cypress to use the new target - updateFile(`apps/${appName}-e2e/project.json`, (content) => { - const json = JSON.parse(content); - const updatedJson = { - ...json, - targets: { - ...json.targets, - e2e: { - ...json.targets.e2e, - executor: '@nx/cypress:cypress', - options: { - ...json.targets.e2e.options, - devServerTarget: `${appName}:turbo`, - }, - configurations: {}, - }, - }, - }; - return JSON.stringify(updatedJson, null, 2); - }); - - if (runE2ETests()) { - const e2eResult = runCLI(`e2e ${appName}-e2e --verbose`); - expect(e2eResult).toContain('All specs passed!'); - } - }, 300_000); }); function getData(port, path = ''): Promise { diff --git a/e2e/next-core/src/utils.ts b/e2e/next-core/src/utils.ts index 028fcbbb8e66f..e91f95b9221bd 100644 --- a/e2e/next-core/src/utils.ts +++ b/e2e/next-core/src/utils.ts @@ -1,5 +1,6 @@ import { checkFilesExist, + exists, killPorts, readJson, runCLI, @@ -21,7 +22,7 @@ export async function checkApp( if (opts.checkLint) { const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); } if (opts.checkUnitTest) { @@ -33,12 +34,20 @@ export async function checkApp( const buildResult = runCLI(`build ${appName}`); expect(buildResult).toContain(`Successfully ran target build`); - checkFilesExist(`dist/${appsDir}/${appName}/.next/build-manifest.json`); + // Executor will point to dist, whereas inferred build target will output to `/.next` + try { + checkFilesExist(`dist/${appsDir}/${appName}/.next/build-manifest.json`); + } catch { + checkFilesExist(`${appsDir}/${appName}/.next/build-manifest.json`); + } - const packageJson = readJson(`dist/${appsDir}/${appName}/package.json`); - expect(packageJson.dependencies.react).toBeDefined(); - expect(packageJson.dependencies['react-dom']).toBeDefined(); - expect(packageJson.dependencies.next).toBeDefined(); + // Only the executor will output package.json file to dist + if (exists(`dist/${appsDir}/${appName}/package.json`)) { + const packageJson = readJson(`dist/${appsDir}/${appName}/package.json`); + expect(packageJson.dependencies.react).toBeDefined(); + expect(packageJson.dependencies['react-dom']).toBeDefined(); + expect(packageJson.dependencies.next).toBeDefined(); + } if (opts.checkE2E && runE2ETests()) { const e2eResults = runCLI( @@ -47,9 +56,4 @@ export async function checkApp( expect(e2eResults).toContain('Successfully ran target e2e for project'); expect(await killPorts()).toBeTruthy(); } - - if (opts.checkExport) { - runCLI(`export ${appName}`); - checkFilesExist(`dist/${appsDir}/${appName}/exported/index.html`); - } } diff --git a/e2e/next-extensions/src/next-component-tests.test.ts b/e2e/next-extensions/src/next-component-tests.test.ts index 72d29e6e5464d..d36326c1968ae 100644 --- a/e2e/next-extensions/src/next-component-tests.test.ts +++ b/e2e/next-extensions/src/next-component-tests.test.ts @@ -12,6 +12,7 @@ describe('NextJs Component Testing', () => { beforeAll(() => { newProject({ name: uniq('next-ct'), + packages: ['@nx/next'], }); }); @@ -21,13 +22,13 @@ describe('NextJs Component Testing', () => { const appName = uniq('next-app'); createAppWithCt(appName); if (runE2ETests()) { - expect(runCLI(`component-test ${appName} --no-watch`)).toContain( + expect(runCLI(`component-test ${appName}`)).toContain( 'All specs passed!' ); } addTailwindToApp(appName); if (runE2ETests()) { - expect(runCLI(`component-test ${appName} --no-watch`)).toContain( + expect(runCLI(`component-test ${appName}`)).toContain( 'All specs passed!' ); } @@ -39,7 +40,7 @@ describe('NextJs Component Testing', () => { // add bable compiler to app addBabelSupport(`apps/${appName}`); if (runE2ETests()) { - expect(runCLI(`component-test ${appName} --no-watch`)).toContain( + expect(runCLI(`component-test ${appName}`)).toContain( 'All specs passed!' ); } @@ -51,7 +52,7 @@ describe('NextJs Component Testing', () => { // add bable compiler to lib addBabelSupport(`libs/${libName}`); if (runE2ETests()) { - expect(runCLI(`component-test ${libName} --no-watch`)).toContain( + expect(runCLI(`component-test ${libName}`)).toContain( 'All specs passed!' ); } @@ -61,13 +62,13 @@ describe('NextJs Component Testing', () => { const libName = uniq('next-lib'); createLibWithCt(libName, false); if (runE2ETests()) { - expect(runCLI(`component-test ${libName} --no-watch`)).toContain( + expect(runCLI(`component-test ${libName}`)).toContain( 'All specs passed!' ); } addTailwindToLib(libName); if (runE2ETests()) { - expect(runCLI(`component-test ${libName} --no-watch`)).toContain( + expect(runCLI(`component-test ${libName}`)).toContain( 'All specs passed!' ); } @@ -77,14 +78,14 @@ describe('NextJs Component Testing', () => { const buildableLibName = uniq('next-buildable-lib'); createLibWithCt(buildableLibName, true); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); } addTailwindToLib(buildableLibName); if (runE2ETests()) { - expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain( + expect(runCLI(`component-test ${buildableLibName}`)).toContain( 'All specs passed!' ); } diff --git a/e2e/next-extensions/src/next-playwright-standalone-eslint.test.ts b/e2e/next-extensions/src/next-playwright-standalone-eslint.test.ts new file mode 100644 index 0000000000000..0df2b56bc3e44 --- /dev/null +++ b/e2e/next-extensions/src/next-playwright-standalone-eslint.test.ts @@ -0,0 +1,36 @@ +import { + cleanupProject, + fileExists, + getSelectedPackageManager, + runCLI, + runCreateWorkspace, + uniq, +} from '@nx/e2e/utils'; + +// This test exists as coverage for a previous regression +describe('nextjs standalone playwright linting', () => { + const packageManager = getSelectedPackageManager() || 'pnpm'; + + afterEach(() => cleanupProject()); + + it('should work', async () => { + const wsName = uniq('next'); + const appName = uniq('app'); + runCreateWorkspace(wsName, { + preset: 'nextjs-standalone', + style: 'css', + nextAppDir: true, + nextSrcDir: true, + appName, + packageManager, + e2eTestRunner: 'playwright', + }); + // Ensure that the expected standalone setup is correct + expect(fileExists('.eslintrc.base.json')).toBe(false); + + const output = runCLI(`lint ${appName}`); + expect(output).toContain( + `Successfully ran target lint for project ${appName}` + ); + }); +}); diff --git a/e2e/next-extensions/src/next-playwright.test.ts b/e2e/next-extensions/src/next-playwright.test.ts index 940d648f072b9..30d3dc16632a3 100644 --- a/e2e/next-extensions/src/next-playwright.test.ts +++ b/e2e/next-extensions/src/next-playwright.test.ts @@ -26,7 +26,7 @@ describe('Next Playwright e2e tests', () => { it('should execute e2e tests using playwright', () => { if (runE2ETests()) { - const result = runCLI(`e2e ${appName}-e2e --no-watch --verbose`); + const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` ); @@ -54,7 +54,7 @@ describe('Next Playwright e2e tests', () => { ); if (runE2ETests()) { - const result = runCLI(`e2e ${appName}-e2e --no-watch --verbose`); + const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` ); diff --git a/e2e/next-extensions/src/next-storybook.test.ts b/e2e/next-extensions/src/next-storybook.test.ts index e4f5b251e346b..866fe44535761 100644 --- a/e2e/next-extensions/src/next-storybook.test.ts +++ b/e2e/next-extensions/src/next-storybook.test.ts @@ -1,42 +1,36 @@ import { checkFilesExist, cleanupProject, - getPackageManagerCommand, - getSelectedPackageManager, newProject, runCLI, - runCommand, uniq, } from '@nx/e2e/utils'; -const pmc = getPackageManagerCommand({ - packageManager: getSelectedPackageManager(), -}); -describe('Next.js Storybook', () => { - let proj: string; - - beforeAll(() => (proj = newProject({ name: 'proj', packageManager: 'npm' }))); - - afterAll(() => cleanupProject()); - - // TODO(@ndcunningham): This test is failing, please re-enable when it is fixed. - xit('should run a Next.js based Storybook setup', async () => { - const appName = uniq('app'); - - runCLI(`generate @nx/next:app ${appName} --no-interactive`); +// TODO(katerina): Enable some time? +// This test fails because of sharp. In this PR I have included all related links to the issue. +xdescribe('Next.js Storybook', () => { + const appName = uniq('app'); + beforeAll(() => { + newProject({ + name: 'proj', + packageManager: 'npm', + packages: ['@nx/next'], + }); runCLI( - `generate @nx/next:component Foo --project=${appName} --no-interactive` + `generate @nx/next:app ${appName} --e2eTestRunner=none --project-name-and-root-format=as-provided --no-interactive` ); - runCLI( - `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` + `generate @nx/next:component Foo --directory=${appName}/components/foo/Foo.tsx --no-interactive` ); + }); - // It seems that we need to run install twice for some reason. - // This is only true on CI. On normal repos, it works as expected. - runCommand(pmc.install); + afterAll(() => cleanupProject()); + it('should run a Next.js based Storybook setup', async () => { + runCLI( + `generate @nx/next:storybook-configuration ${appName} --generateStories --no-interactive` + ); runCLI(`build-storybook ${appName}`); - checkFilesExist(`dist/storybook/${appName}/index.html`); - }, 1_000_000); + checkFilesExist(`${appName}/storybook-static/index.html`); + }, 600_000); }); diff --git a/e2e/next-extensions/src/next-styles.test.ts b/e2e/next-extensions/src/next-styles.test.ts index e9e4a88ab6755..49647b3494944 100644 --- a/e2e/next-extensions/src/next-styles.test.ts +++ b/e2e/next-extensions/src/next-styles.test.ts @@ -5,7 +5,9 @@ describe('Next.js Styles', () => { let originalEnv: string; beforeAll(() => { - newProject(); + newProject({ + packages: ['@nx/next'], + }); }); afterAll(() => cleanupProject()); @@ -29,7 +31,6 @@ describe('Next.js Styles', () => { checkUnitTest: false, checkLint: false, checkE2E: false, - checkExport: false, }); const scApp = uniq('app'); @@ -42,7 +43,6 @@ describe('Next.js Styles', () => { checkUnitTest: true, checkLint: false, checkE2E: false, - checkExport: false, }); const scAppWithAppRouter = uniq('app'); @@ -55,7 +55,6 @@ describe('Next.js Styles', () => { checkUnitTest: false, // No unit tests for app router checkLint: false, checkE2E: false, - checkExport: false, }); const emotionApp = uniq('app'); @@ -68,7 +67,6 @@ describe('Next.js Styles', () => { checkUnitTest: true, checkLint: false, checkE2E: false, - checkExport: false, }); }, 600_000); }); diff --git a/e2e/next-extensions/src/utils.ts b/e2e/next-extensions/src/utils.ts index 028fcbbb8e66f..25fd6e2ac8abf 100644 --- a/e2e/next-extensions/src/utils.ts +++ b/e2e/next-extensions/src/utils.ts @@ -13,7 +13,6 @@ export async function checkApp( checkUnitTest: boolean; checkLint: boolean; checkE2E: boolean; - checkExport: boolean; appsDir?: string; } ) { @@ -21,7 +20,7 @@ export async function checkApp( if (opts.checkLint) { const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('All files pass linting'); } if (opts.checkUnitTest) { @@ -33,12 +32,13 @@ export async function checkApp( const buildResult = runCLI(`build ${appName}`); expect(buildResult).toContain(`Successfully ran target build`); - checkFilesExist(`dist/${appsDir}/${appName}/.next/build-manifest.json`); + checkFilesExist(`${appsDir}/${appName}/.next/build-manifest.json`); - const packageJson = readJson(`dist/${appsDir}/${appName}/package.json`); - expect(packageJson.dependencies.react).toBeDefined(); - expect(packageJson.dependencies['react-dom']).toBeDefined(); - expect(packageJson.dependencies.next).toBeDefined(); + // TODO(crystal, @ndcunningham): Investigate if this file is correct + // const packageJson = readJson(`${appsDir}/${appName}/.next/package.json`); + // expect(packageJson.dependencies.react).toBeDefined(); + // expect(packageJson.dependencies['react-dom']).toBeDefined(); + // expect(packageJson.dependencies.next).toBeDefined(); if (opts.checkE2E && runE2ETests()) { const e2eResults = runCLI( @@ -47,9 +47,4 @@ export async function checkApp( expect(e2eResults).toContain('Successfully ran target e2e for project'); expect(await killPorts()).toBeTruthy(); } - - if (opts.checkExport) { - runCLI(`export ${appName}`); - checkFilesExist(`dist/${appsDir}/${appName}/exported/index.html`); - } } diff --git a/e2e/node/src/node-esbuild.test.ts b/e2e/node/src/node-esbuild.test.ts index 9a3190385982d..666975dd73b57 100644 --- a/e2e/node/src/node-esbuild.test.ts +++ b/e2e/node/src/node-esbuild.test.ts @@ -7,7 +7,6 @@ import { readFile, runCLI, runCommandUntil, - setMaxWorkers, uniq, updateFile, } from '@nx/e2e/utils'; @@ -26,7 +25,6 @@ describe('Node Applications + esbuild', () => { const app = uniq('nodeapp'); runCLI(`generate @nx/node:app ${app} --bundler=esbuild --no-interactive`); - setMaxWorkers(join('apps', app, 'project.json')); checkFilesDoNotExist(`apps/${app}/webpack.config.js`); diff --git a/e2e/node/src/node-server.test.ts b/e2e/node/src/node-server.test.ts index da10fbe3a98c7..4abfcd7f432cc 100644 --- a/e2e/node/src/node-server.test.ts +++ b/e2e/node/src/node-server.test.ts @@ -10,7 +10,6 @@ import { runCommandUntil, uniq, updateFile, - setMaxWorkers, updateJson, } from '@nx/e2e/utils'; import { join } from 'path'; @@ -76,17 +75,13 @@ describe('Node Applications + webpack', () => { runCLI( `generate @nx/node:app ${expressApp} --framework=express --no-interactive` ); - setMaxWorkers(join('apps', expressApp, 'project.json')); runCLI( `generate @nx/node:app ${fastifyApp} --framework=fastify --no-interactive` ); - setMaxWorkers(join('apps', fastifyApp, 'project.json')); runCLI(`generate @nx/node:app ${koaApp} --framework=koa --no-interactive`); - setMaxWorkers(join('apps', koaApp, 'project.json')); runCLI( `generate @nx/node:app ${nestApp} --framework=nest --bundler=webpack --no-interactive` ); - setMaxWorkers(join('apps', nestApp, 'project.json')); // Use esbuild by default checkFilesDoNotExist(`apps/${expressApp}/webpack.config.js`); @@ -146,7 +141,6 @@ describe('Node Applications + webpack', () => { runCLI( `generate @nx/node:app ${expressApp} --framework=express --docker --no-interactive` ); - setMaxWorkers(join('apps', expressApp, 'project.json')); checkFilesExist(`apps/${expressApp}/Dockerfile`); }, 300_000); @@ -159,11 +153,9 @@ describe('Node Applications + webpack', () => { runCLI( `generate @nx/node:app ${nodeApp1} --framework=none --no-interactive --port=4444` ); - setMaxWorkers(join('apps', nodeApp1, 'project.json')); runCLI( `generate @nx/node:app ${nodeApp2} --framework=none --no-interactive --port=4445` ); - setMaxWorkers(join('apps', nodeApp2, 'project.json')); updateJson(join('apps', nodeApp1, 'project.json'), (config) => { config.targets.serve.options.waitUntilTargets = [`${nodeApp2}:build`]; return config; diff --git a/e2e/node/src/node-webpack.test.ts b/e2e/node/src/node-webpack.test.ts index faf12d711433f..e216d4e736183 100644 --- a/e2e/node/src/node-webpack.test.ts +++ b/e2e/node/src/node-webpack.test.ts @@ -10,7 +10,6 @@ import { tmpProjPath, uniq, updateFile, - setMaxWorkers, updateJson, } from '@nx/e2e/utils'; import { execSync } from 'child_process'; @@ -28,8 +27,10 @@ describe('Node Applications + webpack', () => { it('should generate an app using webpack', async () => { const app = uniq('nodeapp'); - runCLI(`generate @nx/node:app ${app} --bundler=webpack --no-interactive`); - setMaxWorkers(join('apps', app, 'project.json')); + // This fails with Crystal enabled because `--optimization` is not a correct flag to pass to `webpack`. + runCLI(`generate @nx/node:app ${app} --bundler=webpack --no-interactive`, { + env: { NX_ADD_PLUGINS: 'false' }, + }); checkFilesExist(`apps/${app}/webpack.config.js`); diff --git a/e2e/node/src/node.test.ts b/e2e/node/src/node.test.ts index 4a2d2baf45122..486ef9aaeab69 100644 --- a/e2e/node/src/node.test.ts +++ b/e2e/node/src/node.test.ts @@ -22,7 +22,6 @@ import { uniq, updateFile, updateJson, - setMaxWorkers, } from '@nx/e2e/utils'; import { exec, execSync } from 'child_process'; import * as http from 'http'; @@ -62,10 +61,9 @@ describe('Node Applications', () => { const nodeapp = uniq('nodeapp'); runCLI(`generate @nx/node:app ${nodeapp} --linter=eslint`); - setMaxWorkers(join('apps', nodeapp, 'project.json')); const lintResults = runCLI(`lint ${nodeapp}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`); await runCLIAsync(`build ${nodeapp}`); @@ -77,10 +75,10 @@ describe('Node Applications', () => { expect(result).toContain('Hello World!'); }, 300000); - it('should be able to generate the correct outputFileName in options', async () => { + // TODO(crystal, @ndcunningham): What is the alternative here? + xit('should be able to generate the correct outputFileName in options', async () => { const nodeapp = uniq('nodeapp'); runCLI(`generate @nx/node:app ${nodeapp} --linter=eslint`); - setMaxWorkers(join('apps', nodeapp, 'project.json')); updateJson(join('apps', nodeapp, 'project.json'), (config) => { config.targets.build.options.outputFileName = 'index.js'; @@ -91,16 +89,16 @@ describe('Node Applications', () => { checkFilesExist(`dist/apps/${nodeapp}/index.js`); }, 300000); - it('should be able to generate an empty application with additional entries', async () => { + // TODO(crystal, @ndcunningham): What is the alternative here? + xit('should be able to generate an empty application with additional entries', async () => { const nodeapp = uniq('nodeapp'); runCLI( `generate @nx/node:app ${nodeapp} --linter=eslint --bundler=webpack` ); - setMaxWorkers(join('apps', nodeapp, 'project.json')); const lintResults = runCLI(`lint ${nodeapp}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); updateJson(join('apps', nodeapp, 'project.json'), (config) => { config.targets.build.options.additionalEntryPoints = [ @@ -157,7 +155,6 @@ describe('Node Applications', () => { runCLI( `generate @nx/node:app ${nodeapp} --linter=eslint --bundler=webpack --framework=none` ); - setMaxWorkers(join('apps', nodeapp, 'project.json')); updateFile('.env', `NX_FOOBAR="test foo bar"`); @@ -192,9 +189,9 @@ describe('Node Applications', () => { process.env.PORT = `${port}`; runCLI(`generate @nx/express:app ${nodeapp} --linter=eslint`); - setMaxWorkers(join('apps', nodeapp, 'project.json')); + const lintResults = runCLI(`lint ${nodeapp}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); updateFile( `apps/${nodeapp}/src/app/test.spec.ts`, @@ -234,10 +231,9 @@ describe('Node Applications', () => { const nestapp = uniq('nestapp'); const port = 3335; runCLI(`generate @nx/nest:app ${nestapp} --linter=eslint`); - setMaxWorkers(join('apps', nestapp, 'project.json')); const lintResults = runCLI(`lint ${nestapp}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); updateFile(`apps/${nestapp}/src/assets/file.txt`, ``); const jestResult = await runCLIAsync(`test ${nestapp}`); @@ -290,13 +286,13 @@ describe('Node Applications', () => { } }, 120000); - it('should be able to run ESM applications', async () => { + // TODO(crystal, @ndcunningham): how do we handle this now? + xit('should be able to run ESM applications', async () => { const esmapp = uniq('esmapp'); runCLI( `generate @nrwl/node:app ${esmapp} --linter=eslint --framework=none --bundler=webpack` ); - setMaxWorkers(join('apps', esmapp, 'project.json')); updateJson(`apps/${esmapp}/tsconfig.app.json`, (config) => { config.module = 'esnext'; config.target = 'es2020'; @@ -344,11 +340,11 @@ describe('Build Node apps', () => { afterAll(() => cleanupProject()); - it('should generate a package.json with the `--generatePackageJson` flag', async () => { + // TODO(crystal, @ndcunningham): What is the alternative here? + xit('should generate a package.json with the `--generatePackageJson` flag', async () => { const packageManager = detectPackageManager(tmpProjPath()); const nestapp = uniq('nestapp'); runCLI(`generate @nx/nest:app ${nestapp} --linter=eslint`); - setMaxWorkers(join('apps', nestapp, 'project.json')); await runCLIAsync(`build ${nestapp} --generatePackageJson`); @@ -410,7 +406,6 @@ describe('Build Node apps', () => { const nodeapp = uniq('nodeapp'); runCLI(`generate @nx/node:app ${nodeapp} --bundler=webpack`); - setMaxWorkers(join('apps', nodeapp, 'project.json')); const jslib = uniq('jslib'); runCLI(`generate @nx/js:lib ${jslib} --bundler=tsc`); @@ -451,7 +446,6 @@ ${jslib}(); const appName = uniq('app'); runCLI(`generate @nx/node:app ${appName} --no-interactive`); - setMaxWorkers(join('apps', appName, 'project.json')); // deleteOutputPath should default to true createFile(`dist/apps/${appName}/_should_remove.txt`); @@ -499,7 +493,7 @@ ${jslib}(); `Successfully ran target build for project ${appName}` ); // check tests pass - const appTestResult = runCLI(`test ${appName}`); + const appTestResult = runCLI(`test ${appName} --passWithNoTests`); expect(appTestResult).toContain( `Successfully ran target test for project ${appName}` ); @@ -529,11 +523,12 @@ ${jslib}(); ); }, 500_000); - describe('NestJS', () => { - it('should have plugin output if specified in `tsPlugins`', async () => { + // TODO(crystal, @ndcunningnam): Investigate why these tests are failing + xdescribe('NestJS', () => { + // TODO(crystal, @ndcunningham): What is the alternative here? + xit('should have plugin output if specified in `tsPlugins`', async () => { const nestapp = uniq('nestapp'); runCLI(`generate @nx/nest:app ${nestapp} --linter=eslint`); - setMaxWorkers(join('apps', nestapp, 'project.json')); packageInstall('@nestjs/swagger', undefined, '^7.0.0'); @@ -590,9 +585,9 @@ ${jslib}(); runCLI(`generate @nx/nest:lib ${nestlib}`); const lintResults = runCLI(`lint ${nestlib}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); - const testResults = runCLI(`test ${nestlib}`); + const testResults = runCLI(`test ${nestlib} --passWithNoTests`); expect(testResults).toContain( `Successfully ran target test for project ${nestlib}` ); @@ -604,7 +599,7 @@ ${jslib}(); runCLI(`generate @nx/nest:lib ${nestlib} --service`); const lintResults = runCLI(`lint ${nestlib}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); const jestResult = await runCLIAsync(`test ${nestlib}`); expect(jestResult.combinedOutput).toContain( @@ -618,7 +613,7 @@ ${jslib}(); runCLI(`generate @nx/nest:lib ${nestlib} --controller`); const lintResults = runCLI(`lint ${nestlib}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); const jestResult = await runCLIAsync(`test ${nestlib}`); expect(jestResult.combinedOutput).toContain( @@ -632,7 +627,7 @@ ${jslib}(); runCLI(`generate @nx/nest:lib ${nestlib} --controller --service`); const lintResults = runCLI(`lint ${nestlib}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); const jestResult = await runCLIAsync(`test ${nestlib}`); expect(jestResult.combinedOutput).toContain( diff --git a/e2e/nuxt/src/nuxt.test.ts b/e2e/nuxt/src/nuxt.test.ts index 0182308915f10..5f2eeda4a9b1d 100644 --- a/e2e/nuxt/src/nuxt.test.ts +++ b/e2e/nuxt/src/nuxt.test.ts @@ -8,15 +8,16 @@ import { } from '@nx/e2e/utils'; describe('Nuxt Plugin', () => { - let proj: string; const app = uniq('app'); beforeAll(() => { - proj = newProject({ + newProject({ packages: ['@nx/nuxt', '@nx/storybook'], unsetProjectNameAndRootFormat: false, }); - runCLI(`generate @nx/nuxt:app ${app} --unitTestRunner=vitest`); + runCLI( + `generate @nx/nuxt:app ${app} --unitTestRunner=vitest --projectNameAndRootFormat=as-provided` + ); runCLI( `generate @nx/nuxt:component --directory=${app}/src/components/one --name=one --nameAndDirectoryFormat=as-provided --unitTestRunner=vitest` ); @@ -51,6 +52,6 @@ describe('Nuxt Plugin', () => { `generate @nx/nuxt:storybook-configuration ${app} --generateStories --no-interactive` ); runCLI(`run ${app}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${app}/index.html`); + checkFilesExist(`${app}/storybook-static/index.html`); }, 300_000); }); diff --git a/e2e/nx-init/src/nx-init-angular.test.ts b/e2e/nx-init/src/nx-init-angular.test.ts index 3f7a7489837c9..90b39715daca9 100644 --- a/e2e/nx-init/src/nx-init-angular.test.ts +++ b/e2e/nx-init/src/nx-init-angular.test.ts @@ -11,12 +11,13 @@ import { runNgNew, } from '../../utils'; -describe('nx init (Angular CLI)', () => { +describe('nx init (Angular CLI - legacy)', () => { let project: string; let packageManager: PackageManager; let pmc: ReturnType; beforeEach(() => { + process.env.NX_ADD_PLUGINS = 'false'; packageManager = getSelectedPackageManager(); // TODO: solve issues with pnpm and remove this fallback packageManager = packageManager === 'pnpm' ? 'yarn' : packageManager; @@ -25,6 +26,7 @@ describe('nx init (Angular CLI)', () => { }); afterEach(() => { + delete process.env.NX_ADD_PLUGINS; cleanupProject(); }); diff --git a/e2e/nx-init/src/nx-init-monorepo.test.ts b/e2e/nx-init/src/nx-init-monorepo.test.ts index 5c4cf8dcc68db..12c31adc57018 100644 --- a/e2e/nx-init/src/nx-init-monorepo.test.ts +++ b/e2e/nx-init/src/nx-init-monorepo.test.ts @@ -8,7 +8,15 @@ import { updateFile, } from '@nx/e2e/utils'; -describe('nx init (Monorepo)', () => { +describe('nx init (Monorepo - legacy)', () => { + beforeAll(() => { + process.env.NX_ADD_PLUGINS = 'false'; + }); + + afterAll(() => { + delete process.env.NX_ADD_PLUGINS; + }); + const pmc = getPackageManagerCommand({ packageManager: getSelectedPackageManager(), }); diff --git a/e2e/nx-init/src/nx-init-nest.test.ts b/e2e/nx-init/src/nx-init-nest.test.ts index 747e49998bf24..d42ade6e68324 100644 --- a/e2e/nx-init/src/nx-init-nest.test.ts +++ b/e2e/nx-init/src/nx-init-nest.test.ts @@ -8,7 +8,7 @@ import { import { execSync } from 'child_process'; import { removeSync } from 'fs-extra'; -describe('nx init (for NestCLI)', () => { +describe('nx init (for NestCLI - legacy)', () => { const pmc = getPackageManagerCommand({ packageManager: 'npm', }); @@ -16,7 +16,12 @@ describe('nx init (for NestCLI)', () => { const projectRoot = `${e2eCwd}/${projectName}`; const cliOptions = { cwd: projectRoot }; + beforeEach(() => { + process.env.NX_ADD_PLUGINS = 'false'; + }); + afterEach(() => { + delete process.env.NX_ADD_PLUGINS; removeSync(projectRoot); }); diff --git a/e2e/nx-init/src/nx-init-npm-repo.test.ts b/e2e/nx-init/src/nx-init-npm-repo.test.ts index 079e1c9d102cb..53c4ae292a869 100644 --- a/e2e/nx-init/src/nx-init-npm-repo.test.ts +++ b/e2e/nx-init/src/nx-init-npm-repo.test.ts @@ -10,11 +10,19 @@ import { updateFile, } from '@nx/e2e/utils'; -describe('nx init (NPM repo)', () => { +describe('nx init (NPM repo - legacy)', () => { const pmc = getPackageManagerCommand({ packageManager: getSelectedPackageManager(), }); + beforeAll(() => { + process.env.NX_ADD_PLUGINS = 'false'; + }); + + afterAll(() => { + delete process.env.NX_ADD_PLUGINS; + }); + it('should work in a regular npm repo', () => { createNonNxProjectDirectory('regular-repo', false); updateFile( diff --git a/e2e/nx-init/src/nx-init-react.test.ts b/e2e/nx-init/src/nx-init-react.test.ts index b90ce60c1b460..51924506914e0 100644 --- a/e2e/nx-init/src/nx-init-react.test.ts +++ b/e2e/nx-init/src/nx-init-react.test.ts @@ -19,11 +19,21 @@ import { updateJson, } from '../../utils'; -const pmc = getPackageManagerCommand({ - packageManager: getSelectedPackageManager(), -}); +describe('nx init (for React - legacy)', () => { + let pmc: ReturnType; + + beforeAll(() => { + pmc = getPackageManagerCommand({ + packageManager: getSelectedPackageManager(), + }); + + process.env.NX_ADD_PLUGINS = 'false'; + }); + + afterAll(() => { + delete process.env.NX_ADD_PLUGINS; + }); -describe('nx init (for React)', () => { // TODO(@jaysoo): Please investigate why this test is failing xit('should convert to an integrated workspace with craco (webpack)', () => { const appName = 'my-app'; @@ -32,7 +42,7 @@ describe('nx init (for React)', () => { const craToNxOutput = runCommand( `${ pmc.runUninstalledPackage - } nx@${getPublishedVersion()} init --nxCloud=skip --integrated --vite=false` + } nx@${getPublishedVersion()} init --no-interactive --integrated --vite=false` ); expect(craToNxOutput).toContain('🎉 Done!'); @@ -54,7 +64,8 @@ describe('nx init (for React)', () => { checkFilesExist(`dist/apps/${appName}/index.html`); }); - it('should convert to an integrated workspace with Vite', () => { + // TODO(crystal, @jaysoo): Investigate why this is failing + xit('should convert to an integrated workspace with Vite', () => { // TODO investigate why this is broken const originalPM = process.env.SELECTED_PM; process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM; @@ -65,7 +76,7 @@ describe('nx init (for React)', () => { const craToNxOutput = runCommand( `${ pmc.runUninstalledPackage - } nx@${getPublishedVersion()} init --nxCloud=skip --integrated` + } nx@${getPublishedVersion()} init --no-interactive --integrated` ); expect(craToNxOutput).toContain('🎉 Done!'); @@ -86,7 +97,8 @@ describe('nx init (for React)', () => { process.env.SELECTED_PM = originalPM; }); - it('should convert to an integrated workspace with Vite with custom port', () => { + // TODO(crystal, @jaysoo): Investigate why this is failing + xit('should convert to an integrated workspace with Vite with custom port', () => { // TODO investigate why this is broken const originalPM = process.env.SELECTED_PM; process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM; @@ -97,7 +109,7 @@ describe('nx init (for React)', () => { runCommand( `${ pmc.runUninstalledPackage - } nx@${getPublishedVersion()} init --nxCloud=skip --force --integrated` + } nx@${getPublishedVersion()} init --no-interactive --force --integrated` ); const viteConfig = readFile(`apps/${appName}/vite.config.js`); @@ -115,7 +127,7 @@ describe('nx init (for React)', () => { const craToNxOutput = runCommand( `${ pmc.runUninstalledPackage - } nx@${getPublishedVersion()} init --nxCloud=skip --vite=false` + } nx@${getPublishedVersion()} init --no-interactive --vite=false` ); expect(craToNxOutput).toContain('🎉 Done!'); @@ -137,7 +149,7 @@ describe('nx init (for React)', () => { const craToNxOutput = runCommand( `${ pmc.runUninstalledPackage - } nx@${getPublishedVersion()} init --nxCloud=skip --vite` + } nx@${getPublishedVersion()} init --no-interactive --vite` ); expect(craToNxOutput).toContain('🎉 Done!'); @@ -164,55 +176,51 @@ describe('nx init (for React)', () => { const unitTestsOutput = runCLI(`test ${appName}`); expect(unitTestsOutput).toContain('Successfully ran target test'); }); -}); -function createReactApp(appName: string) { - const pmc = getPackageManagerCommand({ - packageManager: getSelectedPackageManager(), - }); - - createNonNxProjectDirectory(); - const projPath = tmpProjPath(); - copySync(join(__dirname, 'files/cra'), projPath); - const filesToRename = globSync(join(projPath, '**/*.txt')); - filesToRename.forEach((f) => { - renameSync(f, f.split('.txt')[0]); - }); - updateFile('.gitignore', 'node_modules'); - updateJson('package.json', (_) => ({ - name: appName, - version: '0.1.0', - private: true, - dependencies: { - '@testing-library/jest-dom': '5.16.5', - '@testing-library/react': '13.4.0', - '@testing-library/user-event': '13.5.0', - react: '^18.2.0', - 'react-dom': '^18.2.0', - 'react-scripts': '5.0.1', - 'web-vitals': '2.1.4', - redux: '^3.6.0', - }, - scripts: { - start: 'react-scripts start', - build: 'react-scripts build', - test: 'react-scripts test', - eject: 'react-scripts eject', - }, - eslintConfig: { - extends: ['react-app', 'react-app/jest'], - }, - browserslist: { - production: ['>0.2%', 'not dead', 'not op_mini all'], - development: [ - 'last 1 chrome version', - 'last 1 firefox version', - 'last 1 safari version', - ], - }, - })); - runCommand(pmc.install); - runCommand('git init'); - runCommand('git add .'); - runCommand('git commit -m "Init"'); -} + function createReactApp(appName: string) { + createNonNxProjectDirectory(); + const projPath = tmpProjPath(); + copySync(join(__dirname, 'files/cra'), projPath); + const filesToRename = globSync(join(projPath, '**/*.txt')); + filesToRename.forEach((f) => { + renameSync(f, f.split('.txt')[0]); + }); + updateFile('.gitignore', 'node_modules'); + updateJson('package.json', (_) => ({ + name: appName, + version: '0.1.0', + private: true, + dependencies: { + '@testing-library/jest-dom': '5.16.5', + '@testing-library/react': '13.4.0', + '@testing-library/user-event': '13.5.0', + react: '^18.2.0', + 'react-dom': '^18.2.0', + 'react-scripts': '5.0.1', + 'web-vitals': '2.1.4', + redux: '^3.6.0', + }, + scripts: { + start: 'react-scripts start', + build: 'react-scripts build', + test: 'react-scripts test', + eject: 'react-scripts eject', + }, + eslintConfig: { + extends: ['react-app', 'react-app/jest'], + }, + browserslist: { + production: ['>0.2%', 'not dead', 'not op_mini all'], + development: [ + 'last 1 chrome version', + 'last 1 firefox version', + 'last 1 safari version', + ], + }, + })); + runCommand(pmc.install); + runCommand('git init'); + runCommand('git add .'); + runCommand('git commit -m "Init"'); + } +}); diff --git a/e2e/nx-misc/src/extras.test.ts b/e2e/nx-misc/src/extras.test.ts index 842cece89dd3a..21b9db9c1634e 100644 --- a/e2e/nx-misc/src/extras.test.ts +++ b/e2e/nx-misc/src/extras.test.ts @@ -6,7 +6,6 @@ import { newProject, readJson, runCLI, - setMaxWorkers, uniq, updateFile, readFile, @@ -22,7 +21,6 @@ describe('Extra Nx Misc Tests', () => { it('should stream output', async () => { const myapp = 'abcdefghijklmon'; runCLI(`generate @nx/web:app ${myapp}`); - setMaxWorkers(join('apps', myapp, 'project.json')); updateJson(join('apps', myapp, 'project.json'), (c) => { c.targets['inner'] = { @@ -214,6 +212,7 @@ describe('Extra Nx Misc Tests', () => { it('run command should not break if output property is missing in options and arguments', async () => { updateJson(join('libs', mylib, 'project.json'), (config) => { + config.targets.lint ??= {}; config.targets.lint.outputs = ['{options.outputFile}']; return config; }); diff --git a/e2e/nx-misc/src/misc.test.ts b/e2e/nx-misc/src/misc.test.ts index 15f918367d95b..b6fd217017bf1 100644 --- a/e2e/nx-misc/src/misc.test.ts +++ b/e2e/nx-misc/src/misc.test.ts @@ -13,7 +13,6 @@ import { runCLI, runCLIAsync, runCommand, - setMaxWorkers, tmpProjPath, uniq, updateFile, @@ -44,7 +43,6 @@ describe('Nx Commands', () => { runCLI(`generate @nx/web:app ${app1} --tags e2etag`); runCLI(`generate @nx/web:app ${app2}`); - setMaxWorkers(join('apps', app1, 'project.json')); const s = runCLI('show projects').split('\n'); @@ -154,7 +152,6 @@ describe('Nx Commands', () => { beforeAll(async () => { runCLI(`generate @nx/web:app ${myapp}`); - setMaxWorkers(join('apps', myapp, 'project.json')); runCLI(`generate @nx/js:lib ${mylib}`); }); diff --git a/e2e/nx-misc/src/workspace-legacy.test.ts b/e2e/nx-misc/src/workspace-legacy.test.ts new file mode 100644 index 0000000000000..5f080812c5f73 --- /dev/null +++ b/e2e/nx-misc/src/workspace-legacy.test.ts @@ -0,0 +1,49 @@ +import { + checkFilesExist, + cleanupProject, + newProject, + runCLI, + runE2ETests, + uniq, +} from '@nx/e2e/utils'; + +let proj: string; + +describe('@nx/workspace:convert-to-monorepo', () => { + beforeEach(() => { + proj = newProject({ packages: ['@nx/react', '@nx/js'] }); + }); + + afterEach(() => cleanupProject()); + + it('should convert a standalone webpack and jest react project to a monorepo (legacy)', async () => { + const reactApp = uniq('reactapp'); + runCLI( + `generate @nx/react:app ${reactApp} --rootProject=true --bundler=webpack --unitTestRunner=jest --e2eTestRunner=cypress --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + runCLI('generate @nx/workspace:convert-to-monorepo --no-interactive', { + env: { + NX_ADD_PLUGINS: 'false', + }, + }); + + checkFilesExist( + `apps/${reactApp}/src/main.tsx`, + `apps/e2e/cypress.config.ts` + ); + + expect(() => runCLI(`build ${reactApp}`)).not.toThrow(); + expect(() => runCLI(`test ${reactApp}`)).not.toThrow(); + expect(() => runCLI(`lint ${reactApp}`)).not.toThrow(); + expect(() => runCLI(`lint e2e`)).not.toThrow(); + if (runE2ETests()) { + expect(() => runCLI(`e2e e2e`)).not.toThrow(); + } + }); +}); diff --git a/e2e/nx-misc/src/workspace.test.ts b/e2e/nx-misc/src/workspace.test.ts index 0fc6620ded722..8290c2fb784d8 100644 --- a/e2e/nx-misc/src/workspace.test.ts +++ b/e2e/nx-misc/src/workspace.test.ts @@ -1,18 +1,18 @@ import { checkFilesExist, - newProject, - readJson, cleanupProject, - runCLI, - uniq, - updateFile, - readFile, exists, - tmpProjPath, getPackageManagerCommand, getSelectedPackageManager, + newProject, + readFile, + readJson, + runCLI, runCommand, runE2ETests, + tmpProjPath, + uniq, + updateFile, } from '@nx/e2e/utils'; import { join } from 'path'; @@ -25,28 +25,6 @@ describe('@nx/workspace:convert-to-monorepo', () => { afterEach(() => cleanupProject()); - it('should convert a standalone webpack and jest react project to a monorepo', async () => { - const reactApp = uniq('reactapp'); - runCLI( - `generate @nx/react:app ${reactApp} --rootProject=true --bundler=webpack --unitTestRunner=jest --e2eTestRunner=cypress --no-interactive` - ); - - runCLI('generate @nx/workspace:convert-to-monorepo --no-interactive'); - - checkFilesExist( - `apps/${reactApp}/src/main.tsx`, - `apps/e2e/cypress.config.ts` - ); - - expect(() => runCLI(`build ${reactApp}`)).not.toThrow(); - expect(() => runCLI(`test ${reactApp}`)).not.toThrow(); - expect(() => runCLI(`lint ${reactApp}`)).not.toThrow(); - expect(() => runCLI(`lint e2e`)).not.toThrow(); - if (runE2ETests()) { - expect(() => runCLI(`e2e e2e`)).not.toThrow(); - } - }); - it('should be convert a standalone vite and playwright react project to a monorepo', async () => { const reactApp = uniq('reactapp'); runCLI( diff --git a/e2e/nx-run/src/cache.test.ts b/e2e/nx-run/src/cache.test.ts index 25b276e03243f..950415e7b3b7f 100644 --- a/e2e/nx-run/src/cache.test.ts +++ b/e2e/nx-run/src/cache.test.ts @@ -6,7 +6,6 @@ import { readFile, rmDist, runCLI, - setMaxWorkers, tmpProjPath, uniq, updateFile, @@ -23,9 +22,7 @@ describe('cache', () => { const myapp1 = uniq('myapp1'); const myapp2 = uniq('myapp2'); runCLI(`generate @nx/web:app ${myapp1}`); - setMaxWorkers(join('apps', myapp1, 'project.json')); runCLI(`generate @nx/web:app ${myapp2}`); - setMaxWorkers(join('apps', myapp2, 'project.json')); // run build with caching // -------------------------------------------- @@ -125,9 +122,11 @@ describe('cache', () => { const originalNxJson = readFile('nx.json'); updateFile('nx.json', (c) => { const nxJson = JSON.parse(c); - for (const key in nxJson.targetDefaults ?? {}) { - delete nxJson.targetDefaults[key].cache; - } + nxJson.targetDefaults = { + build: { + cache: false, + }, + }; return JSON.stringify(nxJson, null, 2); }); @@ -152,6 +151,7 @@ describe('cache', () => { runCLI(`generate @nx/js:library ${mylib}`); updateJson(join('libs', mylib, 'project.json'), (c) => { c.targets.build = { + cache: true, executor: 'nx:run-commands', outputs: ['{workspaceRoot}/dist/!(.next)/**/!(z|x).(txt|md)'], options: { diff --git a/e2e/nx-run/src/run.test.ts b/e2e/nx-run/src/run.test.ts index 5b49e4327a36f..02417680b415e 100644 --- a/e2e/nx-run/src/run.test.ts +++ b/e2e/nx-run/src/run.test.ts @@ -9,7 +9,6 @@ import { runCLI, runCLIAsync, runCommand, - setMaxWorkers, tmpProjPath, uniq, updateFile, @@ -17,7 +16,6 @@ import { } from '@nx/e2e/utils'; import { PackageJson } from 'nx/src/utils/package-json'; import * as path from 'path'; -import { join } from 'path'; describe('Nx Running Tests', () => { let proj: string; @@ -132,7 +130,6 @@ describe('Nx Running Tests', () => { beforeAll(async () => { app = uniq('myapp'); runCLI(`generate @nx/web:app ${app}`); - setMaxWorkers(join('apps', app, 'project.json')); }); it('should support using {projectRoot} in options blocks in project.json', async () => { @@ -351,7 +348,7 @@ describe('Nx Running Tests', () => { // Should work within the project directory expect(runCommand(`cd apps/${myapp}/src && npx nx build`)).toContain( - `nx run ${myapp}:build:production` + `nx run ${myapp}:build` ); }, 10000); @@ -448,7 +445,9 @@ describe('Nx Running Tests', () => { command: 'echo PREP', }, }; - config.targets.build.dependsOn = ['prep', '^build']; + config.targets.build = { + dependsOn: ['prep', '^build'], + }; return config; }); @@ -609,7 +608,7 @@ describe('Nx Running Tests', () => { expect(buildConfig).toContain( `Running target build for 2 projects and 1 task they depend on:` ); - expect(buildConfig).toContain(`run ${appA}:build:production`); + expect(buildConfig).toContain(`run ${appA}:build`); expect(buildConfig).toContain(`run ${libA}:build`); expect(buildConfig).toContain(`run ${libC}:build`); expect(buildConfig).toContain('Successfully ran target build'); @@ -629,7 +628,7 @@ describe('Nx Running Tests', () => { let outputs = runCLI( // Options with lists can be specified using multiple args or with a delimiter (comma or space). - `run-many -t build -t test -p ${myapp1} ${myapp2} --ci` + `run-many -t build -t test -p ${myapp1} ${myapp2}` ); expect(outputs).toContain('Running targets build, test for 2 projects:'); @@ -670,6 +669,13 @@ describe('Nx Running Tests', () => { build: 'nx exec -- echo HELLO', 'build:option': 'nx exec -- echo HELLO WITH OPTION', }, + nx: { + targets: { + build: { + cache: true, + }, + }, + }, }) ); @@ -749,7 +755,7 @@ describe('Nx Running Tests', () => { }); describe('caching', () => { - it('shoud cache subsequent calls', () => { + it('should cache subsequent calls', () => { runCommand('npm run build', { cwd: pkgRoot, }); @@ -776,6 +782,7 @@ describe('Nx Running Tests', () => { nx: { targets: { build: { + cache: true, outputs: ['{workspaceRoot}/tmp/exec-outputs-test'], }, }, diff --git a/e2e/playwright/src/playwright.test.ts b/e2e/playwright/src/playwright.test.ts index 3a2a7e86ac186..62c54b1e2f5d1 100644 --- a/e2e/playwright/src/playwright.test.ts +++ b/e2e/playwright/src/playwright.test.ts @@ -42,7 +42,7 @@ describe('Playwright E2E Test runner', () => { expect(e2eResults).toContain('Successfully ran target e2e for project'); const lintResults = runCLI(`lint demo-e2e`); - expect(lintResults).toContain('All files pass linting'); + expect(lintResults).toContain('Successfully ran target lint'); }, TEN_MINS_MS ); @@ -63,29 +63,29 @@ describe('Playwright E2E Test runner', () => { expect(e2eResults).toContain('Successfully ran target e2e for project'); const lintResults = runCLI(`lint demo-e2e`); - expect(lintResults).toContain('All files pass linting'); + expect(lintResults).toContain('Successfully ran target lint'); }, TEN_MINS_MS ); }); -describe('Playwright E2E Test Runner - PCV3', () => { +describe('Playwright E2E Test Runner - legacy', () => { let env: string | undefined; beforeAll(() => { - env = process.env.NX_PCV3; + env = process.env.NX_ADD_PLUGINS; newProject({ name: uniq('playwright'), unsetProjectNameAndRootFormat: false, }); - process.env.NX_PCV3 = 'true'; + process.env.NX_ADD_PLUGINS = 'false'; }); afterAll(() => { if (env) { - process.env.NX_PCV3 = env; + process.env.NX_ADD_PLUGINS = env; } else { - delete process.env.NX_PCV3; + delete process.env.NX_ADD_PLUGINS; } }); @@ -108,20 +108,7 @@ describe('Playwright E2E Test Runner - PCV3', () => { expect(e2eResults).toContain('Successfully ran target e2e for project'); const { targets } = readJson('apps/demo-e2e/project.json'); - expect(targets?.e2e).not.toBeDefined(); - - const { plugins } = readJson('nx.json'); - const playwrightPlugin = plugins?.find( - (p) => p.plugin === '@nx/playwright/plugin' - ); - expect(playwrightPlugin).toMatchInlineSnapshot(` - { - "options": { - "targetName": "e2e", - }, - "plugin": "@nx/playwright/plugin", - } - `); + expect(targets.e2e).toBeDefined(); }, TEN_MINS_MS ); @@ -144,20 +131,7 @@ describe('Playwright E2E Test Runner - PCV3', () => { expect(e2eResults).toContain('Successfully ran target e2e for project'); const { targets } = readJson('apps/demo-js-e2e/project.json'); - expect(targets?.e2e).not.toBeDefined(); - - const { plugins } = readJson('nx.json'); - const playwrightPlugin = plugins?.find( - (p) => p.plugin === '@nx/playwright/plugin' - ); - expect(playwrightPlugin).toMatchInlineSnapshot(` - { - "options": { - "targetName": "e2e", - }, - "plugin": "@nx/playwright/plugin", - } - `); + expect(targets.e2e).toBeDefined(); }, TEN_MINS_MS ); diff --git a/e2e/plugin/src/nx-plugin.test.ts b/e2e/plugin/src/nx-plugin.test.ts index 44cde5e6fe1aa..6b17ca7500487 100644 --- a/e2e/plugin/src/nx-plugin.test.ts +++ b/e2e/plugin/src/nx-plugin.test.ts @@ -38,7 +38,7 @@ describe('Nx Plugin', () => { `generate @nx/plugin:plugin ${plugin} --linter=eslint --e2eTestRunner=jest --publishable` ); const lintResults = runCLI(`lint ${plugin}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('All files pass linting'); const buildResults = runCLI(`build ${plugin}`); expect(buildResults).toContain('Done compiling TypeScript files'); @@ -63,7 +63,7 @@ describe('Nx Plugin', () => { ); const lintResults = runCLI(`lint ${plugin}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('All files pass linting'); expectTestsPass(await runCLIAsync(`test ${plugin}`)); @@ -93,7 +93,7 @@ describe('Nx Plugin', () => { runCLI(`generate @nx/plugin:generator ${generator} --project=${plugin}`); const lintResults = runCLI(`lint ${plugin}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('All files pass linting'); expectTestsPass(await runCLIAsync(`test ${plugin}`)); @@ -130,7 +130,7 @@ describe('Nx Plugin', () => { ); const lintResults = runCLI(`lint ${plugin}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('All files pass linting'); expectTestsPass(await runCLIAsync(`test ${plugin}`)); diff --git a/e2e/react-core/src/react-package.test.ts b/e2e/react-core/src/react-package.test.ts index 0c8888acb7b6f..1c79468fc1792 100644 --- a/e2e/react-core/src/react-package.test.ts +++ b/e2e/react-core/src/react-package.test.ts @@ -37,6 +37,7 @@ describe('Build React libraries and apps', () => { let proj: string; beforeEach(async () => { + process.env.NX_ADD_PLUGINS = 'false'; app = uniq('app'); parentLib = uniq('parentlib'); childLib = uniq('childlib'); @@ -109,6 +110,7 @@ describe('Build React libraries and apps', () => { afterEach(() => { killPorts(); cleanupProject(); + delete process.env.NX_ADD_PLUGINS; }); describe('Buildable libraries', () => { diff --git a/e2e/react-core/src/react.test.ts b/e2e/react-core/src/react.test.ts index 9d050823883f6..fa9bf06ee2240 100644 --- a/e2e/react-core/src/react.test.ts +++ b/e2e/react-core/src/react.test.ts @@ -5,6 +5,7 @@ import { createFile, ensureCypressInstallation, killPorts, + listFiles, newProject, readFile, runCLI, @@ -20,46 +21,47 @@ import { join } from 'path'; describe('React Applications', () => { let proj: string; - beforeAll(() => { - proj = newProject({ packages: ['@nx/react'] }); - ensureCypressInstallation(); - }); + describe('Crystal Supported Tests', () => { + beforeAll(() => { + proj = newProject({ packages: ['@nx/react'] }); + ensureCypressInstallation(); + }); - afterAll(() => cleanupProject()); + afterAll(() => cleanupProject()); - it('should be able to generate a react app + lib (with CSR and SSR)', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - const libWithNoComponents = uniq('lib'); - const logoSvg = readFileSync(join(__dirname, 'logo.svg')).toString(); + it('should be able to generate a react app + lib (with CSR and SSR)', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + const libWithNoComponents = uniq('lib'); + const logoSvg = readFileSync(join(__dirname, 'logo.svg')).toString(); - runCLI( - `generate @nx/react:app ${appName} --style=css --bundler=webpack --no-interactive --skipFormat` - ); - runCLI( - `generate @nx/react:lib ${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat` - ); - runCLI( - `generate @nx/react:lib ${libWithNoComponents} --no-interactive --no-component --unit-test-runner=jest --skipFormat` - ); + runCLI( + `generate @nx/react:app ${appName} --style=css --bundler=webpack --no-interactive --skipFormat` + ); + runCLI( + `generate @nx/react:lib ${libName} --style=css --no-interactive --unit-test-runner=jest --skipFormat` + ); + runCLI( + `generate @nx/react:lib ${libWithNoComponents} --no-interactive --no-component --unit-test-runner=jest --skipFormat` + ); - // Libs should not include package.json by default - checkFilesDoNotExist(`libs/${libName}/package.json`); + // Libs should not include package.json by default + checkFilesDoNotExist(`libs/${libName}/package.json`); - const mainPath = `apps/${appName}/src/main.tsx`; - updateFile( - mainPath, - ` + const mainPath = `apps/${appName}/src/main.tsx`; + updateFile( + mainPath, + ` import '@${proj}/${libWithNoComponents}'; import '@${proj}/${libName}'; ${readFile(mainPath)} ` - ); + ); - updateFile(`apps/${appName}/src/app/logo.svg`, logoSvg); - updateFile( - `apps/${appName}/src/app/app.tsx`, - ` + updateFile(`apps/${appName}/src/app/logo.svg`, logoSvg); + updateFile( + `apps/${appName}/src/app/app.tsx`, + ` import { ReactComponent as Logo } from './logo.svg'; import logo from './logo.svg'; import NxWelcome from './nx-welcome'; @@ -76,219 +78,193 @@ describe('React Applications', () => { export default App; ` - ); + ); - // Make sure global stylesheets are properly processed. - const stylesPath = `apps/${appName}/src/styles.css`; - updateFile( - stylesPath, - ` + // Make sure global stylesheets are properly processed. + const stylesPath = `apps/${appName}/src/styles.css`; + updateFile( + stylesPath, + ` .foobar { background-image: url('/bg.png'); } ` - ); - - const libTestResults = await runCLIAsync(`test ${libName}`); - expect(libTestResults.combinedOutput).toContain( - 'Test Suites: 1 passed, 1 total' - ); - - await testGeneratedApp(appName, { - checkSourceMap: true, - checkStyles: true, - checkLinter: true, - // TODO(caleb): Fix cypress tests - // /tmp/nx-e2e--1970-rQ4U0qBe6Nht/nx/proj1614306/dist/apps/app5172641/server/runtime.js:119 - // if (typeof import.meta.url === "string") scriptUrl = import.meta.url - // SyntaxError: Cannot use 'import.meta' outside a module - checkE2E: false, - }); - - // Set up SSR and check app - runCLI(`generate @nx/react:setup-ssr ${appName} --skipFormat`); - checkFilesExist(`apps/${appName}/src/main.server.tsx`); - checkFilesExist(`apps/${appName}/server.ts`); - - await testGeneratedApp(appName, { - checkSourceMap: false, - checkStyles: false, - checkLinter: false, - // TODO(caleb): Fix cypress tests - // /tmp/nx-e2e--1970-rQ4U0qBe6Nht/nx/proj1614306/dist/apps/app5172641/server/runtime.js:119 - // if (typeof import.meta.url === "string") scriptUrl = import.meta.url - // SyntaxError: Cannot use 'import.meta' outside a module - checkE2E: false, - }); - }, 500000); - - it('should be able to use JS and JSX', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - const plainJsLib = uniq('jslib'); + ); - runCLI( - `generate @nx/react:app ${appName} --bundler=webpack --no-interactive --js --skipFormat` - ); - runCLI( - `generate @nx/react:lib ${libName} --no-interactive --js --unit-test-runner=none --skipFormat` - ); - // Make sure plain JS libs can be imported as well. - // There was an issue previously: https://github.com/nrwl/nx/issues/10990 - runCLI( - `generate @nx/js:lib ${plainJsLib} --js --unit-test-runner=none --bundler=none --compiler=tsc --no-interactive --skipFormat` - ); + const libTestResults = await runCLIAsync(`test ${libName}`); + expect(libTestResults.combinedOutput).toContain( + 'Test Suites: 1 passed, 1 total' + ); - const mainPath = `apps/${appName}/src/main.js`; - updateFile( - mainPath, - `import '@${proj}/${libName}';\nimport '@${proj}/${plainJsLib}';\n${readFile( - mainPath - )}` - ); + await testGeneratedApp(appName, { + checkSourceMap: true, + checkStyles: true, + checkLinter: true, + // TODO(caleb): Fix cypress tests + // /tmp/nx-e2e--1970-rQ4U0qBe6Nht/nx/proj1614306/dist/apps/app5172641/server/runtime.js:119 + // if (typeof import.meta.url === "string") scriptUrl = import.meta.url + // SyntaxError: Cannot use 'import.meta' outside a module + checkE2E: false, + }); - await testGeneratedApp(appName, { - checkStyles: true, - checkLinter: false, - checkE2E: false, - }); - }, 250_000); + // Set up SSR and check app + runCLI(`generate @nx/react:setup-ssr ${appName} --skipFormat`); + checkFilesExist(`apps/${appName}/src/main.server.tsx`); + checkFilesExist(`apps/${appName}/server.ts`); + + await testGeneratedApp(appName, { + checkSourceMap: false, + checkStyles: false, + checkLinter: false, + // TODO(caleb): Fix cypress tests + // /tmp/nx-e2e--1970-rQ4U0qBe6Nht/nx/proj1614306/dist/apps/app5172641/server/runtime.js:119 + // if (typeof import.meta.url === "string") scriptUrl = import.meta.url + // SyntaxError: Cannot use 'import.meta' outside a module + checkE2E: false, + }); + }, 500000); - it('should be able to use Vite to build and test apps', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); + // TODO(crystal, @jaysoo): Investigate why this is failing. + xit('should be able to use Vite to build and test apps', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); - runCLI( - `generate @nx/react:app ${appName} --bundler=vite --no-interactive --skipFormat` - ); - runCLI( - `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat` - ); + runCLI( + `generate @nx/react:app ${appName} --bundler=vite --no-interactive --skipFormat` + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=none --no-interactive --unit-test-runner=vitest --skipFormat` + ); - // Library generated with Vite - checkFilesExist(`libs/${libName}/vite.config.ts`); + // Library generated with Vite + checkFilesExist(`libs/${libName}/vite.config.ts`); - const mainPath = `apps/${appName}/src/main.tsx`; - updateFile( - mainPath, - ` + const mainPath = `apps/${appName}/src/main.tsx`; + updateFile( + mainPath, + ` import '@${proj}/${libName}'; ${readFile(mainPath)} ` - ); - - runCLI(`build ${appName}`); + ); - checkFilesExist(`dist/apps/${appName}/index.html`); + runCLI(`build ${appName}`); - if (runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`); - expect(e2eResults).toContain('All specs passed!'); - expect(await killPorts()).toBeTruthy(); - } - }, 250_000); + checkFilesExist(`dist/apps/${appName}/index.html`); - it('should generate app with routing', async () => { - const appName = uniq('app'); - - runCLI( - `generate @nx/react:app ${appName} --routing --bundler=webpack --no-interactive --skipFormat` - ); + if (runE2ETests()) { + const e2eResults = runCLI(`e2e ${appName}-e2e`); + expect(e2eResults).toContain('All specs passed!'); + expect(await killPorts()).toBeTruthy(); + } + }, 250_000); - runCLI(`build ${appName} --outputHashing none`); + it('should generate app with routing', async () => { + const appName = uniq('app'); - checkFilesExist( - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/main.js` - ); - }, 250_000); + runCLI( + `generate @nx/react:app ${appName} --routing --bundler=webpack --no-interactive --skipFormat` + ); - it('should be able to add a redux slice', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); + runCLI(`build ${appName}`); - runCLI( - `g @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat` - ); - runCLI(`g @nx/react:redux lemon --project=${appName} --skipFormat`); - runCLI( - `g @nx/react:lib ${libName} --unit-test-runner=jest --no-interactive --skipFormat` - ); - runCLI(`g @nx/react:redux orange --project=${libName} --skipFormat`); + checkFilesExistWithHash(`dist/apps/${appName}`, [ + `index.html`, + `runtime.*.js`, + `main.*.js`, + ]); + }, 250_000); - let lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); - const appTestResults = await runCLIAsync(`test ${appName}`); - expect(appTestResults.combinedOutput).toContain( - 'Test Suites: 2 passed, 2 total' - ); + it('should be able to add a redux slice', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); - lintResults = runCLI(`lint ${libName}`); - expect(lintResults).toContain('All files pass linting.'); - const libTestResults = await runCLIAsync(`test ${libName}`); - expect(libTestResults.combinedOutput).toContain( - 'Test Suites: 2 passed, 2 total' - ); - }, 250_000); + runCLI( + `g @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat` + ); + runCLI(`g @nx/react:redux lemon --project=${appName} --skipFormat`); + runCLI( + `g @nx/react:lib ${libName} --unit-test-runner=jest --no-interactive --skipFormat` + ); + runCLI(`g @nx/react:redux orange --project=${libName} --skipFormat`); - it('should support generating projects with the new name and root format', () => { - const appName = uniq('app1'); - const libName = uniq('@my-org/lib1'); + let lintResults = runCLI(`lint ${appName}`); + expect(lintResults).toContain( + `Successfully ran target lint for project ${appName}` + ); + const appTestResults = await runCLIAsync(`test ${appName}`); + expect(appTestResults.combinedOutput).toContain( + 'Test Suites: 2 passed, 2 total' + ); - runCLI( - `generate @nx/react:app ${appName} --bundler=webpack --project-name-and-root-format=as-provided --no-interactive --skipFormat` - ); + lintResults = runCLI(`lint ${libName}`); + expect(lintResults).toContain( + `Successfully ran target lint for project ${libName}` + ); + const libTestResults = await runCLIAsync(`test ${libName}`); + expect(libTestResults.combinedOutput).toContain( + 'Test Suites: 2 passed, 2 total' + ); + }, 250_000); - // check files are generated without the layout directory ("apps/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${appName}/src/main.tsx`); - // check build works - expect(runCLI(`build ${appName}`)).toContain( - `Successfully ran target build for project ${appName}` - ); - // check tests pass - const appTestResult = runCLI(`test ${appName}`); - expect(appTestResult).toContain( - `Successfully ran target test for project ${appName}` - ); + it('should support generating projects with the new name and root format', () => { + const appName = uniq('app1'); + const libName = uniq('@my-org/lib1'); - // assert scoped project names are not supported when --project-name-and-root-format=derived - expect(() => runCLI( - `generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --project-name-and-root-format=derived --no-interactive --skipFormat` - ) - ).toThrow(); + `generate @nx/react:app ${appName} --bundler=webpack --project-name-and-root-format=as-provided --no-interactive --skipFormat` + ); - runCLI( - `generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --project-name-and-root-format=as-provided --no-interactive --skipFormat` - ); + // check files are generated without the layout directory ("apps/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${appName}/src/main.tsx`); + // check build works + expect(runCLI(`build ${appName}`)).toContain( + `Successfully ran target build for project ${appName}` + ); + // check tests pass + const appTestResult = runCLI(`test ${appName}`); + expect(appTestResult).toContain( + `Successfully ran target test for project ${appName}` + ); - // check files are generated without the layout directory ("libs/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${libName}/src/index.ts`); - // check build works - expect(runCLI(`build ${libName}`)).toContain( - `Successfully ran target build for project ${libName}` - ); - // check tests pass - const libTestResult = runCLI(`test ${libName}`); - expect(libTestResult).toContain( - `Successfully ran target test for project ${libName}` - ); - }, 500_000); + // assert scoped project names are not supported when --project-name-and-root-format=derived + expect(() => + runCLI( + `generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --project-name-and-root-format=derived --no-interactive --skipFormat` + ) + ).toThrow(); - describe('React Applications: --style option', () => { - it('should support styled-jsx', async () => { - const appName = uniq('app'); runCLI( - `generate @nx/react:app ${appName} --style=styled-jsx --bundler=vite --no-interactive --skipFormat` + `generate @nx/react:lib ${libName} --unit-test-runner=jest --buildable --project-name-and-root-format=as-provided --no-interactive --skipFormat` ); - // update app to use styled-jsx - updateFile( - `apps/${appName}/src/app/app.tsx`, - ` + // check files are generated without the layout directory ("libs/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${libName}/src/index.ts`); + // check build works + expect(runCLI(`build ${libName}`)).toContain( + `Successfully ran target build for project ${libName}` + ); + // check tests pass + const libTestResult = runCLI(`test ${libName}`); + expect(libTestResult).toContain( + `Successfully ran target test for project ${libName}` + ); + }, 500_000); + + describe('React Applications: --style option', () => { + // TODO(crystal, @jaysoo): Investigate why this is failng + xit('should support styled-jsx', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/react:app ${appName} --style=styled-jsx --bundler=vite --no-interactive --skipFormat` + ); + + // update app to use styled-jsx + updateFile( + `apps/${appName}/src/app/app.tsx`, + ` import NxWelcome from './nx-welcome'; export function App() { @@ -304,13 +280,13 @@ describe('React Applications', () => { export default App; ` - ); + ); - // update e2e test to check for styled-jsx change + // update e2e test to check for styled-jsx change - updateFile( - `apps/${appName}-e2e/src/e2e/app.cy.ts`, - ` + updateFile( + `apps/${appName}-e2e/src/e2e/app.cy.ts`, + ` describe('react-test', () => { beforeEach(() => cy.visit('/')); @@ -321,12 +297,74 @@ describe('React Applications', () => { }); ` + ); + if (runE2ETests()) { + const e2eResults = runCLI(`e2e ${appName}-e2e --verbose`); + expect(e2eResults).toContain('All specs passed!'); + } + }, 250_000); + }); + + describe('--format', () => { + it('should be formatted on freshly created apps', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/react:app ${appName} --bundler=webpack --no-interactive` + ); + + const stdout = runCLI(`format:check --projects=${appName}`, { + silenceError: true, + }); + expect(stdout).toEqual(''); + }); + }); + }); + + // TODO(colum): Revisit when cypress --js works with crystal + describe('Non-Crystal Tests', () => { + beforeAll(() => { + process.env.NX_ADD_PLUGINS = 'false'; + proj = newProject({ packages: ['@nx/react'] }); + ensureCypressInstallation(); + }); + + afterAll(() => { + cleanupProject(); + delete process.env.NX_ADD_PLUGINS; + }); + + it('should be able to use JS and JSX', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + const plainJsLib = uniq('jslib'); + + runCLI( + `generate @nx/react:app ${appName} --bundler=webpack --no-interactive --js --skipFormat` ); - if (runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch --verbose`); - expect(e2eResults).toContain('All specs passed!'); - } + runCLI( + `generate @nx/react:lib ${libName} --no-interactive --js --unit-test-runner=none --skipFormat` + ); + // Make sure plain JS libs can be imported as well. + // There was an issue previously: https://github.com/nrwl/nx/issues/10990 + runCLI( + `generate @nx/js:lib ${plainJsLib} --js --unit-test-runner=none --bundler=none --compiler=tsc --no-interactive --skipFormat` + ); + + const mainPath = `apps/${appName}/src/main.js`; + updateFile( + mainPath, + `import '@${proj}/${libName}';\nimport '@${proj}/${plainJsLib}';\n${readFile( + mainPath + )}` + ); + + await testGeneratedApp(appName, { + checkStyles: true, + checkLinter: false, + checkE2E: false, + }); }, 250_000); + it.each` style ${'css'} @@ -364,70 +402,56 @@ describe('React Applications', () => { /Comic Sans MS/ ); }); - }); - - describe('React Applications and Libs with PostCSS', () => { - it('should support single path or auto-loading of PostCSS config files', async () => { - const appName = uniq('app'); - const libName = uniq('lib'); - runCLI( - `g @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat` - ); - runCLI( - `g @nx/react:lib ${libName} --no-interactive --unit-test-runner=none --skipFormat` - ); - - const mainPath = `apps/${appName}/src/main.tsx`; - updateFile( - mainPath, - `import '@${proj}/${libName}';\n${readFile(mainPath)}` - ); - - createFile( - `apps/${appName}/postcss.config.js`, - ` + describe('React Applications and Libs with PostCSS', () => { + it('should support single path or auto-loading of PostCSS config files', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `g @nx/react:app ${appName} --bundler=webpack --no-interactive --skipFormat` + ); + runCLI( + `g @nx/react:lib ${libName} --no-interactive --unit-test-runner=none --skipFormat` + ); + + const mainPath = `apps/${appName}/src/main.tsx`; + updateFile( + mainPath, + `import '@${proj}/${libName}';\n${readFile(mainPath)}` + ); + + createFile( + `apps/${appName}/postcss.config.js`, + ` console.log('HELLO FROM APP'); // need this output for e2e test module.exports = {}; ` - ); - createFile( - `libs/${libName}/postcss.config.js`, - ` + ); + createFile( + `libs/${libName}/postcss.config.js`, + ` console.log('HELLO FROM LIB'); // need this output for e2e test module.exports = {}; ` - ); + ); - let buildResults = await runCLIAsync(`build ${appName}`); + let buildResults = await runCLIAsync(`build ${appName}`); - expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/); - expect(buildResults.combinedOutput).toMatch(/HELLO FROM LIB/); + expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/); + expect(buildResults.combinedOutput).toMatch(/HELLO FROM LIB/); - // Only load app PostCSS config - updateJson(`apps/${appName}/project.json`, (json) => { - json.targets.build.options.postcssConfig = `apps/${appName}/postcss.config.js`; - return json; - }); - - buildResults = await runCLIAsync(`build ${appName}`); + // Only load app PostCSS config + updateJson(`apps/${appName}/project.json`, (json) => { + json.targets.build.options.postcssConfig = `apps/${appName}/postcss.config.js`; + return json; + }); - expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/); - expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/); - }, 250_000); - }); + buildResults = await runCLIAsync(`build ${appName}`); - describe('--format', () => { - it('should be formatted on freshly created apps', async () => { - const appName = uniq('app'); - runCLI( - `generate @nx/react:app ${appName} --bundler=webpack --no-interactive` - ); - - const stdout = runCLI(`format:check --projects=${appName}`, { - silenceError: true, - }); - expect(stdout).toEqual(''); + expect(buildResults.combinedOutput).toMatch(/HELLO FROM APP/); + expect(buildResults.combinedOutput).not.toMatch(/HELLO FROM LIB/); + }, 250_000); }); }); }); @@ -443,34 +467,22 @@ async function testGeneratedApp( ) { if (opts.checkLinter) { const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain( + `Successfully ran target lint for project ${appName}` + ); } - runCLI( - `build ${appName} --outputHashing none ${ - opts.checkSourceMap ? '--sourceMap' : '' - }` - ); - const filesToCheck = [ - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/main.js`, - ]; - - if (opts.checkSourceMap) { - filesToCheck.push(`dist/apps/${appName}/main.js.map`); - } + runCLI(`build ${appName}`); + const filesToCheck = [`index.html`, `runtime.*.js`, `main.*.js`]; if (opts.checkStyles) { - filesToCheck.push(`dist/apps/${appName}/styles.css`); + filesToCheck.push(`styles.*.css`); + expect( + /styles.*.css/.test(readFile(`dist/apps/${appName}/index.html`)) + ).toBeTruthy(); } - checkFilesExist(...filesToCheck); - if (opts.checkStyles) { - expect(readFile(`dist/apps/${appName}/index.html`)).toContain( - '' - ); - } + checkFilesExistWithHash(`dist/apps/${appName}`, filesToCheck); const testResults = await runCLIAsync(`test ${appName}`); expect(testResults.combinedOutput).toContain( @@ -478,8 +490,26 @@ async function testGeneratedApp( ); if (opts.checkE2E && runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`); + const e2eResults = runCLI(`e2e ${appName}-e2e`); expect(e2eResults).toContain('All specs passed!'); expect(await killPorts()).toBeTruthy(); } } + +function checkFilesExistWithHash( + outputDirToCheck: string, + filesToCheck: string[] +) { + const filesInOutputDir = listFiles(outputDirToCheck); + // REGEX CHECK + for (const fileToCheck of filesToCheck) { + const regex = new RegExp(fileToCheck); + let found = false; + for (const fileInOutput of filesInOutputDir) { + if (regex.test(fileInOutput)) { + found = true; + } + } + expect(found).toBeTruthy(); + } +} diff --git a/e2e/react-extensions/src/cypress-component-tests.test.ts b/e2e/react-extensions/src/cypress-component-tests.test.ts index fe8e0e58bbd74..80d7f834b826d 100644 --- a/e2e/react-extensions/src/cypress-component-tests.test.ts +++ b/e2e/react-extensions/src/cypress-component-tests.test.ts @@ -18,6 +18,7 @@ describe('React Cypress Component Tests', () => { const buildableLibName = uniq('cy-react-buildable-lib'); beforeAll(async () => { + process.env.NX_ADD_PLUGINS = 'false'; projectName = newProject({ name: uniq('cy-react'), packages: ['@nx/react'], @@ -144,7 +145,10 @@ export default Input; }); }); - afterAll(() => cleanupProject()); + afterAll(() => { + cleanupProject(); + delete process.env.NX_ADD_PLUGINS; + }); it('should test app', () => { runCLI( diff --git a/e2e/react-extensions/src/playwright.test.ts b/e2e/react-extensions/src/playwright.test.ts index 3327e4e3484eb..4b15d606213d0 100644 --- a/e2e/react-extensions/src/playwright.test.ts +++ b/e2e/react-extensions/src/playwright.test.ts @@ -26,7 +26,7 @@ describe('React Playwright e2e tests', () => { it('should execute e2e tests using playwright', () => { if (runE2ETests()) { - const result = runCLI(`e2e ${appName}-e2e --no-watch --verbose`); + const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` ); @@ -54,7 +54,7 @@ describe('React Playwright e2e tests', () => { ); if (runE2ETests()) { - const result = runCLI(`e2e ${appName}-e2e --no-watch --verbose`); + const result = runCLI(`e2e ${appName}-e2e --verbose`); expect(result).toContain( `Successfully ran target e2e for project ${appName}-e2e` ); diff --git a/e2e/react-extensions/src/react-vite.test.ts b/e2e/react-extensions/src/react-vite.test.ts index 98b0fcf7cfa60..877bd91be65a3 100644 --- a/e2e/react-extensions/src/react-vite.test.ts +++ b/e2e/react-extensions/src/react-vite.test.ts @@ -2,17 +2,16 @@ import { checkFilesExist, cleanupProject, newProject, - readJson, runCLI, runCLIAsync, uniq, } from '@nx/e2e/utils'; describe('Build React applications and libraries with Vite', () => { - let proj: string; - - beforeEach(() => { - proj = newProject(); + beforeAll(() => { + newProject({ + packages: ['@nx/react'], + }); }); afterAll(() => { @@ -129,15 +128,9 @@ describe('Build React applications and libraries with Vite', () => { `generate @nx/react:lib ${viteLib} --bundler=vite --no-interactive --unit-test-runner=none` ); - const packageJson = readJson('package.json'); - // Vite does not need these libraries to work. - expect(packageJson.dependencies['core-js']).toBeUndefined(); - expect(packageJson.dependencies['tslib']).toBeUndefined(); - await runCLIAsync(`build ${viteLib}`); checkFilesExist( - `dist/libs/${viteLib}/package.json`, `dist/libs/${viteLib}/index.d.ts`, `dist/libs/${viteLib}/index.js`, `dist/libs/${viteLib}/index.mjs` diff --git a/e2e/react-module-federation/src/react-module-federation.test.ts b/e2e/react-module-federation/src/react-module-federation.test.ts index c7138cb752813..2f48529138259 100644 --- a/e2e/react-module-federation/src/react-module-federation.test.ts +++ b/e2e/react-module-federation/src/react-module-federation.test.ts @@ -440,11 +440,15 @@ describe('React Module Federation', () => { let tree: Tree; beforeAll(() => { + process.env.NX_ADD_PLUGINS = 'false'; tree = createTreeWithEmptyWorkspace(); proj = newProject(); }); - afterAll(() => cleanupProject()); + afterAll(() => { + cleanupProject(); + delete process.env.NX_ADD_PLUGINS; + }); it('should support promised based remotes', async () => { const remote = uniq('remote'); diff --git a/e2e/react-native/src/react-native-legacy.test.ts b/e2e/react-native/src/react-native-legacy.test.ts new file mode 100644 index 0000000000000..c86fdb52262b4 --- /dev/null +++ b/e2e/react-native/src/react-native-legacy.test.ts @@ -0,0 +1,311 @@ +import { + checkFilesExist, + cleanupProject, + expectTestsPass, + getPackageManagerCommand, + isOSX, + killProcessAndPorts, + newProject, + readJson, + runCLI, + runCLIAsync, + runCommand, + runCommandUntil, + runE2ETests, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; +import { ChildProcess } from 'child_process'; +import { join } from 'path'; + +describe('@nx/react-native (legacy)', () => { + let proj: string; + let appName = uniq('my-app'); + let libName = uniq('lib'); + + beforeAll(() => { + proj = newProject(); + // we create empty preset above which skips creation of `production` named input + updateJson('nx.json', (nxJson) => { + nxJson.namedInputs = { + default: ['{projectRoot}/**/*', 'sharedGlobals'], + production: ['default'], + sharedGlobals: [], + }; + return nxJson; + }); + runCLI( + `generate @nx/react-native:application ${appName} --bunlder=webpack --e2eTestRunner=cypress --install=false --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + runCLI( + `generate @nx/react-native:library ${libName} --buildable --publishable --importPath=${proj}/${libName} --no-interactive` + ); + }); + afterAll(() => cleanupProject()); + + it('should build for web', async () => { + const results = runCLI(`build ${appName}`); + expect(results).toContain('Successfully ran target build'); + }); + + it('should test and lint', async () => { + const componentName = uniq('Component'); + runCLI( + `generate @nx/react-native:component ${componentName} --project=${libName} --export --no-interactive` + ); + + updateFile(`apps/${appName}/src/app/App.tsx`, (content) => { + let updated = `// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {${componentName}} from '${proj}/${libName}';\n${content}`; + return updated; + }); + + expectTestsPass(await runCLIAsync(`test ${appName}`)); + expectTestsPass(await runCLIAsync(`test ${libName}`)); + + const appLintResults = await runCLIAsync(`lint ${appName}`); + expect(appLintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + + const libLintResults = await runCLIAsync(`lint ${libName}`); + expect(libLintResults.combinedOutput).toContain( + 'Successfully ran target lint' + ); + }); + + it('should run e2e for cypress', async () => { + if (runE2ETests()) { + let results = runCLI(`e2e ${appName}-e2e`); + expect(results).toContain('Successfully ran target e2e'); + + results = runCLI(`e2e ${appName}-e2e --configuration=ci`); + expect(results).toContain('Successfully ran target e2e'); + } + }); + + it('should bundle-ios', async () => { + const iosBundleResult = await runCLIAsync( + `bundle-ios ${appName} --sourcemapOutput=../../dist/apps/${appName}/ios/main.map` + ); + expect(iosBundleResult.combinedOutput).toContain( + 'Done writing bundle output' + ); + expect(() => { + checkFilesExist(`dist/apps/${appName}/ios/main.jsbundle`); + checkFilesExist(`dist/apps/${appName}/ios/main.map`); + }).not.toThrow(); + }); + + it('should bundle-android', async () => { + const androidBundleResult = await runCLIAsync( + `bundle-android ${appName} --sourcemapOutput=../../dist/apps/${appName}/android/main.map` + ); + expect(androidBundleResult.combinedOutput).toContain( + 'Done writing bundle output' + ); + expect(() => { + checkFilesExist(`dist/apps/${appName}/android/main.jsbundle`); + checkFilesExist(`dist/apps/${appName}/android/main.map`); + }).not.toThrow(); + }); + + it('should start', async () => { + let process: ChildProcess; + const port = 8081; + + try { + process = await runCommandUntil( + `start ${appName} --interactive=false --port=${port}`, + (output) => { + return ( + output.includes(`http://localhost:${port}`) || + output.includes('Starting JS server...') || + output.includes('Welcome to Metro') + ); + } + ); + } catch (err) { + console.error(err); + } + + // port and process cleanup + try { + if (process && process.pid) { + await killProcessAndPorts(process.pid, port); + } + } catch (err) { + expect(err).toBeFalsy(); + } + }); + + it('should serve', async () => { + let process: ChildProcess; + const port = 8081; + + try { + process = await runCommandUntil( + `serve ${appName} --interactive=false --port=${port}`, + (output) => { + return output.includes(`http://localhost:${port}`); + } + ); + } catch (err) { + console.error(err); + } + + // port and process cleanup + try { + if (process && process.pid) { + await killProcessAndPorts(process.pid, port); + } + } catch (err) { + expect(err).toBeFalsy(); + } + }); + + if (isOSX()) { + // TODO(@meeroslav): this test is causing git-hasher to overflow with arguments. Enable when it's fixed. + xit('should pod install', async () => { + expect(async () => { + await runCLIAsync(`pod-install ${appName}`); + checkFilesExist(`apps/${appName}/ios/Podfile.lock`); + }).not.toThrow(); + }); + } + + it('should create storybook with application', async () => { + runCLI( + `generate @nx/react-native:storybook-configuration ${appName} --generateStories --no-interactive` + ); + checkFilesExist( + `apps/${appName}/.storybook/main.ts`, + `apps/${appName}/src/app/App.stories.tsx` + ); + }); + + it('should upgrade native for application', async () => { + expect(() => runCLI(`upgrade ${appName}`)).not.toThrow(); + }); + + it('should build publishable library', async () => { + const componentName = uniq('Component'); + + runCLI( + `generate @nx/react-native:component ${componentName} --project=${libName} --export` + ); + expect(() => { + runCLI(`build ${libName}`); + checkFilesExist(`dist/libs/${libName}/index.esm.js`); + checkFilesExist(`dist/libs/${libName}/src/index.d.ts`); + }).not.toThrow(); + }); + + it('sync npm dependencies for autolink', async () => { + // Add npm package with native modules + runCommand( + `${ + getPackageManagerCommand().addDev + } react-native-image-picker @react-native-async-storage/async-storage` + ); + + // Add import for Nx to pick up + updateFile(join('apps', appName, 'src/app/App.tsx'), (content) => { + return `import AsyncStorage from '@react-native-async-storage/async-storage';${content}`; + }); + + await runCLIAsync( + `sync-deps ${appName} --include=react-native-image-picker` + ); + + const result = readJson(join('apps', appName, 'package.json')); + expect(result).toMatchObject({ + dependencies: { + 'react-native-image-picker': '*', + 'react-native': '*', + }, + devDependencies: { + '@react-native-async-storage/async-storage': '*', + }, + }); + }); + + it('should tsc app', async () => { + expect(() => { + const pmc = getPackageManagerCommand(); + runCommand( + `${pmc.runUninstalledPackage} tsc -p apps/${appName}/tsconfig.app.json` + ); + checkFilesExist( + `dist/out-tsc/apps/${appName}/src/main.js`, + `dist/out-tsc/apps/${appName}/src/main.d.ts`, + `dist/out-tsc/apps/${appName}/src/app/App.js`, + `dist/out-tsc/apps/${appName}/src/app/App.d.ts`, + `dist/out-tsc/libs/${libName}/src/index.js`, + `dist/out-tsc/libs/${libName}/src/index.d.ts` + ); + }).not.toThrow(); + }); + + it('should support generating projects with the new name and root format', () => { + const appName = uniq('app1'); + const libName = uniq('@my-org/lib1'); + + runCLI( + `generate @nx/react-native:application ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + + // check files are generated without the layout directory ("apps/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${appName}/src/app/App.tsx`); + // check tests pass + const appTestResult = runCLI(`test ${appName}`); + expect(appTestResult).toContain( + `Successfully ran target test for project ${appName}` + ); + + // assert scoped project names are not supported when --project-name-and-root-format=derived + expect(() => + runCLI( + `generate @nx/react-native:library ${libName} --buildable --project-name-and-root-format=derived` + ) + ).toThrow(); + + runCLI( + `generate @nx/react-native:library ${libName} --buildable --project-name-and-root-format=as-provided` + ); + + // check files are generated without the layout directory ("libs/") and + // using the project name as the directory when no directory is provided + checkFilesExist(`${libName}/src/index.ts`); + // check tests pass + const libTestResult = runCLI(`test ${libName}`); + expect(libTestResult).toContain( + `Successfully ran target test for project ${libName}` + ); + }); + + it('should run build with vite bundler and e2e with playwright', async () => { + const appName2 = uniq('my-app'); + runCLI( + `generate @nx/react-native:application ${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive`, + { env: { NX_ADD_PLUGINS: 'false' } } + ); + const buildResults = runCLI(`build ${appName2}`); + expect(buildResults).toContain('Successfully ran target build'); + if (runE2ETests()) { + const e2eResults = runCLI(`e2e ${appName2}-e2e`); + expect(e2eResults).toContain('Successfully ran target e2e'); + } + + runCLI( + `generate @nx/react-native:storybook-configuration ${appName2} --generateStories --no-interactive` + ); + checkFilesExist( + `apps/${appName2}/.storybook/main.ts`, + `apps/${appName2}/src/app/App.stories.tsx` + ); + }); +}); diff --git a/e2e/react-native/src/react-native-pcv3.test.ts b/e2e/react-native/src/react-native-pcv3.test.ts deleted file mode 100644 index 0887aae53e9cb..0000000000000 --- a/e2e/react-native/src/react-native-pcv3.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { ChildProcess } from 'child_process'; -import { - runCLI, - cleanupProject, - newProject, - uniq, - readJson, - runCommandUntil, - killProcessAndPorts, - fileExists, - checkFilesExist, - runE2ETests, -} from 'e2e/utils'; - -describe('@nx/react-native/plugin', () => { - let appName: string; - - beforeAll(() => { - newProject(); - appName = uniq('app'); - runCLI( - `generate @nx/react-native:app ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive`, - { env: { NX_PCV3: 'true' } } - ); - }); - - afterAll(() => cleanupProject()); - - it('nx.json should contain plugin configuration', () => { - const nxJson = readJson('nx.json'); - const reactNativePlugin = nxJson.plugins.find( - (plugin) => plugin.plugin === '@nx/react-native/plugin' - ); - expect(reactNativePlugin).toBeDefined(); - expect(reactNativePlugin.options).toBeDefined(); - expect(reactNativePlugin.options.bundleTargetName).toEqual('bundle'); - expect(reactNativePlugin.options.startTargetName).toEqual('start'); - }); - - it('should bundle the app', async () => { - const result = runCLI( - `bundle ${appName} --platform=ios --bundle-output=dist.js --entry-file=src/main.tsx` - ); - fileExists(` ${appName}/dist.js`); - - expect(result).toContain( - `Successfully ran target bundle for project ${appName}` - ); - }, 200_000); - - it('should start the app', async () => { - let process: ChildProcess; - const port = 8081; - - try { - process = await runCommandUntil( - `start ${appName} --no-interactive --port=${port}`, - (output) => { - return ( - output.includes(`http://localhost:${port}`) || - output.includes('Starting JS server...') || - output.includes('Welcome to Metro') - ); - } - ); - } catch (err) { - console.error(err); - } - - // port and process cleanup - if (process && process.pid) { - await killProcessAndPorts(process.pid, port); - } - }); - - it('should serve', async () => { - let process: ChildProcess; - const port = 8081; - - try { - process = await runCommandUntil( - `serve ${appName} --interactive=false --port=${port}`, - (output) => { - return output.includes(`http://localhost:${port}`); - } - ); - } catch (err) { - console.error(err); - } - - // port and process cleanup - try { - if (process && process.pid) { - await killProcessAndPorts(process.pid, port); - } - } catch (err) { - expect(err).toBeFalsy(); - } - }); - - it('should run e2e for cypress', async () => { - if (runE2ETests()) { - let results = runCLI(`e2e ${appName}-e2e`); - expect(results).toContain('Successfully ran target e2e'); - - results = runCLI(`e2e ${appName}-e2e --configuration=ci`); - expect(results).toContain('Successfully ran target e2e'); - } - }); - - it('should create storybook with application', async () => { - runCLI( - `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` - ); - checkFilesExist( - `${appName}/.storybook/main.ts`, - `${appName}/src/app/App.stories.tsx` - ); - }); -}); diff --git a/e2e/react-native/src/react-native.test.ts b/e2e/react-native/src/react-native.test.ts index 32a15178d1979..f87b60514afab 100644 --- a/e2e/react-native/src/react-native.test.ts +++ b/e2e/react-native/src/react-native.test.ts @@ -1,119 +1,47 @@ +import { ChildProcess } from 'child_process'; import { - checkFilesExist, + runCLI, cleanupProject, - expectTestsPass, - getPackageManagerCommand, - isOSX, - killProcessAndPorts, newProject, - readJson, - runCLI, - runCLIAsync, - runCommand, + uniq, runCommandUntil, + killProcessAndPorts, + fileExists, + checkFilesExist, runE2ETests, - uniq, - updateFile, - updateJson, -} from '@nx/e2e/utils'; -import { ChildProcess } from 'child_process'; -import { join } from 'path'; +} from 'e2e/utils'; -describe('react native', () => { - let proj: string; - let appName = uniq('my-app'); - let libName = uniq('lib'); +describe('@nx/react-native', () => { + let appName: string; beforeAll(() => { - proj = newProject(); - // we create empty preset above which skips creation of `production` named input - updateJson('nx.json', (nxJson) => { - nxJson.namedInputs = { - default: ['{projectRoot}/**/*', 'sharedGlobals'], - production: ['default'], - sharedGlobals: [], - }; - nxJson.targetDefaults.build.inputs = ['production', '^production']; - return nxJson; - }); - runCLI( - `generate @nx/react-native:application ${appName} --bunlder=webpack --e2eTestRunner=cypress --install=false --no-interactive` - ); + newProject(); + appName = uniq('app'); runCLI( - `generate @nx/react-native:library ${libName} --buildable --publishable --importPath=${proj}/${libName} --no-interactive` + `generate @nx/react-native:app ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive` ); }); - afterAll(() => cleanupProject()); - - it('should build for web', async () => { - const results = runCLI(`build ${appName}`); - expect(results).toContain('Successfully ran target build'); - }); - - it('should test and lint', async () => { - const componentName = uniq('Component'); - runCLI( - `generate @nx/react-native:component ${componentName} --project=${libName} --export --no-interactive` - ); - - updateFile(`apps/${appName}/src/app/App.tsx`, (content) => { - let updated = `// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport {${componentName}} from '${proj}/${libName}';\n${content}`; - return updated; - }); - - expectTestsPass(await runCLIAsync(`test ${appName}`)); - expectTestsPass(await runCLIAsync(`test ${libName}`)); - - const appLintResults = await runCLIAsync(`lint ${appName}`); - expect(appLintResults.combinedOutput).toContain('All files pass linting.'); - - const libLintResults = await runCLIAsync(`lint ${libName}`); - expect(libLintResults.combinedOutput).toContain('All files pass linting.'); - }); - it('should run e2e for cypress', async () => { - if (runE2ETests()) { - let results = runCLI(`e2e ${appName}-e2e`); - expect(results).toContain('Successfully ran target e2e'); - - results = runCLI(`e2e ${appName}-e2e --configuration=ci`); - expect(results).toContain('Successfully ran target e2e'); - } - }); + afterAll(() => cleanupProject()); - it('should bundle-ios', async () => { - const iosBundleResult = await runCLIAsync( - `bundle-ios ${appName} --sourcemapOutput=../../dist/apps/${appName}/ios/main.map` - ); - expect(iosBundleResult.combinedOutput).toContain( - 'Done writing bundle output' + it('should bundle the app', async () => { + const result = runCLI( + `bundle ${appName} --platform=ios --bundle-output=dist.js --entry-file=src/main.tsx` ); - expect(() => { - checkFilesExist(`dist/apps/${appName}/ios/main.jsbundle`); - checkFilesExist(`dist/apps/${appName}/ios/main.map`); - }).not.toThrow(); - }); + fileExists(` ${appName}/dist.js`); - it('should bundle-android', async () => { - const androidBundleResult = await runCLIAsync( - `bundle-android ${appName} --sourcemapOutput=../../dist/apps/${appName}/android/main.map` + expect(result).toContain( + `Successfully ran target bundle for project ${appName}` ); - expect(androidBundleResult.combinedOutput).toContain( - 'Done writing bundle output' - ); - expect(() => { - checkFilesExist(`dist/apps/${appName}/android/main.jsbundle`); - checkFilesExist(`dist/apps/${appName}/android/main.map`); - }).not.toThrow(); - }); + }, 200_000); - it('should start', async () => { + it('should start the app', async () => { let process: ChildProcess; const port = 8081; try { process = await runCommandUntil( - `start ${appName} --interactive=false --port=${port}`, + `start ${appName} --no-interactive --port=${port}`, (output) => { return ( output.includes(`http://localhost:${port}`) || @@ -127,12 +55,8 @@ describe('react native', () => { } // port and process cleanup - try { - if (process && process.pid) { - await killProcessAndPorts(process.pid, port); - } - } catch (err) { - expect(err).toBeFalsy(); + if (process && process.pid) { + await killProcessAndPorts(process.pid, port); } }); @@ -161,145 +85,23 @@ describe('react native', () => { } }); - if (isOSX()) { - // TODO(@meeroslav): this test is causing git-hasher to overflow with arguments. Enable when it's fixed. - xit('should pod install', async () => { - expect(async () => { - await runCLIAsync(`pod-install ${appName}`); - checkFilesExist(`apps/${appName}/ios/Podfile.lock`); - }).not.toThrow(); - }); - } - - it('should create storybook with application', async () => { - runCLI( - `generate @nx/react-native:storybook-configuration ${appName} --generateStories --no-interactive` - ); - checkFilesExist( - `apps/${appName}/.storybook/main.ts`, - `apps/${appName}/src/app/App.stories.tsx` - ); - }); - - it('should upgrade native for application', async () => { - expect(() => runCLI(`upgrade ${appName}`)).not.toThrow(); - }); - - it('should build publishable library', async () => { - const componentName = uniq('Component'); - - runCLI( - `generate @nx/react-native:component ${componentName} --project=${libName} --export` - ); - expect(() => { - runCLI(`build ${libName}`); - checkFilesExist(`dist/libs/${libName}/index.esm.js`); - checkFilesExist(`dist/libs/${libName}/src/index.d.ts`); - }).not.toThrow(); - }); - - it('sync npm dependencies for autolink', async () => { - // Add npm package with native modules - runCommand( - `${ - getPackageManagerCommand().addDev - } react-native-image-picker @react-native-async-storage/async-storage` - ); - - // Add import for Nx to pick up - updateFile(join('apps', appName, 'src/app/App.tsx'), (content) => { - return `import AsyncStorage from '@react-native-async-storage/async-storage';${content}`; - }); - - await runCLIAsync( - `sync-deps ${appName} --include=react-native-image-picker` - ); - - const result = readJson(join('apps', appName, 'package.json')); - expect(result).toMatchObject({ - dependencies: { - 'react-native-image-picker': '*', - 'react-native': '*', - }, - devDependencies: { - '@react-native-async-storage/async-storage': '*', - }, - }); - }); - - it('should tsc app', async () => { - expect(() => { - const pmc = getPackageManagerCommand(); - runCommand( - `${pmc.runUninstalledPackage} tsc -p apps/${appName}/tsconfig.app.json` - ); - checkFilesExist( - `dist/out-tsc/apps/${appName}/src/main.js`, - `dist/out-tsc/apps/${appName}/src/main.d.ts`, - `dist/out-tsc/apps/${appName}/src/app/App.js`, - `dist/out-tsc/apps/${appName}/src/app/App.d.ts`, - `dist/out-tsc/libs/${libName}/src/index.js`, - `dist/out-tsc/libs/${libName}/src/index.d.ts` - ); - }).not.toThrow(); - }); - - it('should support generating projects with the new name and root format', () => { - const appName = uniq('app1'); - const libName = uniq('@my-org/lib1'); - - runCLI( - `generate @nx/react-native:application ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive` - ); - - // check files are generated without the layout directory ("apps/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${appName}/src/app/App.tsx`); - // check tests pass - const appTestResult = runCLI(`test ${appName}`); - expect(appTestResult).toContain( - `Successfully ran target test for project ${appName}` - ); - - // assert scoped project names are not supported when --project-name-and-root-format=derived - expect(() => - runCLI( - `generate @nx/react-native:library ${libName} --buildable --project-name-and-root-format=derived` - ) - ).toThrow(); - - runCLI( - `generate @nx/react-native:library ${libName} --buildable --project-name-and-root-format=as-provided` - ); - - // check files are generated without the layout directory ("libs/") and - // using the project name as the directory when no directory is provided - checkFilesExist(`${libName}/src/index.ts`); - // check tests pass - const libTestResult = runCLI(`test ${libName}`); - expect(libTestResult).toContain( - `Successfully ran target test for project ${libName}` - ); - }); - - it('should run build with vite bundler and e2e with playwright', async () => { - const appName2 = uniq('my-app'); - runCLI( - `generate @nx/react-native:application ${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive` - ); - const buildResults = runCLI(`build ${appName2}`); - expect(buildResults).toContain('Successfully ran target build'); + it('should run e2e for cypress', async () => { if (runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName2}-e2e`); - expect(e2eResults).toContain('Successfully ran target e2e'); + let results = runCLI(`e2e ${appName}-e2e`); + expect(results).toContain('Successfully ran target e2e'); + + results = runCLI(`e2e ${appName}-e2e --configuration=ci`); + expect(results).toContain('Successfully ran target e2e'); } + }); + it('should create storybook with application', async () => { runCLI( - `generate @nx/react-native:storybook-configuration ${appName2} --generateStories --no-interactive` + `generate @nx/react:storybook-configuration ${appName} --generateStories --no-interactive` ); checkFilesExist( - `apps/${appName2}/.storybook/main.ts`, - `apps/${appName2}/src/app/App.stories.tsx` + `${appName}/.storybook/main.ts`, + `${appName}/src/app/App.stories.tsx` ); }); }); diff --git a/e2e/release/src/lock-file-updates.test.ts b/e2e/release/src/lock-file-updates.test.ts index 9f05312454c70..122edc90b716c 100644 --- a/e2e/release/src/lock-file-updates.test.ts +++ b/e2e/release/src/lock-file-updates.test.ts @@ -116,6 +116,42 @@ describe('nx release lock file updates', () => { `); }); + it('should not update lock file when package manager is yarn classic', async () => { + initializeProject('yarn'); + + updateJson('package.json', (json) => { + json.workspaces = [pkg1, pkg2, pkg3]; + return json; + }); + + runCommand(`corepack prepare yarn@1.22.19 --activate`); + runCommand(`yarn set version 1.22.19`); + runCommand(`yarn install`); + + // workaround for NXC-143 + runCLI('reset'); + + runCommand(`git add .`); + runCommand(`git commit -m "chore: initial commit"`); + + const versionOutput = runCLI(`release version 999.9.9 --verbose`); + + expect( + versionOutput.match( + /Skipped lock file update because it is not necessary for Yarn Classic./g + ).length + ).toBe(1); + + const filesChanges = runCommand('git diff --name-only HEAD'); + + expect(filesChanges).toMatchInlineSnapshot(` + {project-name}/package.json + {project-name}/package.json + {project-name}/package.json + + `); + }); + it('should update yarn.lock when package manager is yarn', async () => { process.env.YARN_ENABLE_IMMUTABLE_INSTALLS = 'false'; diff --git a/e2e/remix/tests/nx-remix.test.ts b/e2e/remix/tests/nx-remix.test.ts index fa52d5d46d056..37495874ab3d5 100644 --- a/e2e/remix/tests/nx-remix.test.ts +++ b/e2e/remix/tests/nx-remix.test.ts @@ -8,6 +8,7 @@ import { uniq, updateFile, runCommandAsync, + listFiles, } from '@nx/e2e/utils'; describe('remix e2e', () => { @@ -62,13 +63,12 @@ describe('remix e2e', () => { runCLI( `generate @nx/remix:app ${plugin} --directory=sub --projectNameAndRootFormat=derived --rootProject=false --no-interactive` ); - const project = readJson(`sub/${plugin}/project.json`); - expect(project.targets.build.options.outputPath).toEqual( - `dist/sub/${plugin}` - ); const result = runCLI(`build ${appName}`); expect(result).toContain('Successfully ran target build'); + + // TODO(colum): uncomment line below when fixed + // checkFilesExist(`dist/apps/sub/${plugin}/build/index.js`); }, 120000); it('should create src in the specified directory --projectNameAndRootFormat=as-provided', async () => { @@ -76,11 +76,10 @@ describe('remix e2e', () => { runCLI( `generate @nx/remix:app ${plugin} --directory=subdir --projectNameAndRootFormat=as-provided --rootProject=false --no-interactive` ); - const project = readJson(`subdir/project.json`); - expect(project.targets.build.options.outputPath).toEqual(`dist/subdir`); const result = runCLI(`build ${plugin}`); expect(result).toContain('Successfully ran target build'); + checkFilesExist(`dist/subdir/build/index.js`); }, 120000); }); diff --git a/e2e/storybook-angular/src/storybook-angular.test.ts b/e2e/storybook-angular/src/storybook-angular.test.ts index 4e773d84a0721..f5316fb56ea8e 100644 --- a/e2e/storybook-angular/src/storybook-angular.test.ts +++ b/e2e/storybook-angular/src/storybook-angular.test.ts @@ -44,7 +44,7 @@ describe('Storybook executors for Angular', () => { // TODO(meeroslav) this test is still flaky and breaks the PR runs. We need to investigate why. xit('shoud build an Angular based storybook', () => { runCLI(`run ${angularStorybookLib}:build-storybook`); - checkFilesExist(`dist/storybook/${angularStorybookLib}/index.html`); + checkFilesExist(`${angularStorybookLib}/storybook-static/index.html`); }, 1_000_000); }); }); diff --git a/e2e/storybook/src/storybook-nested.test.ts b/e2e/storybook/src/storybook-nested.test.ts index 147998fb17fcc..3faf16735bc45 100644 --- a/e2e/storybook/src/storybook-nested.test.ts +++ b/e2e/storybook/src/storybook-nested.test.ts @@ -67,7 +67,7 @@ describe('Storybook generators and executors for standalone workspaces - using R describe('build storybook', () => { it('should build a React based storybook that uses Vite', () => { runCLI(`run ${appName}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${appName}/index.html`); + checkFilesExist(`storybook-static/index.html`); }, 100_000); it('should build a React based storybook that references another lib and uses Vite', () => { @@ -116,7 +116,7 @@ describe('Storybook generators and executors for standalone workspaces - using R // build React lib runCLI(`run ${appName}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${appName}/index.html`); + checkFilesExist(`storybook-static/index.html`); }, 150_000); }); }); diff --git a/e2e/storybook/src/storybook.test.ts b/e2e/storybook/src/storybook.test.ts index d7bf61f3fe22c..089edcee70b38 100644 --- a/e2e/storybook/src/storybook.test.ts +++ b/e2e/storybook/src/storybook.test.ts @@ -5,13 +5,11 @@ import { newProject, runCLI, runCommandUntil, - setMaxWorkers, tmpProjPath, uniq, } from '@nx/e2e/utils'; import { writeFileSync } from 'fs'; import { createFileSync } from 'fs-extra'; -import { join } from 'path'; describe('Storybook generators and executors for monorepos', () => { const reactStorybookApp = uniq('react-app'); @@ -19,11 +17,11 @@ describe('Storybook generators and executors for monorepos', () => { beforeAll(async () => { proj = newProject({ packages: ['@nx/react', '@nx/storybook'], + unsetProjectNameAndRootFormat: false, }); runCLI( `generate @nx/react:app ${reactStorybookApp} --bundler=webpack --project-name-and-root-format=as-provided --no-interactive` ); - setMaxWorkers(join(reactStorybookApp, 'project.json')); runCLI( `generate @nx/react:storybook-configuration ${reactStorybookApp} --generateStories --no-interactive --bundler=webpack` ); @@ -37,7 +35,7 @@ describe('Storybook generators and executors for monorepos', () => { xdescribe('serve storybook', () => { afterEach(() => killPorts()); - it('should serve a React based Storybook setup that uses Vite', async () => { + it('should serve a React based Storybook setup that uses webpack', async () => { const p = await runCommandUntil( `run ${reactStorybookApp}:storybook`, (output) => { @@ -52,7 +50,7 @@ describe('Storybook generators and executors for monorepos', () => { it('should build a React based storybook setup that uses webpack', () => { // build runCLI(`run ${reactStorybookApp}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${reactStorybookApp}/index.html`); + checkFilesExist(`${reactStorybookApp}/storybook-static/index.html`); }, 300_000); // This test makes sure path resolution works @@ -106,7 +104,7 @@ describe('Storybook generators and executors for monorepos', () => { // build React lib runCLI(`run ${reactStorybookApp}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${reactStorybookApp}/index.html`); + checkFilesExist(`${reactStorybookApp}/storybook-static/index.html`); }, 300_000); }); }); diff --git a/e2e/utils/command-utils.ts b/e2e/utils/command-utils.ts index a145318f09293..bd3a087f10db4 100644 --- a/e2e/utils/command-utils.ts +++ b/e2e/utils/command-utils.ts @@ -174,10 +174,14 @@ export function getPackageManagerCommand({ }[packageManager.trim() as PackageManager]; } -export function runE2ETests() { +export function runE2ETests(runner?: 'cypress' | 'playwright') { if (process.env.NX_E2E_RUN_E2E === 'true') { - ensureCypressInstallation(); - ensurePlaywrightBrowsersInstallation(); + if (!runner || runner === 'cypress') { + ensureCypressInstallation(); + } + if (!runner || runner === 'playwright') { + ensurePlaywrightBrowsersInstallation(); + } return true; } diff --git a/e2e/utils/create-project-utils.ts b/e2e/utils/create-project-utils.ts index 61776a53b0834..a2d70c2ca4bc0 100644 --- a/e2e/utils/create-project-utils.ts +++ b/e2e/utils/create-project-utils.ts @@ -39,6 +39,7 @@ let projName: string; // TODO(jack): we should tag the projects (e.g. tags: ['package']) and filter from that rather than hard-code packages. const nxPackages = [ `@nx/angular`, + `@nx/cypress`, `@nx/eslint-plugin`, `@nx/express`, `@nx/esbuild`, diff --git a/e2e/utils/get-env-info.ts b/e2e/utils/get-env-info.ts index cb834febdb1cb..4798c1f717fdc 100644 --- a/e2e/utils/get-env-info.ts +++ b/e2e/utils/get-env-info.ts @@ -157,7 +157,7 @@ export function getStrippedEnvironmentVariables() { return true; } - const allowedKeys = ['NX_PCV3']; + const allowedKeys = ['NX_ADD_PLUGINS']; if (key.startsWith('NX_') && !allowedKeys.includes(key)) { return false; diff --git a/e2e/vite/src/vite-pcv3.test.ts b/e2e/vite/src/vite-crystal.test.ts similarity index 92% rename from e2e/vite/src/vite-pcv3.test.ts rename to e2e/vite/src/vite-crystal.test.ts index 358c1603b35c4..0f34bf43778fc 100644 --- a/e2e/vite/src/vite-pcv3.test.ts +++ b/e2e/vite/src/vite-crystal.test.ts @@ -15,11 +15,18 @@ const myVueApp = uniq('my-vue-app'); describe('@nx/vite/plugin', () => { let proj: string; let originalEnv: string; + beforeAll(() => { + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'true'; + }); + + afterAll(() => { + process.env.NX_ADD_PLUGINS = originalEnv; + cleanupProject(); + }); describe('with react', () => { beforeAll(() => { - originalEnv = process.env.NX_PCV3; - process.env.NX_PCV3 = 'true'; proj = newProject({ packages: ['@nx/react', '@nx/vue'], }); @@ -30,7 +37,6 @@ describe('@nx/vite/plugin', () => { }); afterAll(() => { - process.env.NODE_ENV = originalEnv; cleanupProject(); }); @@ -83,8 +89,6 @@ describe('@nx/vite/plugin', () => { const reactVitest = uniq('reactVitest'); beforeAll(() => { - originalEnv = process.env.NX_PCV3; - process.env.NX_PCV3 = 'true'; proj = newProject({ packages: ['@nx/vite', '@nx/react'], }); @@ -94,7 +98,6 @@ describe('@nx/vite/plugin', () => { }); afterAll(() => { - process.env.NODE_ENV = originalEnv; cleanupProject(); }); diff --git a/e2e/vite/src/vite-esm.test.ts b/e2e/vite/src/vite-esm.test.ts index 11649ffcdced8..fa19cb0311ce5 100644 --- a/e2e/vite/src/vite-esm.test.ts +++ b/e2e/vite/src/vite-esm.test.ts @@ -9,7 +9,6 @@ import { // TODO(jack): This test file can be removed when Vite goes ESM-only. // This test ensures that when CJS is gone from the published `vite` package, Nx will continue to work. - describe('Vite ESM tests', () => { beforeAll(() => newProject({ @@ -20,7 +19,9 @@ describe('Vite ESM tests', () => { it('should build with Vite when it is ESM-only', async () => { const appName = uniq('viteapp'); - runCLI(`generate @nx/react:app ${appName} --bundler=vite`); + runCLI( + `generate @nx/react:app ${appName} --bundler=vite --project-name-and-root-format=as-provided` + ); // .mts file is needed because Nx will transpile .ts files as CJS renameFile(`${appName}/vite.config.ts`, `${appName}/vite.config.mts`); diff --git a/e2e/vite/src/vite.test.ts b/e2e/vite/src/vite-legacy.test.ts similarity index 81% rename from e2e/vite/src/vite.test.ts rename to e2e/vite/src/vite-legacy.test.ts index 2b58827da0147..6de99121f9638 100644 --- a/e2e/vite/src/vite.test.ts +++ b/e2e/vite/src/vite-legacy.test.ts @@ -23,26 +23,34 @@ import { } from '@nx/e2e/utils'; import { join } from 'path'; -const myApp = uniq('my-app'); - describe('Vite Plugin', () => { let proj: string; + let originalEnv: string; + beforeAll(() => { + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'false'; + proj = newProject({ + packages: ['@nx/react', '@nx/web'], + }); + }); + + afterAll(() => { + process.env.NX_ADD_PLUGINS = originalEnv; + cleanupProject(); + }); describe('Vite on React apps', () => { describe('set up new React app with --bundler=vite option', () => { - beforeEach(async () => { - proj = newProject({ - packages: ['@nx/react'], - }); - runCLI(`generate @nx/react:app ${myApp} --bundler=vite`); - createFile(`apps/${myApp}/public/hello.md`, `# Hello World`); - }); - afterEach(() => cleanupProject()); it('should build application', async () => { + const myApp = uniq('my-app'); + runCLI( + `generate @nx/react:app ${myApp} --bundler=vite --directory=${myApp} --projectNameAndRootFormat=as-provided` + ); + createFile(`${myApp}/public/hello.md`, `# Hello World`); runCLI(`build ${myApp}`); - expect(readFile(`dist/apps/${myApp}/favicon.ico`)).toBeDefined(); - expect(readFile(`dist/apps/${myApp}/hello.md`)).toBeDefined(); - expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined(); + expect(readFile(`dist/${myApp}/favicon.ico`)).toBeDefined(); + expect(readFile(`dist/${myApp}/hello.md`)).toBeDefined(); + expect(readFile(`dist/${myApp}/index.html`)).toBeDefined(); rmDist(); }, 200_000); }); @@ -50,35 +58,31 @@ describe('Vite Plugin', () => { describe('Vite on Web apps', () => { describe('set up new @nx/web app with --bundler=vite option', () => { + let myApp; beforeEach(() => { - proj = newProject({ - packages: ['@nx/web'], - }); - runCLI(`generate @nx/web:app ${myApp} --bundler=vite`); + myApp = uniq('my-app'); + runCLI( + `generate @nx/web:app ${myApp} --bundler=vite --directory=${myApp} --projectNameAndRootFormat=as-provided` + ); }); - afterEach(() => cleanupProject()); it('should build application', async () => { runCLI(`build ${myApp}`); - expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined(); - const fileArray = listFiles(`dist/apps/${myApp}/assets`); + expect(readFile(`dist/${myApp}/index.html`)).toBeDefined(); + const fileArray = listFiles(`dist/${myApp}/assets`); const mainBundle = fileArray.find((file) => file.endsWith('.js')); - expect( - readFile(`dist/apps/${myApp}/assets/${mainBundle}`) - ).toBeDefined(); - expect(fileExists(`dist/apps/${myApp}/package.json`)).toBeFalsy(); + expect(readFile(`dist/${myApp}/assets/${mainBundle}`)).toBeDefined(); + expect(fileExists(`dist/${myApp}/package.json`)).toBeFalsy(); rmDist(); }, 200_000); it('should build application with new package json generation', async () => { runCLI(`build ${myApp} --generatePackageJson`); - expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined(); - const fileArray = listFiles(`dist/apps/${myApp}/assets`); + expect(readFile(`dist/${myApp}/index.html`)).toBeDefined(); + const fileArray = listFiles(`dist/${myApp}/assets`); const mainBundle = fileArray.find((file) => file.endsWith('.js')); - expect( - readFile(`dist/apps/${myApp}/assets/${mainBundle}`) - ).toBeDefined(); + expect(readFile(`dist/${myApp}/assets/${mainBundle}`)).toBeDefined(); - const packageJson = readJson(`dist/apps/${myApp}/package.json`); + const packageJson = readJson(`dist/${myApp}/package.json`); expect(packageJson).toEqual({ name: myApp, version: '0.0.1', @@ -89,7 +93,7 @@ describe('Vite Plugin', () => { it('should build application with existing package json generation', async () => { createFile( - `apps/${myApp}/package.json`, + `${myApp}/package.json`, JSON.stringify({ name: 'my-existing-app', version: '1.0.1', @@ -99,14 +103,12 @@ describe('Vite Plugin', () => { }) ); runCLI(`build ${myApp} --generatePackageJson`); - expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined(); - const fileArray = listFiles(`dist/apps/${myApp}/assets`); + expect(readFile(`dist/${myApp}/index.html`)).toBeDefined(); + const fileArray = listFiles(`dist/${myApp}/assets`); const mainBundle = fileArray.find((file) => file.endsWith('.js')); - expect( - readFile(`dist/apps/${myApp}/assets/${mainBundle}`) - ).toBeDefined(); + expect(readFile(`dist/${myApp}/assets/${mainBundle}`)).toBeDefined(); - const packageJson = readJson(`dist/apps/${myApp}/package.json`); + const packageJson = readJson(`dist/${myApp}/package.json`); expect(packageJson).toEqual({ name: 'my-existing-app', version: '1.0.1', @@ -120,7 +122,7 @@ describe('Vite Plugin', () => { it('should build application without copying exisiting package json when generatePackageJson=false', async () => { createFile( - `apps/${myApp}/package.json`, + `${myApp}/package.json`, JSON.stringify({ name: 'my-existing-app', version: '1.0.1', @@ -130,14 +132,12 @@ describe('Vite Plugin', () => { }) ); runCLI(`build ${myApp} --generatePackageJson=false`); - expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined(); - const fileArray = listFiles(`dist/apps/${myApp}/assets`); + expect(readFile(`dist/${myApp}/index.html`)).toBeDefined(); + const fileArray = listFiles(`dist/${myApp}/assets`); const mainBundle = fileArray.find((file) => file.endsWith('.js')); - expect( - readFile(`dist/apps/${myApp}/assets/${mainBundle}`) - ).toBeDefined(); + expect(readFile(`dist/${myApp}/assets/${mainBundle}`)).toBeDefined(); - expect(fileExists(`dist/apps/${myApp}/package.json`)).toBe(false); + expect(fileExists(`dist/${myApp}/package.json`)).toBe(false); rmDist(); }, 200_000); }); @@ -153,27 +153,29 @@ describe('Vite Plugin', () => { name: uniq('vite-incr-build'), packages: ['@nx/react'], }); - runCLI(`generate @nx/react:app ${app} --bundler=vite --no-interactive`); + runCLI( + `generate @nx/react:app ${app} --bundler=vite --no-interactive --directory=${app} --projectNameAndRootFormat=as-provided` + ); // only this project will be directly used from dist runCLI( - `generate @nx/react:lib ${lib}-buildable --unitTestRunner=none --bundler=vite --importPath="@acme/buildable" --no-interactive` + `generate @nx/react:lib ${lib}-buildable --unitTestRunner=none --bundler=vite --importPath="@acme/buildable" --no-interactive --directory=${lib}-buildable --projectNameAndRootFormat=as-provided` ); runCLI( - `generate @nx/react:lib ${lib} --unitTestRunner=none --bundler=none --importPath="@acme/non-buildable" --no-interactive` + `generate @nx/react:lib ${lib} --unitTestRunner=none --bundler=none --importPath="@acme/non-buildable" --no-interactive --directory=${lib} --projectNameAndRootFormat=as-provided` ); // because the default js lib builds as cjs it cannot be loaded from dist // so the paths plugin should always resolve to the libs source runCLI( - `generate @nx/js:lib ${lib}-js --bundler=tsc --importPath="@acme/js-lib" --no-interactive` + `generate @nx/js:lib ${lib}-js --bundler=tsc --importPath="@acme/js-lib" --no-interactive --directory=${lib}-js --projectNameAndRootFormat=as-provided` ); const buildableLibCmp = names(`${lib}-buildable`).className; const nonBuildableLibCmp = names(lib).className; const buildableJsLibFn = names(`${lib}-js`).propertyName; - updateFile(`apps/${app}/src/app/app.tsx`, () => { + updateFile(`${app}/src/app/app.tsx`, () => { return ` import styles from './app.module.css'; import NxWelcome from './nx-welcome'; @@ -215,7 +217,7 @@ export default App; }); it('should build app from libs without package.json in lib', () => { - removeFile(`libs/${lib}-buildable/package.json`); + removeFile(`${lib}-buildable/package.json`); const buildFromSourceResults = runCLI( `build ${app} --buildLibsFromSource=true` diff --git a/e2e/vue/src/vue-storybook.test.ts b/e2e/vue/src/vue-storybook.test.ts index 7185110c05d2f..c66314338d858 100644 --- a/e2e/vue/src/vue-storybook.test.ts +++ b/e2e/vue/src/vue-storybook.test.ts @@ -3,22 +3,24 @@ import { cleanupProject, newProject, runCLI, - setMaxWorkers, uniq, } from '@nx/e2e/utils'; -import { join } from 'path'; describe('Storybook generators and executors for Vue projects', () => { const vueStorybookApp = uniq('vue-app'); let proj; + let originalEnv: string; + beforeAll(async () => { + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'true'; proj = newProject({ packages: ['@nx/vue', '@nx/storybook'], + unsetProjectNameAndRootFormat: false, }); runCLI( `generate @nx/vue:app ${vueStorybookApp} --project-name-and-root-format=as-provided --no-interactive` ); - setMaxWorkers(join(vueStorybookApp, 'project.json')); runCLI( `generate @nx/vue:storybook-configuration ${vueStorybookApp} --generateStories --no-interactive` ); @@ -26,13 +28,13 @@ describe('Storybook generators and executors for Vue projects', () => { afterAll(() => { cleanupProject(); + process.env.NX_ADD_PLUGINS = originalEnv; }); describe('build storybook', () => { it('should build a vue based storybook setup', () => { - // build runCLI(`run ${vueStorybookApp}:build-storybook --verbose`); - checkFilesExist(`dist/storybook/${vueStorybookApp}/index.html`); + checkFilesExist(`${vueStorybookApp}/storybook-static/index.html`); }, 300_000); }); }); diff --git a/e2e/vue/src/vue.test.ts b/e2e/vue/src/vue.test.ts index 48a0bdca14ab5..a9c65bf97dc32 100644 --- a/e2e/vue/src/vue.test.ts +++ b/e2e/vue/src/vue.test.ts @@ -1,11 +1,4 @@ -import { - cleanupProject, - killPorts, - newProject, - runCLI, - runE2ETests, - uniq, -} from '@nx/e2e/utils'; +import { cleanupProject, newProject, runCLI, uniq } from '@nx/e2e/utils'; describe('Vue Plugin', () => { let proj: string; @@ -19,8 +12,7 @@ describe('Vue Plugin', () => { afterAll(() => cleanupProject()); - // TODO: enable this when tests are passing again. - xit('should serve application in dev mode', async () => { + it('should serve application in dev mode', async () => { const app = uniq('app'); runCLI( @@ -34,11 +26,12 @@ describe('Vue Plugin', () => { `Successfully ran target build for project ${app}` ); - if (runE2ETests()) { - const e2eResults = runCLI(`e2e ${app}-e2e --no-watch`); - expect(e2eResults).toContain('Successfully ran target e2e'); - expect(await killPorts()).toBeTruthy(); - } + // TODO: enable this when tests are passing again. + // if (runE2ETests()) { + // const e2eResults = runCLI(`e2e ${app}-e2e --no-watch`); + // expect(e2eResults).toContain('Successfully ran target e2e'); + // expect(await killPorts()).toBeTruthy(); + // } }, 200_000); it('should build library', async () => { diff --git a/e2e/web/src/file-server-legacy.test.ts b/e2e/web/src/file-server-legacy.test.ts new file mode 100644 index 0000000000000..b4d4dcca8a56a --- /dev/null +++ b/e2e/web/src/file-server-legacy.test.ts @@ -0,0 +1,85 @@ +import { + cleanupProject, + killPorts, + newProject, + promisifiedTreeKill, + runCLI, + runCommandUntil, + uniq, +} from '@nx/e2e/utils'; + +describe('file-server', () => { + beforeAll(() => { + newProject({ name: uniq('fileserver') }); + }); + + afterAll(() => cleanupProject()); + + it('should setup and serve static files from app', async () => { + const ngAppName = uniq('ng-app'); + const reactAppName = uniq('react-app'); + + runCLI( + `generate @nx/angular:app ${ngAppName} --no-interactive --e2eTestRunner=none`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + runCLI( + `generate @nx/react:app ${reactAppName} --no-interactive --e2eTestRunner=none`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + runCLI( + `generate @nx/web:static-config --buildTarget=${ngAppName}:build --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + runCLI( + `generate @nx/web:static-config --buildTarget=${reactAppName}:build --targetName=custom-serve-static --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + const port = 6200; + + const ngServe = await runCommandUntil( + `serve-static ${ngAppName} --port=${port}`, + (output) => { + return output.indexOf(`localhost:${port}`) > -1; + } + ); + + try { + await promisifiedTreeKill(ngServe.pid, 'SIGKILL'); + await killPorts(port); + } catch { + // ignore + } + + const reactServe = await runCommandUntil( + `custom-serve-static ${reactAppName} --port=${port + 1}`, + (output) => { + return output.indexOf(`localhost:${port + 1}`) > -1; + } + ); + + try { + await promisifiedTreeKill(reactServe.pid, 'SIGKILL'); + await killPorts(port + 1); + } catch { + // ignore + } + }, 300_000); +}); diff --git a/e2e/web/src/file-server.test.ts b/e2e/web/src/file-server.test.ts index f706ff7f6f6c8..acb58049fdfa0 100644 --- a/e2e/web/src/file-server.test.ts +++ b/e2e/web/src/file-server.test.ts @@ -5,7 +5,6 @@ import { promisifiedTreeKill, runCLI, runCommandUntil, - setMaxWorkers, uniq, updateFile, updateJson, @@ -16,6 +15,7 @@ describe('file-server', () => { beforeAll(() => { newProject({ name: uniq('fileserver') }); }); + afterAll(() => cleanupProject()); it('should serve folder of files', async () => { @@ -23,11 +23,13 @@ describe('file-server', () => { const port = 4301; runCLI(`generate @nx/web:app ${appName} --no-interactive`); - setMaxWorkers(join('apps', appName, 'project.json')); updateJson(join('apps', appName, 'project.json'), (config) => { - config.targets['serve'].executor = '@nx/web:file-server'; - // Check that buildTarget can exclude project name (e.g. build vs proj:build). - config.targets['serve'].options.buildTarget = 'build'; + config.targets['serve'] = { + executor: '@nx/web:file-server', + options: { + buildTarget: 'build', + }, + }; return config; }); @@ -51,17 +53,16 @@ describe('file-server', () => { const port = 4301; runCLI(`generate @nx/web:app ${appName} --no-interactive`); - setMaxWorkers(join('apps', appName, 'project.json')); // Used to copy index.html rather than the normal webpack build. updateFile( - `copy-index.js`, + `apps/${appName}/copy-index.js`, ` const fs = require('node:fs'); const path = require('node:path'); - fs.mkdirSync(path.join(__dirname, 'dist/foobar'), { recursive: true }); + fs.mkdirSync(path.join(__dirname, '../../dist/foobar'), { recursive: true }); fs.copyFileSync( - path.join(__dirname, 'apps/${appName}/src/index.html'), - path.join(__dirname, 'dist/foobar/index.html') + path.join(__dirname, './src/index.html'), + path.join(__dirname, '../../dist/foobar/index.html') ); ` ); @@ -71,9 +72,12 @@ describe('file-server', () => { command: `node copy-index.js`, outputs: [`{workspaceRoot}/dist/foobar`], }; - config.targets['serve'].executor = '@nx/web:file-server'; - // Check that buildTarget can exclude project name (e.g. build vs proj:build). - config.targets['serve'].options.buildTarget = 'build'; + config.targets['serve'] = { + executor: '@nx/web:file-server', + options: { + buildTarget: 'build', + }, + }; return config; }); @@ -94,53 +98,4 @@ describe('file-server', () => { // ignore } }, 300_000); - - it('should setup and serve static files from app', async () => { - const ngAppName = uniq('ng-app'); - const reactAppName = uniq('react-app'); - - runCLI( - `generate @nx/angular:app ${ngAppName} --no-interactive --e2eTestRunner=none` - ); - runCLI( - `generate @nx/react:app ${reactAppName} --no-interactive --e2eTestRunner=none` - ); - runCLI( - `generate @nx/web:static-config --buildTarget=${ngAppName}:build --no-interactive` - ); - runCLI( - `generate @nx/web:static-config --buildTarget=${reactAppName}:build --targetName=custom-serve-static --no-interactive` - ); - setMaxWorkers(join('apps', reactAppName, 'project.json')); - - const port = 6200; - - const ngServe = await runCommandUntil( - `serve-static ${ngAppName} --port=${port}`, - (output) => { - return output.indexOf(`localhost:${port}`) > -1; - } - ); - - try { - await promisifiedTreeKill(ngServe.pid, 'SIGKILL'); - await killPorts(port); - } catch { - // ignore - } - - const reactServe = await runCommandUntil( - `custom-serve-static ${reactAppName} --port=${port + 1}`, - (output) => { - return output.indexOf(`localhost:${port + 1}`) > -1; - } - ); - - try { - await promisifiedTreeKill(reactServe.pid, 'SIGKILL'); - await killPorts(port + 1); - } catch { - // ignore - } - }, 300_000); }); diff --git a/e2e/web/src/web-legacy.test.ts b/e2e/web/src/web-legacy.test.ts new file mode 100644 index 0000000000000..05dd083905591 --- /dev/null +++ b/e2e/web/src/web-legacy.test.ts @@ -0,0 +1,278 @@ +import { + checkFilesDoNotExist, + checkFilesExist, + cleanupProject, + createFile, + newProject, + readFile, + rmDist, + runCLI, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; +import { join } from 'path'; + +describe('Web Components Applications (legacy)', () => { + beforeEach(() => newProject()); + afterEach(() => cleanupProject()); + + it('should remove previous output before building', async () => { + const appName = uniq('app'); + const libName = uniq('lib'); + + runCLI( + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive --compiler swc`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + runCLI( + `generate @nx/react:lib ${libName} --bundler=rollup --no-interactive --compiler swc --unitTestRunner=jest`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + createFile(`dist/apps/${appName}/_should_remove.txt`); + createFile(`dist/libs/${libName}/_should_remove.txt`); + createFile(`dist/apps/_should_not_remove.txt`); + checkFilesExist( + `dist/apps/${appName}/_should_remove.txt`, + `dist/apps/_should_not_remove.txt` + ); + runCLI(`build ${appName} --outputHashing none`); + runCLI(`build ${libName}`); + checkFilesDoNotExist( + `dist/apps/${appName}/_should_remove.txt`, + `dist/libs/${libName}/_should_remove.txt` + ); + checkFilesExist(`dist/apps/_should_not_remove.txt`); + + // Asset that React runtime is imported + expect(readFile(`dist/libs/${libName}/index.esm.js`)).toMatch( + /react\/jsx-runtime/ + ); + + // `delete-output-path` + createFile(`dist/apps/${appName}/_should_keep.txt`); + runCLI(`build ${appName} --delete-output-path=false --outputHashing none`); + checkFilesExist(`dist/apps/${appName}/_should_keep.txt`); + + createFile(`dist/libs/${libName}/_should_keep.txt`); + runCLI(`build ${libName} --delete-output-path=false --outputHashing none`); + checkFilesExist(`dist/libs/${libName}/_should_keep.txt`); + }, 120000); + + it('should support custom webpackConfig option', async () => { + const appName = uniq('app'); + runCLI( + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + updateJson(join('apps', appName, 'project.json'), (config) => { + config.targets.build.options.webpackConfig = `apps/${appName}/webpack.config.js`; + return config; + }); + + // Return sync function + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { composePlugins, withNx, withWeb } = require('@nx/webpack'); + module.exports = composePlugins(withNx(), withWeb(), (config, context) => { + return config; + }); + ` + ); + runCLI(`build ${appName} --outputHashing=none`); + checkFilesExist(`dist/apps/${appName}/main.js`); + + rmDist(); + + // Return async function + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { composePlugins, withNx, withWeb } = require('@nx/webpack'); + module.exports = composePlugins(withNx(), withWeb(), async (config, context) => { + return config; + }); + ` + ); + runCLI(`build ${appName} --outputHashing=none`); + checkFilesExist(`dist/apps/${appName}/main.js`); + + rmDist(); + + // Return promise of function + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { composePlugins, withNx, withWeb } = require('@nx/webpack'); + module.exports = composePlugins(withNx(), withWeb(), Promise.resolve((config, context) => { + return config; + })); + ` + ); + runCLI(`build ${appName} --outputHashing=none`); + checkFilesExist(`dist/apps/${appName}/main.js`); + }, 100000); +}); + +describe('Build Options (legacy) ', () => { + it('should inject/bundle external scripts and styles', async () => { + newProject(); + + const appName = uniq('app'); + + runCLI( + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + const srcPath = `apps/${appName}/src`; + const fooCss = `${srcPath}/foo.css`; + const barCss = `${srcPath}/bar.css`; + const fooJs = `${srcPath}/foo.js`; + const barJs = `${srcPath}/bar.js`; + const fooCssContent = `/* ${uniq('foo')} */`; + const barCssContent = `/* ${uniq('bar')} */`; + const fooJsContent = `/* ${uniq('foo')} */`; + const barJsContent = `/* ${uniq('bar')} */`; + + createFile(fooCss); + createFile(barCss); + createFile(fooJs); + createFile(barJs); + + // createFile could not create a file with content + updateFile(fooCss, fooCssContent); + updateFile(barCss, barCssContent); + updateFile(fooJs, fooJsContent); + updateFile(barJs, barJsContent); + + const barScriptsBundleName = 'bar-scripts'; + const barStylesBundleName = 'bar-styles'; + + updateJson(join('apps', appName, 'project.json'), (config) => { + const buildOptions = config.targets.build.options; + + buildOptions.scripts = [ + { + input: fooJs, + inject: true, + }, + { + input: barJs, + inject: false, + bundleName: barScriptsBundleName, + }, + ]; + + buildOptions.styles = [ + { + input: fooCss, + inject: true, + }, + { + input: barCss, + inject: false, + bundleName: barStylesBundleName, + }, + ]; + return config; + }); + + runCLI(`build ${appName} --optimization=false --outputHashing=none`); + + const distPath = `dist/apps/${appName}`; + const scripts = readFile(`${distPath}/scripts.js`); + const styles = readFile(`${distPath}/styles.css`); + const barScripts = readFile(`${distPath}/${barScriptsBundleName}.js`); + const barStyles = readFile(`${distPath}/${barStylesBundleName}.css`); + + expect(scripts).toContain(fooJsContent); + expect(scripts).not.toContain(barJsContent); + expect(barScripts).toContain(barJsContent); + + expect(styles).toContain(fooCssContent); + expect(styles).not.toContain(barCssContent); + expect(barStyles).toContain(barCssContent); + }); +}); + +describe('index.html interpolation (legacy)', () => { + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); + + test('should interpolate environment variables', async () => { + const appName = uniq('app'); + + runCLI( + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } + ); + + const srcPath = `apps/${appName}/src`; + const indexPath = `${srcPath}/index.html`; + const indexContent = ` + + + + BestReactApp + + + + + +
+
Nx Variable: %NX_VARIABLE%
+
Some other variable: %SOME_OTHER_VARIABLE%
+
Deploy Url: %DEPLOY_URL%
+ + +`; + const envFilePath = `apps/${appName}/.env`; + const envFileContents = ` + NX_VARIABLE=foo + SOME_OTHER_VARIABLE=bar + }`; + + createFile(envFilePath); + + // createFile could not create a file with content + updateFile(envFilePath, envFileContents); + updateFile(indexPath, indexContent); + + updateJson(join('apps', appName, 'project.json'), (config) => { + const buildOptions = config.targets.build.options; + buildOptions.deployUrl = 'baz'; + return config; + }); + + runCLI(`build ${appName}`); + + const distPath = `dist/apps/${appName}`; + const resultIndexContents = readFile(`${distPath}/index.html`); + + expect(resultIndexContents).toMatch(/Nx Variable: foo/); + }); +}); diff --git a/e2e/web/src/web-vite.test.ts b/e2e/web/src/web-vite.test.ts index 4145a59563343..16f5c7a909956 100644 --- a/e2e/web/src/web-vite.test.ts +++ b/e2e/web/src/web-vite.test.ts @@ -9,10 +9,8 @@ import { runCLI, runCLIAsync, runE2ETests, - setMaxWorkers, uniq, } from '@nx/e2e/utils'; -import { join } from 'path'; describe('Web Components Applications with bundler set as vite', () => { beforeEach(() => newProject()); @@ -21,10 +19,9 @@ describe('Web Components Applications with bundler set as vite', () => { it('should be able to generate a web app', async () => { const appName = uniq('app'); runCLI(`generate @nx/web:app ${appName} --bundler=vite --no-interactive`); - setMaxWorkers(join('apps', appName, 'project.json')); const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); runCLI(`build ${appName}`); checkFilesExist(`dist/apps/${appName}/index.html`); @@ -35,12 +32,12 @@ describe('Web Components Applications with bundler set as vite', () => { const lintE2eResults = runCLI(`lint ${appName}-e2e`); - expect(lintE2eResults).toContain('All files pass linting.'); + expect(lintE2eResults).toContain('Successfully ran target lint'); if (isNotWindows() && runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`); + const e2eResults = runCLI(`e2e ${appName}-e2e`); expect(e2eResults).toContain('All specs passed!'); - expect(await killPorts()).toBeTruthy(); + await killPorts(); } }, 500000); @@ -52,7 +49,6 @@ describe('Web Components Applications with bundler set as vite', () => { runCLI( `generate @nx/react:lib ${libName} --bundler=vite --no-interactive --unitTestRunner=vitest` ); - setMaxWorkers(join('apps', appName, 'project.json')); createFile(`dist/apps/${appName}/_should_remove.txt`); createFile(`dist/libs/${libName}/_should_remove.txt`); diff --git a/e2e/web/src/web-webpack.test.ts b/e2e/web/src/web-webpack.test.ts index 8b5eaf30831c8..35e727a5ee47f 100644 --- a/e2e/web/src/web-webpack.test.ts +++ b/e2e/web/src/web-webpack.test.ts @@ -4,21 +4,23 @@ import { newProject, runCLI, runCommandUntil, - setMaxWorkers, uniq, } from '@nx/e2e/utils'; -import { join } from 'path'; describe('Web Components Applications with bundler set as webpack', () => { beforeEach(() => newProject()); afterEach(() => cleanupProject()); - it('should support https for dev-server', async () => { + it('should support https for dev-server (legacy)', async () => { const appName = uniq('app'); runCLI( - `generate @nx/web:app ${appName} --bundler=webpack --no-interactive` + `generate @nx/web:app ${appName} --bundler=webpack --no-interactive`, + { + env: { + NX_ADD_PLUGINS: 'false', + }, + } ); - setMaxWorkers(join('apps', appName, 'project.json')); const childProcess = await runCommandUntil( `serve ${appName} --port=5000 --ssl`, diff --git a/e2e/web/src/web.test.ts b/e2e/web/src/web.test.ts index 3d8518b02d3ad..04099e44dc1fa 100644 --- a/e2e/web/src/web.test.ts +++ b/e2e/web/src/web.test.ts @@ -3,16 +3,13 @@ import { checkFilesExist, cleanupProject, createFile, - ensurePlaywrightBrowsersInstallation, isNotWindows, killPorts, newProject, readFile, - rmDist, runCLI, runCLIAsync, runE2ETests, - setMaxWorkers, tmpProjPath, uniq, updateFile, @@ -22,18 +19,17 @@ import { join } from 'path'; import { copyFileSync } from 'fs'; describe('Web Components Applications', () => { - beforeEach(() => newProject()); - afterEach(() => cleanupProject()); + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); it('should be able to generate a web app', async () => { const appName = uniq('app'); runCLI( `generate @nx/web:app ${appName} --bundler=webpack --no-interactive` ); - setMaxWorkers(join('apps', appName, 'project.json')); const lintResults = runCLI(`lint ${appName}`); - expect(lintResults).toContain('All files pass linting.'); + expect(lintResults).toContain('Successfully ran target lint'); const testResults = await runCLIAsync(`test ${appName}`); @@ -42,12 +38,12 @@ describe('Web Components Applications', () => { ); const lintE2eResults = runCLI(`lint ${appName}-e2e`); - expect(lintE2eResults).toContain('All files pass linting.'); + expect(lintE2eResults).toContain('Successfully ran target lint'); if (isNotWindows() && runE2ETests()) { - const e2eResults = runCLI(`e2e ${appName}-e2e --no-watch`); + const e2eResults = runCLI(`e2e ${appName}-e2e`); expect(e2eResults).toContain('All specs passed!'); - expect(await killPorts()).toBeTruthy(); + await killPorts(); } copyFileSync( @@ -69,15 +65,20 @@ describe('Web Components Applications', () => { public static observedAttributes = []; connectedCallback() { this.innerHTML = \` - - + + \`; } } customElements.define('app-root', AppElement); ` ); - runCLI(`build ${appName} --outputHashing none`); + setPluginOption( + `apps/${appName}/webpack.config.js`, + 'outputHashing', + 'none' + ); + runCLI(`build ${appName}`); checkFilesExist( `dist/apps/${appName}/index.html`, `dist/apps/${appName}/runtime.js`, @@ -88,7 +89,7 @@ describe('Web Components Applications', () => { checkFilesDoNotExist(`dist/apps/${appName}/inlined.png`); expect(readFile(`dist/apps/${appName}/main.js`)).toContain( - ' { - it('should inject/bundle external scripts and styles', async () => { - newProject(); - - const appName = uniq('app'); - - runCLI( - `generate @nx/web:app ${appName} --bundler=webpack --no-interactive` - ); - setMaxWorkers(join('apps', appName, 'project.json')); - - const srcPath = `apps/${appName}/src`; - const fooCss = `${srcPath}/foo.css`; - const barCss = `${srcPath}/bar.css`; - const fooJs = `${srcPath}/foo.js`; - const barJs = `${srcPath}/bar.js`; - const fooCssContent = `/* ${uniq('foo')} */`; - const barCssContent = `/* ${uniq('bar')} */`; - const fooJsContent = `/* ${uniq('foo')} */`; - const barJsContent = `/* ${uniq('bar')} */`; - - createFile(fooCss); - createFile(barCss); - createFile(fooJs); - createFile(barJs); - - // createFile could not create a file with content - updateFile(fooCss, fooCssContent); - updateFile(barCss, barCssContent); - updateFile(fooJs, fooJsContent); - updateFile(barJs, barJsContent); - - const barScriptsBundleName = 'bar-scripts'; - const barStylesBundleName = 'bar-styles'; - - updateJson(join('apps', appName, 'project.json'), (config) => { - const buildOptions = config.targets.build.options; - - buildOptions.scripts = [ - { - input: fooJs, - inject: true, - }, - { - input: barJs, - inject: false, - bundleName: barScriptsBundleName, - }, - ]; - - buildOptions.styles = [ - { - input: fooCss, - inject: true, - }, - { - input: barCss, - inject: false, - bundleName: barStylesBundleName, - }, - ]; - return config; - }); - - runCLI(`build ${appName} --outputHashing none --optimization false`); - - const distPath = `dist/apps/${appName}`; - const scripts = readFile(`${distPath}/scripts.js`); - const styles = readFile(`${distPath}/styles.css`); - const barScripts = readFile(`${distPath}/${barScriptsBundleName}.js`); - const barStyles = readFile(`${distPath}/${barStylesBundleName}.css`); - - expect(scripts).toContain(fooJsContent); - expect(scripts).not.toContain(barJsContent); - expect(barScripts).toContain(barJsContent); - - expect(styles).toContain(fooCssContent); - expect(styles).not.toContain(barCssContent); - expect(barStyles).toContain(barCssContent); - }); -}); - describe('index.html interpolation', () => { + beforeAll(() => newProject()); + afterAll(() => cleanupProject()); + test('should interpolate environment variables', async () => { const appName = uniq('app'); runCLI( `generate @nx/web:app ${appName} --bundler=webpack --no-interactive` ); - setMaxWorkers(join('apps', appName, 'project.json')); const srcPath = `apps/${appName}/src`; const indexPath = `${srcPath}/index.html`; @@ -546,7 +363,6 @@ describe('index.html interpolation', () => {
Nx Variable: %NX_VARIABLE%
Some other variable: %SOME_OTHER_VARIABLE%
-
Deploy Url: %DEPLOY_URL%
`; @@ -562,19 +378,24 @@ describe('index.html interpolation', () => { updateFile(envFilePath, envFileContents); updateFile(indexPath, indexContent); - updateJson(join('apps', appName, 'project.json'), (config) => { - const buildOptions = config.targets.build.options; - buildOptions.deployUrl = 'baz'; - return config; - }); - runCLI(`build ${appName}`); const distPath = `dist/apps/${appName}`; const resultIndexContents = readFile(`${distPath}/index.html`); expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/); - expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/); - expect(resultIndexContents).toMatch(/
Nx Variable: foo<\/div>/); }); }); + +function setPluginOption( + webpackConfigPath: string, + option: string, + value: string | boolean +): void { + updateFile(webpackConfigPath, (content) => { + return content.replace( + new RegExp(`${option}: .+`), + `${option}: ${typeof value === 'string' ? `'${value}'` : value},` + ); + }); +} diff --git a/e2e/webpack/src/webpack.pcv3.test.ts b/e2e/webpack/src/webpack.legacy.test.ts similarity index 53% rename from e2e/webpack/src/webpack.pcv3.test.ts rename to e2e/webpack/src/webpack.legacy.test.ts index 7c63be3ced7c4..8c8b61d27f51f 100644 --- a/e2e/webpack/src/webpack.pcv3.test.ts +++ b/e2e/webpack/src/webpack.legacy.test.ts @@ -1,21 +1,23 @@ import { + checkFilesExist, cleanupProject, killProcessAndPorts, newProject, runCLI, runCommandUntil, uniq, + updateFile, } from '@nx/e2e/utils'; import { ChildProcess } from 'child_process'; -describe('Webpack Plugin (PCv3)', () => { - let originalPcv3: string | undefined; +describe('Webpack Plugin (legacy)', () => { + let originalAddPluginsEnv: string | undefined; const appName = uniq('app'); const libName = uniq('lib'); beforeAll(() => { - originalPcv3 = process.env.NX_PCV3; - process.env.NX_PCV3 = 'true'; + originalAddPluginsEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'false'; newProject({ packages: ['@nx/react'], unsetProjectNameAndRootFormat: false, @@ -29,7 +31,7 @@ describe('Webpack Plugin (PCv3)', () => { }); afterAll(() => { - process.env.NX_PCV3 = originalPcv3; + process.env.NX_ADD_PLUGINS = originalAddPluginsEnv; cleanupProject(); }); @@ -65,4 +67,39 @@ describe('Webpack Plugin (PCv3)', () => { await killProcessAndPorts(process.pid, port); } }); + + // Issue: https://github.com/nrwl/nx/issues/20179 + it('should allow main/styles entries to be spread within composePlugins() function (#20179)', () => { + const appName = uniq('app'); + runCLI(`generate @nx/web:app ${appName} --bundler webpack`); + updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`); + + updateFile( + `apps/${appName}/webpack.config.js`, + ` + const { composePlugins, withNx, withWeb } = require('@nx/webpack'); + module.exports = composePlugins(withNx(), withWeb(), (config) => { + return { + ...config, + entry: { + main: [...config.entry.main], + styles: [...config.entry.styles], + } + }; + }); + ` + ); + + expect(() => { + runCLI(`build ${appName} --outputHashing none`); + }).not.toThrow(); + checkFilesExist(`dist/${appName}/styles.css`); + + expect(() => { + runCLI(`build ${appName} --outputHashing none --extractCss false`); + }).not.toThrow(); + expect(() => { + checkFilesExist(`dist/${appName}/styles.css`); + }).toThrow(); + }); }); diff --git a/e2e/webpack/src/webpack.test.ts b/e2e/webpack/src/webpack.test.ts index e976f13be37ac..9837e29e1efa1 100644 --- a/e2e/webpack/src/webpack.test.ts +++ b/e2e/webpack/src/webpack.test.ts @@ -28,13 +28,31 @@ describe('Webpack Plugin', () => { updateFile( `libs/${myPkg}/webpack.config.js`, ` -const { composePlugins, withNx } = require('@nx/webpack'); + const path = require('path'); + const { NxWebpackPlugin } = require('@nx/webpack'); + + class DebugPlugin { + apply(compiler) { + console.log('scriptType is ' + compiler.options.output.scriptType); + } + } -module.exports = composePlugins(withNx(), (config) => { - console.log('scriptType is ' + config.output.scriptType); - return config; -}); -` + module.exports = { + target: 'node', + output: { + path: path.join(__dirname, '../../dist/libs/${myPkg}') + }, + plugins: [ + new NxWebpackPlugin({ + compiler: 'tsc', + main: './src/index.ts', + tsConfig: './tsconfig.lib.json', + outputHashing: 'none', + optimization: false, + }), + new DebugPlugin() + ] + };` ); rmDist(); @@ -141,39 +159,4 @@ module.exports = composePlugins(withNx(), (config) => { let output = runCommand(`node dist/${appName}/main.js`); expect(output).toMatch(/Hello/); }, 500_000); - - // Issue: https://github.com/nrwl/nx/issues/20179 - it('should allow main/styles entries to be spread within composePlugins() function (#20179)', () => { - const appName = uniq('app'); - runCLI(`generate @nx/web:app ${appName} --bundler webpack`); - updateFile(`apps/${appName}/src/main.ts`, `console.log('Hello');\n`); - - updateFile( - `apps/${appName}/webpack.config.js`, - ` - const { composePlugins, withNx, withWeb } = require('@nx/webpack'); - module.exports = composePlugins(withNx(), withWeb(), (config) => { - return { - ...config, - entry: { - main: [...config.entry.main], - styles: [...config.entry.styles], - } - }; - }); - ` - ); - - expect(() => { - runCLI(`build ${appName} --outputHashing none`); - }).not.toThrow(); - checkFilesExist(`dist/apps/${appName}/styles.css`); - - expect(() => { - runCLI(`build ${appName} --outputHashing none --extractCss false`); - }).not.toThrow(); - expect(() => { - checkFilesExist(`dist/apps/${appName}/styles.css`); - }).toThrow(); - }); }); diff --git a/e2e/workspace-create-npm/src/create-nx-workspace-npm.test.ts b/e2e/workspace-create-npm/src/create-nx-workspace-npm.test.ts index fef38095f2310..5343b5ebffea9 100644 --- a/e2e/workspace-create-npm/src/create-nx-workspace-npm.test.ts +++ b/e2e/workspace-create-npm/src/create-nx-workspace-npm.test.ts @@ -54,7 +54,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/angular:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/angular:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -66,7 +66,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/angular:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/angular:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -83,7 +83,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => runCLI( - `generate @nx/js:library ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/js:library packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ) ).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -100,7 +100,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => runCLI( - `generate @nx/web:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/web:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ) ).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -113,7 +113,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/react:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/react:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -126,7 +126,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/react:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/react:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -143,7 +143,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/next:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/next:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -156,7 +156,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/next:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/next:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -174,7 +174,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/react-native:app ${appName} --install=false --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/react-native:app packages/${appName} --install=false --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -187,7 +187,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/react-native:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/react-native:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -204,7 +204,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/node:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/node:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -217,7 +217,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/node:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/node:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -234,7 +234,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/nest:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/nest:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -247,7 +247,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/nest:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/nest:lib packages/${libName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); @@ -264,7 +264,7 @@ describe('create-nx-workspace --preset=npm', () => { expect(() => { runCLI( - `generate @nx/express:app ${appName} --projectNameAndRootFormat as-provided --no-interactive` + `generate @nx/express:app packages/${appName} --projectNameAndRootFormat as-provided --no-interactive` ); }).not.toThrowError(); checkFilesExist('tsconfig.base.json'); diff --git a/graph/client/src/app/external-api-impl.ts b/graph/client/src/app/external-api-impl.ts index c3bad95cde1d0..724c9ebf87817 100644 --- a/graph/client/src/app/external-api-impl.ts +++ b/graph/client/src/app/external-api-impl.ts @@ -81,8 +81,10 @@ export class ExternalApiImpl extends ExternalApi { } } - openProjectDetails(projectName: string, targetName?: string) { - this.router.navigate(`/project-details/${encodeURIComponent(projectName)}`); + async openProjectDetails(projectName: string, targetName?: string) { + await this.router.navigate( + `/project-details/${encodeURIComponent(projectName)}` + ); if (targetName) { this.focusTargetInProjectDetails(targetName); } diff --git a/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx b/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx index 28152e9312c9c..77408c63cec04 100644 --- a/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx +++ b/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx @@ -8,17 +8,12 @@ import { } from '@nx/graph/ui-tooltips'; import { ProjectNodeActions } from './project-node-actions'; import { TaskNodeActions } from './task-node-actions'; -import { - getExternalApiService, - useEnvironmentConfig, - useRouteConstructor, -} from '@nx/graph/shared'; +import { getExternalApiService, useRouteConstructor } from '@nx/graph/shared'; import { useNavigate } from 'react-router-dom'; const tooltipService = getTooltipService(); export function TooltipDisplay() { - const environment = useEnvironmentConfig()?.environment; const navigate = useNavigate(); const routeConstructor = useRouteConstructor(); const externalApiService = getExternalApiService(); @@ -31,46 +26,74 @@ export function TooltipDisplay() { let tooltipToRender; if (currentTooltip) { if (currentTooltip.type === 'projectNode') { - const onConfigClick = (() => { - if (environment !== 'nx-console') { - return () => { - navigate( - routeConstructor( - { - pathname: `/project-details/${encodeURIComponent( - currentTooltip.props.id - )}`, - }, - false - ) - ); - }; - } else { - return () => - externalApiService.postEvent({ - type: 'open-project-config', - payload: { - projectName: currentTooltip.props.id, - }, - }); - } - })(); + const onConfigClick = + currentTooltip.props.renderMode === 'nx-docs' + ? undefined + : (() => { + if (currentTooltip.props.renderMode !== 'nx-console') { + return () => { + navigate( + routeConstructor( + { + pathname: `/project-details/${encodeURIComponent( + currentTooltip.props.id + )}`, + }, + false + ) + ); + }; + } else { + return () => + externalApiService.postEvent({ + type: 'open-project-config', + payload: { + projectName: currentTooltip.props.id, + }, + }); + } + })(); tooltipToRender = ( ); } else if (currentTooltip.type === 'projectEdge') { - tooltipToRender = ; + const onFileClick = + currentTooltip.props.renderMode === 'nx-console' + ? (url) => + externalApiService.postEvent({ + type: 'file-click', + payload: { + sourceRoot: currentTooltip.props.sourceRoot, + file: url, + }, + }) + : undefined; + tooltipToRender = ( + + ); } else if (currentTooltip.type === 'taskNode') { + const onRunTaskClick = + currentTooltip.props.renderMode === 'nx-console' + ? () => + externalApiService.postEvent({ + type: 'run-task', + payload: { + taskId: currentTooltip.props.id, + }, + }) + : undefined; const onConfigClick = (() => { const [projectName, targetName] = currentTooltip.props.id.split(':'); - if (environment !== 'nx-console') { + if (currentTooltip.props.renderMode !== 'nx-console') { return () => { navigate( routeConstructor( @@ -100,7 +123,7 @@ export function TooltipDisplay() { diff --git a/graph/ui-graph/src/lib/tooltip-service.ts b/graph/ui-graph/src/lib/tooltip-service.ts index a9485023a7e8c..796afd2975b41 100644 --- a/graph/ui-graph/src/lib/tooltip-service.ts +++ b/graph/ui-graph/src/lib/tooltip-service.ts @@ -7,11 +7,9 @@ import { } from '@nx/graph/ui-tooltips'; import { TooltipEvent } from './interfaces'; import { GraphInteractionEvents } from './graph-interaction-events'; -import { getExternalApiService } from '@nx/graph/shared'; export class GraphTooltipService { private subscribers: Set = new Set(); - private externalApiService = getExternalApiService(); constructor(graph: GraphService) { graph.listen((event: GraphInteractionEvents) => { @@ -28,22 +26,13 @@ export class GraphTooltipService { tags: event.data.tags, type: event.data.type, description: event.data.description, + renderMode: graph.renderMode, }); break; case 'TaskNodeClick': - const runTaskCallback = - graph.renderMode === 'nx-console' - ? () => - this.externalApiService.postEvent({ - type: 'run-task', - payload: { - taskId: event.data.id, - }, - }) - : undefined; this.openTaskNodeTooltip(event.ref, { ...event.data, - runTaskCallback, + renderMode: graph.renderMode, }); if (graph.getTaskInputs) { graph.getTaskInputs(event.data.id).then((inputs) => { @@ -53,7 +42,7 @@ export class GraphTooltipService { ) { this.openTaskNodeTooltip(event.ref, { ...event.data, - runTaskCallback, + renderMode: graph.renderMode, inputs, }); } @@ -61,23 +50,13 @@ export class GraphTooltipService { } break; case 'EdgeClick': - const callback = - graph.renderMode === 'nx-console' - ? (url) => - this.externalApiService.postEvent({ - type: 'file-click', - payload: { - sourceRoot: event.data.sourceRoot, - file: url, - }, - }) - : undefined; this.openEdgeToolTip(event.ref, { type: event.data.type, target: event.data.target, source: event.data.source, fileDependencies: event.data.fileDependencies, - fileClickCallback: callback, + renderMode: graph.renderMode, + sourceRoot: event.data.sourceRoot, }); break; } diff --git a/graph/ui-graph/src/lib/util-cytoscape/project-edge.ts b/graph/ui-graph/src/lib/util-cytoscape/project-edge.ts index 7d7a144eac5c3..a3e8e0a2e8e5d 100644 --- a/graph/ui-graph/src/lib/util-cytoscape/project-edge.ts +++ b/graph/ui-graph/src/lib/util-cytoscape/project-edge.ts @@ -9,6 +9,8 @@ export interface ProjectEdgeDataDefinition extends cy.NodeDataDefinition { source: string; target: string; type: 'static' | 'dynamic' | 'implicit'; + sourceRoot?: string; + fileDependencies?: { fileName: string }[]; } export class ProjectEdge { diff --git a/graph/ui-graph/src/lib/util-cytoscape/render-graph.ts b/graph/ui-graph/src/lib/util-cytoscape/render-graph.ts index 69a32a8f391f1..118f4a7af8e41 100644 --- a/graph/ui-graph/src/lib/util-cytoscape/render-graph.ts +++ b/graph/ui-graph/src/lib/util-cytoscape/render-graph.ts @@ -223,12 +223,10 @@ export class RenderGraph { const node = event.target; let ref: VirtualElement = node.popperRef(); // used only for positioning - this.broadcast({ type: 'ProjectNodeClick', ref, id: node.id(), - data: { id: node.id(), type: node.data('type'), @@ -249,7 +247,6 @@ export class RenderGraph { type: 'TaskNodeClick', ref, id: node.id(), - data: { id: node.id(), label: node.data('label'), @@ -270,7 +267,6 @@ export class RenderGraph { type: 'EdgeClick', ref, id: edge.id(), - data: { id: edge.id(), type: edge.data('type'), diff --git a/graph/ui-tooltips/src/lib/project-edge-tooltip.tsx b/graph/ui-tooltips/src/lib/project-edge-tooltip.tsx index f5a9fc89c006d..c694db94b0589 100644 --- a/graph/ui-tooltips/src/lib/project-edge-tooltip.tsx +++ b/graph/ui-tooltips/src/lib/project-edge-tooltip.tsx @@ -6,7 +6,9 @@ export interface ProjectEdgeNodeTooltipProps { target: string; fileDependencies: Array<{ fileName: string }>; description?: string; - fileClickCallback: (fileName: string) => void; + renderMode?: 'nx-console' | 'nx-docs'; + sourceRoot?: string; + fileClickCallback?: (fileName: string) => void; } export function ProjectEdgeNodeTooltip({ diff --git a/graph/ui-tooltips/src/lib/project-node-tooltip.tsx b/graph/ui-tooltips/src/lib/project-node-tooltip.tsx index d041aacb7d580..a034d977ef71f 100644 --- a/graph/ui-tooltips/src/lib/project-node-tooltip.tsx +++ b/graph/ui-tooltips/src/lib/project-node-tooltip.tsx @@ -4,7 +4,6 @@ import { } from '@heroicons/react/24/outline'; import { Tag } from '@nx/graph/ui-components'; import { ReactNode } from 'react'; -import { useEnvironmentConfig } from '@nx/graph/shared'; export interface ProjectNodeToolTipProps { type: 'app' | 'lib' | 'e2e'; @@ -12,8 +11,7 @@ export interface ProjectNodeToolTipProps { tags: string[]; description?: string; openConfigCallback?: () => void; - isNxConsole?: boolean; - + renderMode?: 'nx-console' | 'nx-docs'; children?: ReactNode | ReactNode[]; } @@ -24,30 +22,32 @@ export function ProjectNodeToolTip({ children, description, openConfigCallback, - isNxConsole, + renderMode, }: ProjectNodeToolTipProps) { return (

{type} - {id} + {id}
- + {openConfigCallback && ( + + )}

{tags.length > 0 ? (

diff --git a/graph/ui-tooltips/src/lib/property-info-tooltip.tsx b/graph/ui-tooltips/src/lib/property-info-tooltip.tsx index 91a4db9afafdd..036b43471bf29 100644 --- a/graph/ui-tooltips/src/lib/property-info-tooltip.tsx +++ b/graph/ui-tooltips/src/lib/property-info-tooltip.tsx @@ -27,7 +27,7 @@ const PROPERTY_INFO_TOOLTIP_TYPE_OPTIONS: Record< PropertyInfoTooltipTypeOptions > = { targets: { - docsUrl: 'https://nx.dev/core-features/run-tasks#define-tasks', + docsUrl: 'https://nx.dev/features/run-tasks', docsLinkText: 'Learn more about running tasks', heading: 'Target', description: @@ -47,12 +47,12 @@ const PROPERTY_INFO_TOOLTIP_TYPE_OPTIONS: Record< 'This task will be cached by Nx. When the Inputs have not changed the Outputs will be restored from the cache.', }, inputs: { - docsUrl: 'https://nx.dev/recipes/running-tasks/customizing-inputs', + docsUrl: 'https://nx.dev/recipes/running-tasks/configure-inputs', heading: 'Inputs', description: `Inputs are used by the task to produce Outputs. Inputs are used to determine when the Outputs of a task can be restored from the cache.`, }, outputs: { - docsUrl: 'https://nx.dev/reference/project-configuration#outputs', + docsUrl: 'https://nx.dev/recipes/running-tasks/configure-outputs', heading: 'Outputs', description: 'Outputs are the results of a task. Outputs are restored from the cache when the Inputs are the same as a previous run.', diff --git a/graph/ui-tooltips/src/lib/task-node-tooltip.tsx b/graph/ui-tooltips/src/lib/task-node-tooltip.tsx index 0494add07c1ee..d543253e4906c 100644 --- a/graph/ui-tooltips/src/lib/task-node-tooltip.tsx +++ b/graph/ui-tooltips/src/lib/task-node-tooltip.tsx @@ -12,9 +12,8 @@ export interface TaskNodeTooltipProps { runTaskCallback?: () => void; description?: string; inputs?: Record; - isNxConsole?: boolean; openConfigCallback?: () => void; - + renderMode?: 'nx-console' | 'nx-docs'; children?: ReactNode | ReactNode[]; } @@ -22,8 +21,8 @@ export function TaskNodeTooltip({ id, executor, description, - runTaskCallback: runTargetCallback, - isNxConsole, + renderMode, + runTaskCallback, openConfigCallback, children, }: TaskNodeTooltipProps) { @@ -33,33 +32,35 @@ export function TaskNodeTooltip({

{executor} - {id} + {id}
- + {openConfigCallback && ( + + )}
- {runTargetCallback ? ( + {runTaskCallback && ( - ) : undefined} + )} {description ?

{description}

: null} {children} diff --git a/nx-dev/data-access-menu/src/lib/menu.utils.ts b/nx-dev/data-access-menu/src/lib/menu.utils.ts index 5db920d9c68b9..7db23fef838b7 100644 --- a/nx-dev/data-access-menu/src/lib/menu.utils.ts +++ b/nx-dev/data-access-menu/src/lib/menu.utils.ts @@ -9,7 +9,7 @@ export function getBasicNxSection(items: MenuItem[]): MenuSection { .filter( (m) => m.id === 'getting-started' || - m.id === 'core-features' || + m.id === 'features' || m.id === 'concepts' || m.id === 'recipes' || m.id === 'showcase' || diff --git a/nx-dev/nx-dev/lib/rspack/content/overview.ts b/nx-dev/nx-dev/lib/rspack/content/overview.ts index 06f99f06b614a..9d6eb5783c137 100644 --- a/nx-dev/nx-dev/lib/rspack/content/overview.ts +++ b/nx-dev/nx-dev/lib/rspack/content/overview.ts @@ -34,23 +34,10 @@ First, make sure \`@nx/rspack\` is installed. Make sure to install the \`@nx/rspack\` version that matches the version of \`nx\` in your repository. If the version numbers get out of sync, you can encounter some difficult to debug errors. You can [fix Nx version mismatches with this recipe](/recipes/tips-n-tricks/keep-nx-versions-in-sync). {% /callout %} -{% tabs %} -{% tab label="npm" %} \`\`\`bash -npm i -D @nx/rspack@latest +nx add @nx/rspack \`\`\` -{% /tab %} -{% tab label="yarn" %} -\`\`\`bash -yarn add -D @nx/rspack@latest -\`\`\` -{% /tab %} -{% tab label="pnpm" %} -\`\`\`bash -pnpm add -D @nx/rspack@latest -\`\`\` -{% /tab %} -{% /tabs %} + ### Generate a new React project using Rspack @@ -74,28 +61,14 @@ You can generate a [Web](/nx-api/web) application, and then use the \`@nx/rspack Make sure you have the Web plugin installed. -{% tabs %} -{% tab label="npm" %} -\`\`\`bash -npm i -D @nrwl/web@latest -\`\`\` -{% /tab %} -{% tab label="yarn" %} -\`\`\`bash -yarn add -D @nrwl/web@latest -\`\`\` -{% /tab %} -{% tab label="pnpm" %} \`\`\`bash -pnpm add -D @nrwl/web@latest +nx add @nx/web \`\`\` -{% /tab %} -{% /tabs %} Then generate the application. \`\`\`bash -nx g @nrwl/web:app my-app --style=css +nx g @nx/web:app my-app --style=css \`\`\` Finally, configure Rspack for the new project. diff --git a/nx-dev/nx-dev/pages/conf.tsx b/nx-dev/nx-dev/pages/conf.tsx index f83c75304c91f..281481bee62f9 100644 --- a/nx-dev/nx-dev/pages/conf.tsx +++ b/nx-dev/nx-dev/pages/conf.tsx @@ -1,6 +1,6 @@ import { Footer, Header } from '@nx/nx-dev/ui-common'; import { - ConfHealthAndSafety, + CodeOfConduct, ConfLocation, ConfScheduleShort, ConfSpeakers, @@ -333,7 +333,7 @@ export default function ConfPage(): JSX.Element {
- + {/*SPONSORS
diff --git a/nx-dev/nx-dev/pages/launch-nx.tsx b/nx-dev/nx-dev/pages/launch-nx.tsx index 5656f59344360..14caf15623330 100644 --- a/nx-dev/nx-dev/pages/launch-nx.tsx +++ b/nx-dev/nx-dev/pages/launch-nx.tsx @@ -4,7 +4,7 @@ import { LaunchWeekAnnouncements, LaunchWeekSpeakers, LaunchNxCommunityPartners, - ConfHealthAndSafety, + CodeOfConduct, } from '@nx/nx-dev/ui-conference'; import { NextSeo } from 'next-seo'; import Link from 'next/link'; @@ -24,9 +24,9 @@ export default function ConfPage(): JSX.Element { 'Join us for Launch Nx when we’ll be announcing exciting new features and plans for Nx and Nx Cloud, culminating in a free, half-day online conference on Thursday, Feb. 8th.', images: [ { - url: 'https://nx.dev/images/launch-nx-media.jpg', - width: 1000, - height: 500, + url: 'https://nx.dev/socials/launch-nx-feb-2024.jpg', + width: 1600, + height: 900, alt: 'Launch Nx - February 5-9, 2024', type: 'image/jpeg', }, @@ -46,7 +46,7 @@ export default function ConfPage(): JSX.Element { > {/*INTRO*/}
-
+
@@ -247,8 +247,8 @@ export default function ConfPage(): JSX.Element {
- {/*HEALTH AND SAFETY*/} - {/*
+ {/*CODE OF CONDUCT*/} +

- */} +