docs(core): improve core features and concepts

This commit is contained in:
Juri 2023-09-05 23:20:24 +02:00 committed by Juri Strumpflohner
parent 470a0a3021
commit 68064b53b0
30 changed files with 8008 additions and 639 deletions

View File

@ -794,7 +794,7 @@
"disableCollapsible": false "disableCollapsible": false
}, },
{ {
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"path": "/concepts/task-pipeline-configuration", "path": "/concepts/task-pipeline-configuration",
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"isExternal": false, "isExternal": false,
@ -802,7 +802,7 @@
"disableCollapsible": false "disableCollapsible": false
}, },
{ {
"name": "Affected", "name": "How Affected Works",
"path": "/concepts/affected", "path": "/concepts/affected",
"id": "affected", "id": "affected",
"isExternal": false, "isExternal": false,
@ -848,14 +848,6 @@
"id": "more-concepts", "id": "more-concepts",
"isExternal": false, "isExternal": false,
"children": [ "children": [
{
"name": "Customizing Inputs",
"path": "/concepts/more-concepts/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Incremental Builds", "name": "Incremental Builds",
"path": "/concepts/more-concepts/incremental-builds", "path": "/concepts/more-concepts/incremental-builds",
@ -1055,7 +1047,7 @@
"disableCollapsible": false "disableCollapsible": false
}, },
{ {
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"path": "/concepts/task-pipeline-configuration", "path": "/concepts/task-pipeline-configuration",
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"isExternal": false, "isExternal": false,
@ -1063,7 +1055,7 @@
"disableCollapsible": false "disableCollapsible": false
}, },
{ {
"name": "Affected", "name": "How Affected Works",
"path": "/concepts/affected", "path": "/concepts/affected",
"id": "affected", "id": "affected",
"isExternal": false, "isExternal": false,
@ -1133,14 +1125,6 @@
"id": "more-concepts", "id": "more-concepts",
"isExternal": false, "isExternal": false,
"children": [ "children": [
{
"name": "Customizing Inputs",
"path": "/concepts/more-concepts/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Incremental Builds", "name": "Incremental Builds",
"path": "/concepts/more-concepts/incremental-builds", "path": "/concepts/more-concepts/incremental-builds",
@ -1296,14 +1280,6 @@
], ],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Customizing Inputs",
"path": "/concepts/more-concepts/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Incremental Builds", "name": "Incremental Builds",
"path": "/concepts/more-concepts/incremental-builds", "path": "/concepts/more-concepts/incremental-builds",
@ -1462,6 +1438,31 @@
"id": "recipes", "id": "recipes",
"isExternal": false, "isExternal": false,
"children": [ "children": [
{
"name": "Tasks & Caching",
"path": "/recipes/running-tasks",
"id": "running-tasks",
"isExternal": false,
"children": [
{
"name": "Fine-tuning Caching with Inputs",
"path": "/recipes/running-tasks/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Defining a Task Pipeline",
"path": "/recipes/running-tasks/defining-task-pipeline",
"id": "defining-task-pipeline",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{ {
"name": "Adopting Nx", "name": "Adopting Nx",
"path": "/recipes/adopting-nx", "path": "/recipes/adopting-nx",
@ -2419,6 +2420,47 @@
], ],
"disableCollapsible": false "disableCollapsible": false
}, },
{
"name": "Tasks & Caching",
"path": "/recipes/running-tasks",
"id": "running-tasks",
"isExternal": false,
"children": [
{
"name": "Fine-tuning Caching with Inputs",
"path": "/recipes/running-tasks/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Defining a Task Pipeline",
"path": "/recipes/running-tasks/defining-task-pipeline",
"id": "defining-task-pipeline",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{
"name": "Fine-tuning Caching with Inputs",
"path": "/recipes/running-tasks/customizing-inputs",
"id": "customizing-inputs",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Defining a Task Pipeline",
"path": "/recipes/running-tasks/defining-task-pipeline",
"id": "defining-task-pipeline",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{ {
"name": "Adopting Nx", "name": "Adopting Nx",
"path": "/recipes/adopting-nx", "path": "/recipes/adopting-nx",

View File

@ -689,7 +689,7 @@
"itemList": [], "itemList": [],
"isExternal": false, "isExternal": false,
"path": "/core-features/run-tasks", "path": "/core-features/run-tasks",
"tags": ["run-tasks"] "tags": ["run-tasks", "cache-task-results"]
}, },
{ {
"id": "cache-task-results", "id": "cache-task-results",
@ -805,7 +805,7 @@
"itemList": [], "itemList": [],
"isExternal": false, "isExternal": false,
"path": "/core-features/run-tasks", "path": "/core-features/run-tasks",
"tags": ["run-tasks"] "tags": ["run-tasks", "cache-task-results"]
}, },
"/core-features/cache-task-results": { "/core-features/cache-task-results": {
"id": "cache-task-results", "id": "cache-task-results",
@ -986,17 +986,17 @@
}, },
{ {
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"description": "", "description": "",
"file": "shared/concepts/task-pipeline-configuration", "file": "shared/concepts/task-pipeline-configuration",
"itemList": [], "itemList": [],
"isExternal": false, "isExternal": false,
"path": "/concepts/task-pipeline-configuration", "path": "/concepts/task-pipeline-configuration",
"tags": ["run-tasks", "cache-task-results", "use-task-executors"] "tags": ["run-tasks", "use-task-executors"]
}, },
{ {
"id": "affected", "id": "affected",
"name": "Affected", "name": "How Affected Works",
"description": "", "description": "",
"file": "shared/using-nx/affected", "file": "shared/using-nx/affected",
"itemList": [], "itemList": [],
@ -1056,16 +1056,6 @@
"description": "Get deeper into how Nx works and its different aspects.", "description": "Get deeper into how Nx works and its different aspects.",
"file": "", "file": "",
"itemList": [ "itemList": [
{
"id": "customizing-inputs",
"name": "Customizing Inputs",
"description": "",
"file": "shared/concepts/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/concepts/more-concepts/customizing-inputs",
"tags": ["cache-task-results"]
},
{ {
"id": "incremental-builds", "id": "incremental-builds",
"name": "Incremental Builds", "name": "Incremental Builds",
@ -1318,17 +1308,17 @@
}, },
"/concepts/task-pipeline-configuration": { "/concepts/task-pipeline-configuration": {
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"description": "", "description": "",
"file": "shared/concepts/task-pipeline-configuration", "file": "shared/concepts/task-pipeline-configuration",
"itemList": [], "itemList": [],
"isExternal": false, "isExternal": false,
"path": "/concepts/task-pipeline-configuration", "path": "/concepts/task-pipeline-configuration",
"tags": ["run-tasks", "cache-task-results", "use-task-executors"] "tags": ["run-tasks", "use-task-executors"]
}, },
"/concepts/affected": { "/concepts/affected": {
"id": "affected", "id": "affected",
"name": "Affected", "name": "How Affected Works",
"description": "", "description": "",
"file": "shared/using-nx/affected", "file": "shared/using-nx/affected",
"itemList": [], "itemList": [],
@ -1413,16 +1403,6 @@
"description": "Get deeper into how Nx works and its different aspects.", "description": "Get deeper into how Nx works and its different aspects.",
"file": "", "file": "",
"itemList": [ "itemList": [
{
"id": "customizing-inputs",
"name": "Customizing Inputs",
"description": "",
"file": "shared/concepts/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/concepts/more-concepts/customizing-inputs",
"tags": ["cache-task-results"]
},
{ {
"id": "incremental-builds", "id": "incremental-builds",
"name": "Incremental Builds", "name": "Incremental Builds",
@ -1618,16 +1598,6 @@
"path": "/concepts/more-concepts", "path": "/concepts/more-concepts",
"tags": [] "tags": []
}, },
"/concepts/more-concepts/customizing-inputs": {
"id": "customizing-inputs",
"name": "Customizing Inputs",
"description": "",
"file": "shared/concepts/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/concepts/more-concepts/customizing-inputs",
"tags": ["cache-task-results"]
},
"/concepts/more-concepts/incremental-builds": { "/concepts/more-concepts/incremental-builds": {
"id": "incremental-builds", "id": "incremental-builds",
"name": "Incremental Builds", "name": "Incremental Builds",
@ -1824,6 +1794,37 @@
"description": "In depth recipes for common tasks", "description": "In depth recipes for common tasks",
"file": "", "file": "",
"itemList": [ "itemList": [
{
"id": "running-tasks",
"name": "Tasks & Caching",
"description": "A series of recipes that show how to run tasks efficiently with Nx",
"file": "",
"itemList": [
{
"id": "customizing-inputs",
"name": "Fine-tuning Caching with Inputs",
"description": "",
"file": "shared/recipes/running-tasks/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/customizing-inputs",
"tags": ["run-tasks", "cache-task-results"]
},
{
"id": "defining-task-pipeline",
"name": "Defining a Task Pipeline",
"description": "",
"file": "shared/recipes/running-tasks/defining-task-pipeline",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/defining-task-pipeline",
"tags": ["run-tasks"]
}
],
"isExternal": false,
"path": "/recipes/running-tasks",
"tags": []
},
{ {
"id": "adopting-nx", "id": "adopting-nx",
"name": "Adopting Nx", "name": "Adopting Nx",
@ -3017,6 +3018,57 @@
"path": "/recipes", "path": "/recipes",
"tags": [] "tags": []
}, },
"/recipes/running-tasks": {
"id": "running-tasks",
"name": "Tasks & Caching",
"description": "A series of recipes that show how to run tasks efficiently with Nx",
"file": "",
"itemList": [
{
"id": "customizing-inputs",
"name": "Fine-tuning Caching with Inputs",
"description": "",
"file": "shared/recipes/running-tasks/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/customizing-inputs",
"tags": ["run-tasks", "cache-task-results"]
},
{
"id": "defining-task-pipeline",
"name": "Defining a Task Pipeline",
"description": "",
"file": "shared/recipes/running-tasks/defining-task-pipeline",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/defining-task-pipeline",
"tags": ["run-tasks"]
}
],
"isExternal": false,
"path": "/recipes/running-tasks",
"tags": []
},
"/recipes/running-tasks/customizing-inputs": {
"id": "customizing-inputs",
"name": "Fine-tuning Caching with Inputs",
"description": "",
"file": "shared/recipes/running-tasks/customizing-inputs",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/customizing-inputs",
"tags": ["run-tasks", "cache-task-results"]
},
"/recipes/running-tasks/defining-task-pipeline": {
"id": "defining-task-pipeline",
"name": "Defining a Task Pipeline",
"description": "",
"file": "shared/recipes/running-tasks/defining-task-pipeline",
"itemList": [],
"isExternal": false,
"path": "/recipes/running-tasks/defining-task-pipeline",
"tags": ["run-tasks"]
},
"/recipes/adopting-nx": { "/recipes/adopting-nx": {
"id": "adopting-nx", "id": "adopting-nx",
"name": "Adopting Nx", "name": "Adopting Nx",

View File

@ -11,16 +11,30 @@
"description": "", "description": "",
"file": "shared/concepts/task-pipeline-configuration", "file": "shared/concepts/task-pipeline-configuration",
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"path": "/concepts/task-pipeline-configuration" "path": "/concepts/task-pipeline-configuration"
}, },
{ {
"description": "", "description": "",
"file": "shared/using-nx/affected", "file": "shared/using-nx/affected",
"id": "affected", "id": "affected",
"name": "Affected", "name": "How Affected Works",
"path": "/concepts/affected" "path": "/concepts/affected"
}, },
{
"description": "",
"file": "shared/recipes/running-tasks/customizing-inputs",
"id": "customizing-inputs",
"name": "Fine-tuning Caching with Inputs",
"path": "/recipes/running-tasks/customizing-inputs"
},
{
"description": "",
"file": "shared/recipes/running-tasks/defining-task-pipeline",
"id": "defining-task-pipeline",
"name": "Defining a Task Pipeline",
"path": "/recipes/running-tasks/defining-task-pipeline"
},
{ {
"description": "", "description": "",
"file": "shared/recipes/root-level-scripts", "file": "shared/recipes/root-level-scripts",
@ -51,6 +65,13 @@
} }
], ],
"cache-task-results": [ "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",
"id": "run-tasks",
"name": "Run Tasks",
"path": "/core-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.", "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/core-features/cache-task-results",
@ -67,17 +88,10 @@
}, },
{ {
"description": "", "description": "",
"file": "shared/concepts/task-pipeline-configuration", "file": "shared/recipes/running-tasks/customizing-inputs",
"id": "task-pipeline-configuration",
"name": "Task Pipeline Configuration",
"path": "/concepts/task-pipeline-configuration"
},
{
"description": "",
"file": "shared/concepts/customizing-inputs",
"id": "customizing-inputs", "id": "customizing-inputs",
"name": "Customizing Inputs", "name": "Fine-tuning Caching with Inputs",
"path": "/concepts/more-concepts/customizing-inputs" "path": "/recipes/running-tasks/customizing-inputs"
}, },
{ {
"description": "", "description": "",
@ -433,7 +447,7 @@
"description": "", "description": "",
"file": "shared/concepts/task-pipeline-configuration", "file": "shared/concepts/task-pipeline-configuration",
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"path": "/concepts/task-pipeline-configuration" "path": "/concepts/task-pipeline-configuration"
}, },
{ {

View File

@ -186,7 +186,7 @@
{ {
"name": "Run Tasks", "name": "Run Tasks",
"description": "Learn about the various ways you can use Nx to run tasks in your workspace.", "description": "Learn about the various ways you can use Nx to run tasks in your workspace.",
"tags": ["run-tasks"], "tags": ["run-tasks", "cache-task-results"],
"id": "run-tasks", "id": "run-tasks",
"file": "shared/core-features/run-tasks" "file": "shared/core-features/run-tasks"
}, },
@ -296,13 +296,13 @@
"file": "shared/concepts/improve-worst-case-ci-times" "file": "shared/concepts/improve-worst-case-ci-times"
}, },
{ {
"name": "Task Pipeline Configuration", "name": "What is a Task Pipeline",
"tags": ["run-tasks", "cache-task-results", "use-task-executors"], "tags": ["run-tasks", "use-task-executors"],
"id": "task-pipeline-configuration", "id": "task-pipeline-configuration",
"file": "shared/concepts/task-pipeline-configuration" "file": "shared/concepts/task-pipeline-configuration"
}, },
{ {
"name": "Affected", "name": "How Affected Works",
"tags": ["run-tasks"], "tags": ["run-tasks"],
"id": "affected", "id": "affected",
"file": "shared/using-nx/affected" "file": "shared/using-nx/affected"
@ -341,12 +341,6 @@
"id": "more-concepts", "id": "more-concepts",
"description": "Get deeper into how Nx works and its different aspects.", "description": "Get deeper into how Nx works and its different aspects.",
"itemList": [ "itemList": [
{
"name": "Customizing Inputs",
"id": "customizing-inputs",
"tags": ["cache-task-results"],
"file": "shared/concepts/customizing-inputs"
},
{ {
"name": "Incremental Builds", "name": "Incremental Builds",
"id": "incremental-builds", "id": "incremental-builds",
@ -460,6 +454,25 @@
"id": "recipes", "id": "recipes",
"description": "In depth recipes for common tasks", "description": "In depth recipes for common tasks",
"itemList": [ "itemList": [
{
"name": "Tasks & Caching",
"id": "running-tasks",
"description": "A series of recipes that show how to run tasks efficiently with Nx",
"itemList": [
{
"name": "Fine-tuning Caching with Inputs",
"id": "customizing-inputs",
"tags": ["run-tasks", "cache-task-results"],
"file": "shared/recipes/running-tasks/customizing-inputs"
},
{
"name": "Defining a Task Pipeline",
"id": "defining-task-pipeline",
"tags": ["run-tasks"],
"file": "shared/recipes/running-tasks/defining-task-pipeline"
}
]
},
{ {
"name": "Adopting Nx", "name": "Adopting Nx",
"id": "adopting-nx", "id": "adopting-nx",

View File

@ -121,7 +121,7 @@ When you run a task, Nx uses the inputs for your task to create a hash that is u
If this index does not exist, Nx runs the command and if the command succeeds, it stores the result 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/more-concepts/customizing-inputs" /%} {% 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

View File

@ -1,209 +0,0 @@
# Customizing Inputs and Named Inputs
The `inputs` property of a task allows you to define under what conditions the cache for that task should be invalidated and the task should be run again. 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). Those `inputs` can be `fileset`s, `runtime` inputs or `env` variables.
If you find yourself reusing the same `inputs` definitions, you can instead create a `namedInput` in the project configuration or `nx.json` and use that `namedInput` in your `inputs` array.
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
Knowing the syntax doesn't always explain how you would use the feature, so here are two scenarios explaining how to customize `inputs` to match your particular set up.
## Defaults
If you don't specify any `inputs`, Nx uses as inputs every file in the task's project and every file in that project's dependencies. It's the same as writing this:
```jsonc {% fileName="nx.json" %}
{
"namedInputs": {
"default": ["{projectRoot}/**/*"]
},
"targetDefaults": {
"build": {
"inputs": ["default", "^default"]
}
}
}
```
This default behavior works and will always give you correct output, but it might re-run a task in some cases where the cache could have been used instead. Modifying `inputs` and `namedInputs` is all about getting the most you can out of the caching mechanism.
## Scenario 1: React App
Let's say we have a repo with two projects. There's a React app (`react-app`) that depends on a React UI library (`ui-library`).
### Global Settings
In the root `nx.json` file, we can set the following `namedInputs`:
```jsonc {% fileName="nx.json" %}
{
"namedInputs": {
"sharedGlobals": ["{workspaceRoot}/babel.config.json"],
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/*.spec.ts",
"!{projectRoot}/**/*.md",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.ts",
"!{projectRoot}/.eslintrc.json"
]
}
}
```
This configuration defines three `namedInputs`.
- `sharedGlobals` contains root level files that should invalidate the cache for all projects. Note that `tsconfig.base.json` and the `package.json` lock files are handled behind the scenes by Nx so that when you modify the specific properties that affect your project, the cache is invalidated.
- `default` contains every file in the project and everything defined in `sharedGlobals`
- `production` starts with every file in `default`, but removes `.spec.ts` files, markdown files and some project-specific config files.
These names are not hard-coded. You can add your own `namedInputs` or rename these as you see fit.
With these `namedInputs` in place, we can set default `inputs` for project targets in `nx.json`:
```jsonc {% fileName="nx.json" %}
{
"namedInputs": {
"sharedGlobals": [
/* ... */
],
"default": [
/* ... */
],
"production": [
/* ... */
]
},
"targetDefaults": {
"build": {
"inputs": ["production", "^production"],
"dependsOn": ["^build"]
},
"test": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"]
}
}
}
```
In this configuration, `build` needs to be re-run if the project's `production` files are changed or the dependencies' `production` files are changed. The `"dependsOn": ["^build"]` setting ensures that the output files of the dependencies are correct, but it does not tell Nx to re-run this project's build target when those outputs change. That's why `"^production"` is needed in the `inputs` array.
Note that we are using `^production` instead of `^default` because changing test files of a dependency should not invalidate the build cache for this project.
The `test` target cache is invalidated if test or production code is changed in this project (`default`) or if production code is changed in a dependency `^production`. The tests also need to be run again if the root level `jest.preset.js` file is modified.
### Project Settings
In the `ui-library` library, we have some `*.spec.tsx` files that we don't want to count as production files. We can modify the project configuration to account for this:
```jsonc {% command="ui-library/project.json" %}
{
"namedInputs": {
"production": [
// copied this definition from nx.json
"default",
"!{projectRoot}/**/*.spec.ts",
"!{projectRoot}/**/*.spec.tsx", // added this line
"!{projectRoot}/**/*.md",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.ts",
"!{projectRoot}/.eslintrc.json"
]
}
}
```
Note that I need to copy the entire definition of `production` from `nx.json`. This entry overwrites the existing `production` entry defined in `nx.json`, but `default` and `sharedGlobals` are inherited. Now when I modify a `spec.tsx` file in `ui-library`, the build for `ui-library` is unaffected and the build for `react-app` is unaffected.
{% callout type="note" title="Modifying production in nx.json" %}
You could also handle this scenario by modifying the `production` definition in the `nx.json` so that it applies to all projects in the repo. In fact, the defaults created by Nx do exactly that: `"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)"`. This is a complex glob expression though and is not particularly helpful for explaining the concepts of `inputs` and `namedInputs`.
{% /callout %}
The `build` and `test` `inputs` do not need to be modified at the project level, since the defaults defined at the root are still correct.
## Scenario 2: Generated Documentation Site
Let's say you have a repo with two projects, a `docs-site` app that contains all the code for rendering a documentation site and a `content` library that contains markdown files that are used as the content of the site.
The `content` library has a node script `.ts` file that is used to check through the markdown files for internal broken links. The `test` target looks like this:
```jsonc
{
"targets": {
"test": {
"inputs": ["default", "^production"],
"executor": "nx:run-commands",
"command": "ts-node ./check-for-broken-links.ts"
}
}
}
```
Note that we are overwriting the default `inputs` for `test` because changes to the root `jest.preset.js` file shouldn't affect this project's tests.
This library's `production` definition should look like this:
```jsonc
{
"namedInputs": {
"production": ["default", "!{projectRoot}/**/*.ts"]
}
}
```
This ensures that the `.md` files are included in the `production` file set, but the `check-for-broken-links.ts` script is not. Now changes to a markdown file in `content` will force a re-build of `docs-site`, even though changes to markdown files in `docs-site` will not force a re-build.
## Scenario 3: Deploying applications and publishing libraries
We can use `nx:run-commands` and a custom `deploy` target for deploying our applications. Normally, we want to deploy only the applications that have been affected by recent changes. The hash for checking whether a certain project was affected consists of several parts:
- The full command we are running (e.g. `nx run my-app:deploy`)
- The hash of the project's files and files of the dependencies
- The hash of the target executor's dependencies
Since `nx:run-commands` is a special executor we can't automatically say what packages this executor depends on, so any change in the installed packages will cause a cache miss. This is of course not ideal.
We can therefore specify what external packages our executor should depend on (in this case none, we only depend on `fly` version)
```jsonc
{
"targets": {
"deploy": {
"inputs": [
"production",
{ "externalDependencies": [] }, // this explicitly tells hasher to ignore all external packages for executor
{ "runtime": "fly version" }
],
"dependsOn": ["build"],
"executor": "nx:run-commands",
"cwd": "dist/{projectRoot}",
"command": "fly deploy"
}
}
}
```
Similarly, we can specify dependencies for publishing libraries:
```jsonc
{
"targets": {
"publish": {
"inputs": [
"production",
{ "externalDependencies": ["lerna"] } // we explicitly say that our run-commands depends on lerna only
],
"dependsOn": ["build"],
"executor": "nx:run-commands",
"cwd": "dist/{projectRoot}",
"command": "lerna publish"
}
}
}
```

View File

@ -16,20 +16,17 @@ By default, the computation hash for something like `nx test remixapp` includes:
> This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global > This behavior is customizable. For instance, lint checks may only depend on the source code of the project and global
> configs. Builds can depend on the dts files of the compiled libs instead of their source. > configs. Builds can depend on the dts files of the compiled libs instead of their source.
After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks After Nx computes the hash for a task, it then checks if it ran this exact computation before. First, it checks locally, and then if it is missing, and if a remote cache is configured, it checks remotely. If a matching computation is found, Nx retrieves and replays it. This includes restoring files.
locally, and then if it is missing, and if a remote cache is configured, it checks remotely.
If Nx finds the computation, Nx retrieves it and replays it. Nx places the right files in the right folders and Nx places the right files in the right folders and prints the terminal output. From the users point of view, the command ran the same, just a lot faster.
prints the terminal output. From the users point of view, the command ran the same, just a lot faster.
![cache](/shared/images/caching/cache.svg) ![cache](/shared/images/caching/cache.svg)
If Nx doesnt find a corresponding computation hash, Nx runs the task, and after it completes, it takes the If Nx doesnt find a corresponding computation hash, Nx runs the task, and after it completes, it takes the outputs and the terminal logs and stores them locally (and, if configured, remotely as well). All of this happens transparently, so you dont have to worry about it.
outputs and the terminal logs and stores them locally (and if configured remotely as well). All of this happens
transparently, so you dont have to worry about it.
Although conceptually this is fairly straightforward, Nx optimizes this to make this experience good for you. For ## Optimizations
instance, Nx:
Although conceptually this is fairly straightforward, Nx optimizes the experience for you. For instance, Nx:
- Captures stdout and stderr to make sure the replayed output looks the same, including on Windows. - Captures stdout and stderr to make sure the replayed output looks the same, including on Windows.
- Minimizes the IO by remembering what files are replayed where. - Minimizes the IO by remembering what files are replayed where.
@ -43,104 +40,130 @@ 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 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. work happens. The rest is either left as is or restored from the cache.
## Source Code Hash Inputs ## What is Cached
The result of building/testing an application or a library depends on the source code of that project and all the source Nx works on the process level. Regardless of the tools used to build/test/lint/etc.. your project, the results are cached.
codes of all the libraries it depends on (directly or indirectly).
By default, Nx is conservative. When running, It sets up hooks to collect stdout/stderr before running the command. All the output is cached and then replayed during a cache hit.
say, `nx run test --script=remixapp` Nx will consider all the files in the `remixapp` directory and all the files
in the `header` and `footer` directories (`remixapp` dependencies). This would result in unnecessary cache misses. For
instance, we know that changing a `footer`'s spec file will not change the result of the test command above.
We can define a more precise configuration as follows: 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`:
```json {% fileName="nx.json"%} {% tabs %}
{% tab label="package.json" %}
```json {% fileName="apps/myapp/package.json"%}
{ {
"namedInputs": { "name": "myapp",
"default": ["{projectRoot}/**/*"], "dependencies": {},
"production": ["!{projectRoot}/**/*.spec.tsx"] "devDependencies": {},
}, "nx": {
"targets": {
"build": {
"outputs": ["{projectRoot}/build", "{projectRoot}/public/build"]
}
}
}
}
```
{% /tab %}
{% tab label="project.json" %}
```json {% fileName="apps/myapp/project.json"%}
{
"name": "myapp",
...
"targets": {
"build": {
...
"outputs": ["dist/dist/myapp"]
}
}
}
```
{% /tab %}
If the `outputs` property for a given target isn't defined in the project'
s `package.json` file, Nx will look at the global, workspace-wide definition in the `targetDefaults` section of `nx.json`:
```jsonc {% fileName="nx.json"%}
{
...
"targetDefaults": { "targetDefaults": {
"build": { "build": {
"inputs": ["production", "^production"] "dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/build",
"{projectRoot}/public/build"
]
}
}
}
```
If neither is defined, Nx defaults to caching `dist` and `build` at the root of the repository.
{% callout title="Output vs OutputPath" type="info" %}
Several executors have a property in options called `outputPath`. On its own, this property does not influence caching or what is stored at the end of a run. You can reuse that property though by defining your outputs like: `outputs: [{options.outputPath}]`.
{% /callout %}
## Define Cache Inputs
By default the cache considers all project files (e.g. `{projectRoot}/**/*`). This behavior can be customized by defining in a much more fine-grained way what files should be included or excluded for each target.
{% tabs %}
{% tab label="Globally" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {
"build": {
"inputs": ["{projectRoot}/**/*", "!{projectRoot}/**/*.md"]
...
}, },
"test": { "test": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.config.ts"] "inputs": [...]
} }
} }
} }
``` ```
<!-- Prettier causes the callout block to break --> {% /tab %}
<!-- prettier-ignore-start --> {% tab label="Project Level" %}
{% callout type="note" title="Special Syntax Explained" %} ```json {% fileName="packages/some-project/project.json" %}
- `{projectRoot}` is a key word that is replaced by the path to the current project's root directory.
- `{workspaceRoot}` is a key word that is replaced by the root path of your workspace.
- The `^` symbol means "of dependencies", i.e. `"^production"` means match the files defined for the `"production"` `namedInput`, but for all projects which the current project depends on.
- The rest of the string is parsed with the [minimatch](https://github.com/isaacs/minimatch) library
{% /callout %}
<!-- prettier-ignore-end -->
With this configuration, the build script will only consider the non-test files of `remixapp`, `header` and `footer`.
The test script will consider all the source files for the project under test and only non-test files of its
dependencies. The test script will also consider the jest config file at the root of the workspace.
For more information about modifying `inputs` and `namedInputs` for your own repo, read [Customizing Inputs](/concepts/more-concepts/customizing-inputs)
### Filesets
By default a value in `inputs` refers to either a `namedInput` or a `fileset`.
```json {% fileName="project.json"%}
{ {
"name": "some-project",
"targets": { "targets": {
"some-target": {
"inputs": ["{workspaceRoot}/cache-file-input"]
}
}
}
```
**is equivalent to**
```json {% fileName="project.json"%}
{
"targets": {
"some-target": {
"inputs": [{ "fileset": "{workspaceRoot}/cache-file-input" }]
}
}
}
```
<!-- prettier-ignore-start -->
{% callout type="note" title="Ignored Files" %}
By default any file that is ignored by either a `.gitignore` or `.nxignore` file will not be considered
as an input to the cache.
You could consider using a runtime hash input if a file ignored by one of these files is needed as an
input to the hash.
{% /callout %}
<!-- prettier-ignore-end -->
## Runtime Hash Inputs
Your targets can also depend on runtime values.
```json {% fileName="nx.json"%}
{
"targetDefaults": {
"build": { "build": {
"inputs": [{ "env": "MY_ENV_NAME" }, { "runtime": "node -v" }] "inputs": ["!{projectRoot}/**/*.md"],
...
},
"test": {
"inputs": [...]
} }
...
} }
} }
``` ```
{% /tab %}
Inputs may include
- source files
- environment variables
- runtime inputs
- command line arguments
Learn more about fine tuning caching in the [Fine-tuning Caching with Inputs page](/recipes/running-tasks/customizing-inputs).
## Args Hash Inputs ## Args Hash Inputs
Finally, in addition to Source Code Hash Inputs and Runtime Hash Inputs, Nx needs to consider the arguments: For Finally, in addition to Source Code Hash Inputs and Runtime Hash Inputs, Nx needs to consider the arguments: For
@ -172,94 +195,8 @@ npx nx build header
npx nx build footer npx nx build footer
``` ```
## What is Cached ## Next steps
Nx works on the process level. Regardless of the tools used to build/test/lint/etc.. your project, the results are Learn more about how to configure caching, where the cache is stored, how to reset it and more.
cached.
Nx sets up hooks to collect stdout/stderr before running the command. All the output is cached and then replayed - [Cache Task Results](/core-features/cache-task-results)
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`:
```json {% fileName="package.json"%}
{
"nx": {
"targets": {
"build": {
"outputs": ["{projectRoot}/build", "{projectRoot}/public/build"]
}
}
}
}
```
If the `outputs` property for a given target isn't defined in the project'
s `package.json` file, Nx will look at the `targetDefaults` section of `nx.json`:
```jsonc {% fileName="nx.json"%}
{
...
"targetDefaults": {
"build": {
"dependsOn": [
"^build"
],
"outputs": [
"{projectRoot}/dist",
"{projectRoot}/build",
"{projectRoot}/public/build"
]
}
}
}
```
If neither is defined, Nx defaults to caching `dist` and `build` at the root of the repository.
## Skipping Cache
Sometimes you want to skip the cache. If, for example, you are measuring the performance of a command, you can use
the `--skip-nx-cache` flag to skip checking the computation cache.
```shell
npx nx run build --skip-nx-cache
npx nx run test --skip-nx-cache
```
## Customizing the Cache Location
The cache is stored in `node_modules/.cache/nx` by default. To change the cache location, update the `cacheDirectory` option for the task runner in `nx.json`:
{% tabs %}
{% tab label="Nx >= 17" %}
```json {% fileName="nx.json"%}
{
"cacheDirectory": "/tmp/mycache"
}
```
{% /tab %}
{% tab label="Nx < 17" %}
```json {% fileName="nx.json"%}
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheDirectory": "/tmp/mycache"
}
}
}
}
```
{% /tab %}
{% /tabs %}
## Outputs vs Output Path
Several executors have a property in `options` called `outputPath`. On its own, this property does not influence caching or what is stored at the end of a run. Frequently though, this property would point to your build artifacts. In these cases, you can include `"{options.outputPath}"` in the `outputs` array for your target to avoid duplicating the value.
The properties inside `options` are never considered for determining where artifacts are located, and are just passed into the executor when running a task. If there are artifacts that save to disk they **_must_** be included in the `outputs` array or they will not be restored when there is a cache hit for that particular target.

View File

@ -1,64 +1,65 @@
# Task Pipeline Configuration # What is a Task Pipeline
Nx runs tasks in the most efficient way possible. The `nx.json` file is the place where you can configure how Nx does it. If you have a monorepo workspace (or modularized app), you rarely just run one task. Almost certainly there are relationships among the projects in the workspace and hence tasks need to follow a certain order.
## Run Tasks in Parallel As you can see in the graph visualization below, the `myreactapp` project depends on other projects. Therefore, when running the build for `myreactapp`, these dependencies need to be built first so that `myreactapp` can use the resulting build artifacts.
If you want to increase the number of processes running tasks to, say, 5 (by default, it is 3), pass the {% graph height="450px" %}
following:
```shell ```json
npx nx build myapp --parallel=5
```
Note, you can also change the default in `nx.json`, like this:
{% tabs %}
{% tab label="Nx >= 17" %}
```json {% fileName="nx.json"%}
{ {
"parallel": 5 "projects": [
} {
``` "name": "myreactapp",
"type": "app",
{% /tab %} "data": {
{% tab label="Nx < 17" %} "tags": []
}
```json {% fileName="nx.json"%} },
{ {
"tasksRunnerOptions": { "name": "shared-ui",
"default": { "type": "lib",
"runner": "nx/tasks-runners/default", "data": {
"options": { "tags": []
"parallel": 5 }
},
{
"name": "feat-products",
"type": "lib",
"data": {
"tags": []
} }
} }
} ],
"dependencies": {
"myreactapp": [
{ "source": "myreactapp", "target": "feat-products", "type": "static" }
],
"shared-ui": [],
"feat-products": [
{
"source": "feat-products",
"target": "shared-ui",
"type": "static"
}
]
},
"workspaceLayout": { "appsDir": "", "libsDir": "" },
"affectedProjectIds": [],
"focus": null,
"groupByFolder": false
} }
``` ```
{% /tab %} {% /graph %}
{% /tabs %}
## Define Task Dependencies (aka Task Pipelines) While you could manage these relationships on your own and set up custom scripts to build all projects in the proper order (e.g. first build `shared-ui`, then `feat-products` and finally `myreactapp`), that kind of approach is not scalable and would need constant maintenance as you keep changing and adding projects to your workspace.
To ensure tasks run in the correct order, Nx needs to know how the tasks depend on each other. Add the following to `nx.json`: This becomes even more evident when you run tasks in parallel. You cannot just naively run all of them at the same time. Instead, the task orchestrator needs to respect the order of the tasks so that it builds libraries first and then resumes building the apps that depend on those libraries in parallel.
```jsonc {% fileName="nx.json"%} ![task-graph-execution](/shared/mental-model/task-graph-execution.svg)
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
With this, Nx knows that before it can build a project, it needs to build all of its dependencies first. There are, however, no constraints on tests. Nx allows you to define task dependencies in the form of "rules", which are then followed when running tasks. There's a [detailed recipe](/recipes/running-tasks/defining-task-pipeline) but here's the high-level overview:
This mechanism is very flexible. Let's look at this example:
```jsonc {% fileName="nx.json"%} ```jsonc {% fileName="nx.json"%}
{ {
@ -74,37 +75,22 @@ This mechanism is very flexible. Let's look at this example:
} }
``` ```
> Note, older versions of Nx used targetDependencies instead of targetDefaults. `targetDependencies` was removed in version 16, with `targetDefaults` replacing its use case. {% callout title="Older versions of Nx" type="warning" %}
Older versions of Nx used targetDependencies instead of targetDefaults. `targetDependencies` was removed in version 16, with `targetDefaults` replacing its use case.
{% /callout %}
When running `nx test myproj`, the above configuration would tell Nx to When running `nx test myproj`, the above configuration would tell Nx to
1. Run the `test` command for `myproj` 1. Run the `test` command for `myproj`
2. But since there's a dependency defined from `test -> build` (see `test:["build"]`), Nx runs `build` for `myproj` 2. But since there's a dependency defined from `test` to `build` (see `"dependsOn" :["build"]`), Nx runs `build` for `myproj` first.
first. 3. `build` itself defines a dependency on `prebuild` (on the same project) as well as `build` of all the dependencies. Therefore, it will run the `prebuild` script and will run the `build` script for all the dependencies.
3. `build` itself defines a dependency on `prebuild` (on the same project) as well as `build` of all the dependencies.
Therefore, it will run the `prebuild` script and will run the `build` script for all the dependencies.
Note, Nx doesn't have to run all builds before it starts running tests. The task orchestrator will run as many tasks Note, Nx doesn't have to run all builds before it starts running tests. The task orchestrator will run as many tasks in parallel as possible as long as the constraints are met.
in parallel as possible as long as the constraints are met.
Situations like this are pretty common: These rules can be defined globally in the `nx.json` file or locally per project in the `package.json` or `project.json` files.
![task-graph-execution](/shared/mental-model/task-graph-execution.svg) ## Configure It for Your Own Project
Because we described the rules in `nx.json`, they will apply to all the projects in the repo. You can also define Learn about all the details of how to configure [task pipelines in the according recipe section](/recipes/running-tasks/defining-task-pipeline).
project-specific rules by adding them to the project's configuration ([learn more](/reference/project-configuration#dependson)).
```jsonc {% fileName="package.json"%}
{
...
"nx": {
"targets": {
"test": {
"dependsOn": [
"build"
]
}
}
}
}
```

View File

@ -1,12 +1,10 @@
# Cache Task Results # Cache Task Results
It's costly to rebuild and retest the same code over and over again. Nx uses a computation cache to never rebuild the It's costly to rebuild and retest the same code over and over again. Nx has the most sophisticated and battle-tested computation caching system to make sure it never rebuilds the same code twice. It knows when the task you are about to run, has been executed before, so it can use the cache to restore the results of running that task.
same code twice.
## Setup If you want to learn more about the conceptual model behind Nx's caching, read [How Caching Works](/concepts/how-caching-works).
Nx has the most sophisticated and battle-tested computation caching system. It knows when the task you are ## Define Cacheable Tasks
about to run has been executed before, so it can use the cache to restore the results of running that task.
{% tabs %} {% tabs %}
{% tab label="Nx >= 17" %} {% tab label="Nx >= 17" %}
@ -53,48 +51,125 @@ the same output. As an example, e2e test runs that hit the backend API cannot be
the result of the test run. the result of the test run.
{% /callout %} {% /callout %}
Now, run the following command twice. The second time the operation will be instant: Now, if you run a `build` task twice, the second time the operation will be instant because it is restored from the cache.
{% terminal-video src="/documentation/shared/images/caching/cache-terminal-animation.mp4" alt="Video showing the terminal output of running a build command first without cache and then with cache. The 2nd run is almost instant, taking just 18ms" /%}
Nx restores both
- the terminal output
- the files & artifacts created as a result of running the task (e.g. your `build` or `dist` directory)
Keep reading to learn how to fine-tune what gets cached.
## Fine-tune Caching with Inputs and Outputs
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.)
- **Outputs -** define folders where files might be placed as part of the task execution.
You can define these inputs and outputs at the project level (`project.json`) or globally for all projects (in `nx.json`).
Take the following example: we want to exclude all `*.md` files from the cache such that whenever we change the README.md (or any other markdown file), it does _not_ invalidate the build cache. We also know that the build output will be stored in a folder named after the project name in the `dist` folder at the root of the workspace.
To achieve this, we can add an `inputs` and `outputs` definition globally for all projects or at a per-project level:
{% tabs %}
{% tab label="Globally" %}
```json {% fileName="nx.json" %}
{
"targetDefaults": {
"build": {
"inputs": ["{projectRoot}/**/*", "!{projectRoot}/**/*.md"],
"outputs": ["{workspaceRoot}/dist/{projectName"]
}
}
}
```
{% /tab %}
{% tab label="Project Level" %}
```json {% fileName="packages/some-project/project.json" %}
{
"name": "some-project",
"targets": {
"build": {
...
"inputs": ["!{projectRoot}/**/*.md"],
"outputs": ["dist/apps/some-project"],
...
}
...
}
}
```
{% /tab %}
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).
## Where is the Cache Stored?
By default the cache is stored locally in your `node_modules/.cache`. Cache results are stored for a week before they get deleted. You can customize the cache location in the `nx.json`:
{% tabs %}
{% tab label="Nx >= 17" %}
```json {% fileName="nx.json"%}
{
"cacheDirectory": "/tmp/mycache"
}
```
{% /tab %}
{% tab label="Nx < 17" %}
```json {% fileName="nx.json"%}
{
"tasksRunnerOptions": {
"default": {
"options": {
"cacheDirectory": "/tmp/mycache"
}
}
}
}
```
{% /tab %}
{% /tabs %}
## Enable Remote Caching
You can enable remote caching by connecting to [Nx Cloud](/nx-cloud). To connect Nx to Nx Cloud run the following command:
```shell ```shell
nx build header npx nx connect
``` ```
```{% command="nx build header"%} Learn more about [remote caching](/core-features/remote-cache).
> nx run header:build [local cache]
## Turn off or Skip the Cache
> header@0.0.0 build If you want to ignore the cache (both reads and writes), use the `--skip-nx-cache` flag:
> rimraf dist && rollup --config
```shell
src/index.tsx → dist... nx build header --skip-nx-cache
created dist in 858ms
—————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for project header (13ms)
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.
``` ```
## Replaying from 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](/core-features/remote-cache#skipping-cloud-cache), you might want to use `--no-cloud` to skip remote caching.
When Nx determines that the inputs for a task have not changed, it recreates the outputs of that task as if it actually ran on your machine - but much faster. The outputs of a cached task include both the terminal output and the files created in the defined `output` directories for that task. ## Clear the Local Cache
You can test this out by deleting the `dist` folder that the `header:build` task outputs to and then running `nx build header` again. The cached task will replay instantly and the correct files will be present in the `dist` folder. To clear the local cache, run:
```treeview ```shell
header/ npx nx reset
└── dist/ <-- this folder gets recreated
``` ```
If your task creates output artifacts in a different location, you can [change the output folder(s)](/reference/project-configuration#outputs) that are cached. You can also [customize which inputs](/concepts/more-concepts/customizing-inputs) will invalidate the cache if they are changed. For more details refer to the [`nx reset`](/nx-api/nx/documents/reset) page.
## Advanced Caching
For a more in-depth understanding of the caching implementation and to fine-tune the caching for your repo, read [How Caching Works](/concepts/how-caching-works).
## Local Computation Caching
By default, Nx uses a local computation cache. Nx stores the cached values only for a week, after which they
are deleted. To clear the cache run [`nx reset`](/nx-api/nx/documents/reset), and Nx will create a new one the next time it tries to access it.

View File

@ -1,7 +1,6 @@
# Use Remote Caching # Use Remote Caching
The computation cache provided by Nx can be distributed across multiple machines. You can either build an implementation of the cache or use Nx Cloud. Nx Cloud is an app that provides a fast and zero-config implementation of distributed caching. It's completely free for OSS projects and for most closed-sourced 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 distributed caching. It's completely free for OSS projects and for most closed-sourced projects ([read more here](https://nx.app/pricing)).
projects ([read more here](https://nx.app/pricing)).
![Diagram showing Teika sharing his cache with CI, Kimiko and James](/shared/images/dte/distributed-caching.svg) ![Diagram showing Teika sharing his cache with CI, Kimiko and James](/shared/images/dte/distributed-caching.svg)
@ -86,9 +85,8 @@ forth.
**You will also see an interactive tutorial helping you explore distributed caching and the Nx Cloud user interface.** **You will also see an interactive tutorial helping you explore distributed caching and the Nx Cloud user interface.**
If you lose this link, you can still connect your workspace to Nx Cloud. Go to [nx.app](https://nx.app), create an **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`.
account, and connect your workspace using the access token from `nx.json`.
## Skipping Cloud ## 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. 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.

View File

@ -1,7 +1,6 @@
# Run Tasks # Run Tasks
Monorepos can have hundreds or even thousands of projects, so being able to run actions against all (or some) of 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.
them is a key feature of a tool like Nx.
## Definitions ## Definitions
@ -34,10 +33,7 @@ Each project has the `test` and `build` targets defined. Tasks can be defined as
{ {
"targets": { "targets": {
"build": { "build": {
"executor": "nx:run-commands", "command": "webpack -c webpack.conf.js"
"options": {
"command": "webpack -c webpack.conf.js"
}
}, },
"test": { "test": {
"executor": "@nx/jest:jest", "executor": "@nx/jest:jest",
@ -68,7 +64,7 @@ npx nx test header
### Run Tasks for Multiple Projects ### Run Tasks for Multiple Projects
you can use the `run-many` command to run a task for multiple projects. Here are a couple of examples. 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` target for all projects in the repo:
@ -92,6 +88,45 @@ Note that Nx parallelizes all these tasks making also sure they are run in the r
Learn more about the [run-many](/nx-api/nx/documents/run-many) command. Learn more about the [run-many](/nx-api/nx/documents/run-many) command.
### Run Tasks in Parallel
If you want to increase the number of processes running tasks to, say, 5 (by default, it is 3), pass the
following:
```shell
npx nx build myapp --parallel=5
```
Note, you can also change the default in `nx.json`, like this:
{% tabs %}
{% tab label="Nx >= 17" %}
```json {% fileName="nx.json"%}
{
"parallel": 5
}
```
{% /tab %}
{% tab label="Nx < 17" %}
```json {% fileName="nx.json"%}
{
"tasksRunnerOptions": {
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"parallel": 5
}
}
}
}
```
{% /tab %}
{% /tabs %}
### Run Tasks on Projects Affected by a PR ### Run Tasks on Projects Affected by a PR
You can also run a command for all the projects affected by your PR like this: You can also run a command for all the projects affected by your PR like this:
@ -102,6 +137,81 @@ npx nx affected -t test
Learn more about the affected command [here](/concepts/affected). Learn more about the affected command [here](/concepts/affected).
## Defining a Task Pipeline
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)).
{% graph height="450px" %}
```json
{
"projects": [
{
"name": "myreactapp",
"type": "app",
"data": {
"tags": []
}
},
{
"name": "shared-ui",
"type": "lib",
"data": {
"tags": []
}
},
{
"name": "feat-products",
"type": "lib",
"data": {
"tags": []
}
}
],
"dependencies": {
"myreactapp": [
{ "source": "myreactapp", "target": "feat-products", "type": "static" }
],
"shared-ui": [],
"feat-products": [
{
"source": "feat-products",
"target": "shared-ui",
"type": "static"
}
]
},
"workspaceLayout": { "appsDir": "", "libsDir": "" },
"affectedProjectIds": [],
"focus": null,
"groupByFolder": false
}
```
{% /graph %}
However, you need to define for which targets such ordering matters. In the following example we are telling Nx that before running the `build` target it needs to run the `build` target on all the projects the current project depends on:
```json {% fileName="nx.json" %}
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Meaning, if we run `nx build myreactapp`, Nx will first run `build` on `modules-shared-ui` and `modules-products` before running `build` on `myreactapp`. You can define these task dependencies globally for your workspace in `nx.json` or individually in each project's `project.json` file.
Learn all the details:
- [What a task pipeline is all about](/concepts/task-pipeline-configuration)
- [How to configure a task pipeline](/recipes/running-tasks/defining-task-pipeline)
## Run Root-Level Tasks ## Run Root-Level Tasks
Sometimes you have tasks that apply to the entire codebase rather than to a single project. But you still want those tasks to go through the "Nx pipeline" in order to benefit from caching. You can define these in the root-level `package.json` as follows: Sometimes you have tasks that apply to the entire codebase rather than to a single project. But you still want those tasks to go through the "Nx pipeline" in order to benefit from caching. You can define these in the root-level `package.json` as follows:
@ -137,22 +247,3 @@ If you want Nx to cache the task, but prefer to use npm (or pnpm/yarn) to run th
``` ```
Learn more about root-level tasks [in our dedicated recipe page](/recipes/tips-n-tricks/root-level-scripts). Learn more about root-level tasks [in our dedicated recipe page](/recipes/tips-n-tricks/root-level-scripts).
## Defining the Task Pipeline
In a monorepo you might need to define the order with which the tasks are being run. For example, if project `app` depends on `header` you might want to run the `build` target on `header` before running the `build` target on `app`.
Nx automatically understands these dependencies but you can configure for which targets such ordering needs to be respected by defining them in the `nx.json`:
```json {% fileName="nx.json" %}
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Learn more about it in the [Task Pipeline Configuration](/concepts/task-pipeline-configuration).

View File

@ -1,6 +1,6 @@
# Global Implicit Dependencies # Global Implicit Dependencies
Since v14.4, Nx supports [`inputs` and `namedInputs`](/concepts/more-concepts/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/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.
## Projects Depending on Global Files ## 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. 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](/concepts/more-concepts/customizing-inputs) For a more detailed explanation, read the [Customizing Inputs and Named Inputs guide](/recipes/running-tasks/customizing-inputs)
### Dependencies on Sections of the Root `package.json` File ### Dependencies on Sections of the Root `package.json` File

View File

@ -90,4 +90,121 @@ pnpm install --global nx@latest
The advantage of a global installation is that you don't have to prefix your commands with npx, yarn or pnpm. The global Nx installation hands off the process execution to the local Nx installation in your repository, which eliminates any issues with outdated globally installed packages. The advantage of a global installation is that you don't have to prefix your commands with npx, yarn or pnpm. The global Nx installation hands off the process execution to the local Nx installation in your repository, which eliminates any issues with outdated globally installed packages.
Learn more about [managing and troubleshooting a global Nx installation](/concepts/more-concepts/global-nx). ### Updating your global Nx installation
There are some cases where an issue could arise when using an outdated global installation of Nx. If the structure of your Nx workspace no longer matches up with what the globally installed copy of Nx expects, it may fail to hand off to your local installation properly and instead error. This commonly results in errors such as:
- `Could not find Nx modules in this workspace.`
- `The current directory isn't part of an Nx workspace.`
If you find yourself in this position, you will need to update your global install of Nx.
In most cases, you can update a globally installed npm package by rerunning the command you used to install it, as described [above](#installing-nx-globally)
If you cannot remember which package manager you installed Nx globally with or are still encountering issues, you can locate other installs of Nx with these commands:
{% tabs %}
{% tab label="npm" %}
```shell
npm list --global nx
```
{% /tab %}
{% tab label="yarn" %}
```shell
yarn global list nx
```
{% /tab %}
{% tab label="pnpm" %}
```shell
pnpm list --global nx
```
{% /tab %}
{% /tabs %}
{% callout type="note" title="Older Global Installations" %}
In prior versions, Nx could be installed globally via `@nrwl/cli` or `@nrwl/tao`. If you are seeing these warnings but cannot find other global installations of Nx via the above commands, you should look for these packages as well. In general, you should remove these and install the latest version of `nx` instead.
{% /callout %}
You can then remove the extra global installations by running the following commands for the duplicate installations:
{% tabs %}
{% tab label="npm" %}
```shell
npm rm --global nx @nrwl/cli @nrwl/tao
```
{% /tab %}
{% tab label="yarn" %}
```shell
yarn global remove nx @nrwl/cli @nrwl/tao
```
{% /tab %}
{% tab label="pnpm" %}
```shell
pnpm rm --global nx @nrwl/cli @nrwl/tao
```
{% /tab %}
{% /tabs %}
Finally, to complete your global installation update, simply reinstall it as described [above](#installing-nx-globally).
## Self-managed Nx installation
This type of installation is useful for repositories that may not contain any JavaScript or TypeScript (e.g. .Net or Java based workspaces that want to leverage Nx features). In such setup Nx is able to manage its own installation via a `.nx` directory.
By allowing Nx to manage its installation, a given repository is no longer required to contain a package.json or node_modules in its root.
### Usage
You can install Nx in the `.nx/installation` directory by running `nx init` in a directory without package.json, and picking to install Nx in the current directory.
When Nx is installed in `.nx`, you can run Nx via a global Nx installation or the nx and nx.bat scripts that were created. In either case, the wrapper (.nx/nxw.js) will be invoked and ensure that the current workspace is up to date prior to invoking Nx.
{% tabs %}
{% tab label="Global Install" %}
```shell
> nx build my-project
> nx generate application
> nx graph
```
{% /tab %}
{% tab label="nx shell script" %}
```shell
> ./nx build my-project
> ./nx generate application
> ./nx graph
```
{% /tab %}
{% tab label="nx.bat" %}
```shell
> ./nx.bat build my-project
> ./nx.bat generate application
> ./nx.bat graph
```
{% /tab %}
{% /tabs %}
{% callout type="note" title="Available since Nx v15.8.7" %}
Support for `--use-dot-nx-installation` was added in Nx v15.8.7. To ensure that it is available, specify the version of nx when running your command so that `npx` doesn't accept an older version that is in the cache. (e.g. `npx nx@latest init`)
{% /callout %}

File diff suppressed because it is too large Load Diff

View File

@ -136,13 +136,13 @@ For example, excluding markdown files from the `lint` task cache:
This includes all TypeScript files, but excludes markdown files. As a result, changing your README won't invalidate your "lint cache". 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](/concepts/more-concepts/customizing-inputs). Learn more about [Nx Inputs](/recipes/running-tasks/customizing-inputs).
## Learn More ## Learn More
{% cards %} {% cards %}
{% card title="Customizing Inputs and Named Inputs" description="Learn more about how to fine-tune caching with custom inputs" type="documentation" url="/concepts/more-concepts/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/customizing-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="/core-features/cache-task-results" /%}

View File

@ -170,12 +170,12 @@ Creating the equivalent configuration with Nx yields the following files:
For each `turbo.json` configuration property, the equivalent Nx property is listed. For each `turbo.json` configuration property, the equivalent Nx property is listed.
| **Global Configuration:** | | | **Global Configuration:** | |
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/concepts/more-concepts/customizing-inputs) | | `globalDependencies` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/customizing-inputs) |
| `globalEnv` | add to the [`sharedGlobals` `namedInput`](/concepts/more-concepts/customizing-inputs) as an [`env` input](/reference/project-configuration#env-variables) | | `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) | | `globalPassThroughEnv` | N/A. See [Defining Environment Variables](/recipes/tips-n-tricks/define-environment-variables) |
| `globalDotEnv` | add to the [`sharedGlobals` `namedInput`](/concepts/more-concepts/customizing-inputs) | | `globalDotEnv` | add to the [`sharedGlobals` `namedInput`](/recipes/running-tasks/customizing-inputs) |
| **Task Configuration:** | | | **Task Configuration:** | |
| ------------------------------- | ------------------------------------------------------------------------------------------------- | | ------------------------------- | ------------------------------------------------------------------------------------------------- |
@ -204,7 +204,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). | | `--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 | | `--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 | | `--force` | [`nx reset`](/nx-api/nx/documents/reset) and then run the command again |
| `--global-deps` | Use [`inputs` in the `nx.json`](/concepts/more-concepts/customizing-inputs) or project configuration | | `--global-deps` | Use [`inputs` in the `nx.json`](/recipes/running-tasks/customizing-inputs) or project configuration |
| `--framework-inference` | Nx knows if you're using a particular framework if you use an executor for that framework. | | `--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`) | | `--ignore` | Use an [`.nxignore` file](/reference/nxignore) (or `.gitignore`) |
| `--log-order` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) | | `--log-order` | Use [`--output-style`](/nx-api/nx/documents/run-many#output-style) |

View File

@ -98,7 +98,7 @@ Documentation site generated in /docs
Nx read the output from the cache instead of running the command for 1 out of 1 tasks. 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](/concepts/more-concepts/customizing-inputs). Read more about [cacheableOperations](/core-features/cache-task-results) and fine-tuning caching with [task inputs](/recipes/running-tasks/customizing-inputs).
## Keep using NPM to run scripts rather than Nx ## Keep using NPM to run scripts rather than Nx

View File

@ -0,0 +1,351 @@
---
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.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}"
}
}
}
```

View File

@ -0,0 +1,108 @@
---
title: Defining a Task Pipeline
description: This recipe shows how to define task dependencies in your Nx workspace
---
# Defining a Task Pipeline
Running a specific task like `build` in a monorepo usually involves running multiple commands.
If you want to learn more about the concept of a task pipeline and its importance in a monorepo, have a look at [the What is a Task Pipeline page](/concepts/task-pipeline-configuration).
## Define Dependencies Between Tasks
You can define dependencies among tasks by using the `dependsOn` property:
```json
// nx.json
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
## Per Project vs Global
Task dependencies can be [defined globally](/reference/nx-json#target-defaults) for all projects in `nx.json` file:
```json {% fileName="nx.json"%}
{
...
"targetDefaults": {
"build": {
"dependsOn": ["^build"]
}
}
}
```
Or they can be [defined per-project](/reference/project-configuration#dependson) in the `project.json` or `package.json` files. If for example you have a `prebuild` step for a given project, you can define that relationship as follows:
{% tabs %}
{% tab label="package.json" %}
```json {% fileName="apps/myapp/package.json"%}
{
"name": "myapp",
"dependencies": {},
"devDependencies": {},
...
"nx": {
"targets": {
"build": {
"dependsOn": [
"prebuild"
]
}
}
}
}
```
{% /tab %}
{% tab label="project.json" %}
```json {% fileName="apps/myreactapp/project.json"%}
{
"name": "myreactapp",
...
"targets": {
"prebuild": {
"command": "echo Prebuild"
},
"build": {
"command": "echo Build",
"dependsOn": ["prebuild"]
}
}
}
```
{% /tab %}
{% /tabs %}
## 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.
To view the task graph in your browser, run:
```shell
npx nx graph
```
And then select "Tasks" from the top-left dropdown, choose the target (e.g. `build`, `test`,..) and either show all tasks or select a specific project you're interested in. Here's an example of the `playwright` Nx plugin `build` target (in the [Nx repo](https://github.com/nrwl/nx)).
![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:
![Selecting "Focus task in Nx Graph" from the context menu in VS Code](/shared/recipes/running-tasks/task-graph-context-menu.webp)
It'll then visualize within the IDE:
![Task graph of the Playwright Nx plugin in the nx repo being rendered in VS Code](/shared/recipes/running-tasks/task-graph-vscode.webp)

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -32,7 +32,7 @@ When the [cache inputs](#cache-inputs) for a [task](#task) match an existing ent
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). 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](/concepts/more-concepts/customizing-inputs) > See: [Customizing Inputs and Named Inputs](/recipes/running-tasks/customizing-inputs)
### Cache Miss ### Cache Miss

View File

@ -107,14 +107,12 @@ If you accidentally generate a project in the wrong folder, use the [move genera
### inputs & namedInputs ### inputs & namedInputs
Named inputs defined in `nx.json` are merged with the named inputs defined in each project's project.json. 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}`.
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`. 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`. Using pseudocode `inputs = projectJson.targets.build.inputs || nxJson.targetDefaults.build.inputs`.
You can also define and redefine named inputs. This enables one key use case, where your `nx.json` can define things You can also define and redefine named inputs. This enables one key use case, where your `nx.json` can define things like this (which applies to every project):
like this (which applies to every project):
``` ```
"test": { "test": {
@ -125,7 +123,7 @@ like this (which applies to every project):
} }
``` ```
And projects can define their `production` fileset, without having to redefine the inputs for the `test` target. And projects can define their `production` inputs, without having to redefine the inputs for the `test` target.
```json {% fileName="project.json" %} ```json {% fileName="project.json" %}
{ {
@ -139,7 +137,7 @@ In this case Nx will use the right `production` input for each project.
{% cards %} {% 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="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="/concepts/more-concepts/customizing-inputs" /%} {% 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" /%}
{% /cards %} {% /cards %}
### Target Defaults ### Target Defaults

View File

@ -285,7 +285,7 @@ sources (non-test sources) of its dependencies. In other words, it treats test s
{% cards %} {% 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="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="/concepts/more-concepts/customizing-inputs" /%} {% 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" /%}
{% /cards %} {% /cards %}
### Outputs ### Outputs

View File

@ -50,14 +50,13 @@
- [Types of Configuration](/concepts/types-of-configuration) - [Types of Configuration](/concepts/types-of-configuration)
- [How Caching Works](/concepts/how-caching-works) - [How Caching Works](/concepts/how-caching-works)
- [Improve Worst Case CI Times](/concepts/dte) - [Improve Worst Case CI Times](/concepts/dte)
- [Task Pipeline Configuration](/concepts/task-pipeline-configuration) - [What is a Task Pipeline](/concepts/task-pipeline-configuration)
- [Affected](/concepts/affected) - [How Affected Works](/concepts/affected)
- [Module Federation](/concepts/module-federation) - [Module Federation](/concepts/module-federation)
- [Faster Builds with Module Federation](/concepts/module-federation/faster-builds-with-module-federation) - [Faster Builds with Module Federation](/concepts/module-federation/faster-builds-with-module-federation)
- [Micro Frontend Architecture](/concepts/module-federation/micro-frontend-architecture) - [Micro Frontend Architecture](/concepts/module-federation/micro-frontend-architecture)
- [Manage Library Versions with Module Federation](/concepts/module-federation/manage-library-versions-with-module-federation) - [Manage Library Versions with Module Federation](/concepts/module-federation/manage-library-versions-with-module-federation)
- [More Concepts](/concepts/more-concepts) - [More Concepts](/concepts/more-concepts)
- [Customizing Inputs](/concepts/more-concepts/customizing-inputs)
- [Incremental Builds](/concepts/more-concepts/incremental-builds) - [Incremental Builds](/concepts/more-concepts/incremental-builds)
- [Illustrated Distributed Task Execution](/concepts/more-concepts/illustrated-dte) - [Illustrated Distributed Task Execution](/concepts/more-concepts/illustrated-dte)
- [Nx and Turborepo](/concepts/more-concepts/turbo-and-nx) - [Nx and Turborepo](/concepts/more-concepts/turbo-and-nx)
@ -78,6 +77,9 @@
- [Nx and the Nx Wrapper](/concepts/more-concepts/nx-and-the-wrapper) - [Nx and the Nx Wrapper](/concepts/more-concepts/nx-and-the-wrapper)
- [Managing your Global Nx Installation](/concepts/more-concepts/global-nx) - [Managing your Global Nx Installation](/concepts/more-concepts/global-nx)
- [Recipes](/recipes) - [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)
- [Adopting Nx](/recipes/adopting-nx) - [Adopting Nx](/recipes/adopting-nx)
- [NPM/Yarn/PNPM workspaces](/recipes/adopting-nx/adding-to-monorepo) - [NPM/Yarn/PNPM workspaces](/recipes/adopting-nx/adding-to-monorepo)
- [Migrate From Turborepo](/recipes/adopting-nx/from-turborepo) - [Migrate From Turborepo](/recipes/adopting-nx/from-turborepo)

View File

@ -4,8 +4,6 @@
Before reading this guide, [check out the mental model guide](/concepts/mental-model). It will help you understand how computation caching fits into the rest of Nx. Before reading this guide, [check out the mental model guide](/concepts/mental-model). It will help you understand how computation caching fits into the rest of Nx.
{% /callout %} {% /callout %}
## Overview
When you run `nx test app1`, you are telling Nx to run the app1:test task plus all the tasks it depends on. When you run `nx test app1`, you are telling Nx to run the app1:test task plus all the tasks it depends on.
When you run `nx run-many -t test -p app1 lib`, you are telling Nx to do the same for two tasks app1:test When you run `nx run-many -t test -p app1 lib`, you are telling Nx to do the same for two tasks app1:test

View File

@ -889,6 +889,8 @@ const latestRecipesRefactoring = {
const coreFeatureRefactoring = { const coreFeatureRefactoring = {
'/core-features/share-your-cache': '/core-features/remote-cache', '/core-features/share-your-cache': '/core-features/remote-cache',
'/concepts/more-concepts/customizing-inputs':
'/recipes/running-tasks/customizing-inputs',
}; };
/* /*

View File

@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef } from 'react';
export function VideoLoop({ export function VideoLoop({
src, src,