React Standalone Tutorial - Part 4: Task Pipelines

Running Dependent Tasks

Let's build the store application:

~/store

npx nx build store

1 22/2 dependent project tasks succeeded [0 read from cache] 3 4 Hint: you can run the command with --verbose to see the full dependent project outputs 5 6 ———————————————————————————————————————————————————————————————————————————————————————————————————————— 7 8 9> nx run store:build:production 10 11 12vite v3.2.4 building for production... 1343 modules transformed. 14dist/store/index.html 0.46 KiB 15dist/store/assets/index.50de2671.css 0.03 KiB / gzip: 0.05 KiB 16dist/store/assets/index.f18c2b19.js 157.69 KiB / gzip: 51.26 KiB 17dist/store/assets/index.f18c2b19.js.map 565.79 KiB 18 19 ———————————————————————————————————————————————————————————————————————————————————————————————————————— 20 21 > NX Successfully ran target build for project store and 2 task(s) they depend on (6s) 22 23

Notice this line:

✔ 2/2 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:

1{ 2 "targetDefaults": { 3 "build": { 4 "dependsOn": ["^build"], 5 "inputs": ["production", "^production"] 6 } 7 } 8} 9

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.

More On The Task Pipeline Configuration

See the Task Pipeline Configuration Guide for more details on how to configure your Task Graph.

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.

~/store

npx nx build store

1 22/2 dependent project tasks succeeded [2 read from cache] 3 4 Hint: you can run the command with --verbose to see the full dependent project outputs 5 6 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 7 8 9> nx run store:build:production [local cache] 10 11 12vite v3.2.4 building for production... 1343 modules transformed. 14dist/store/index.html 0.46 KiB 15dist/store/assets/index.50de2671.css 0.03 KiB / gzip: 0.05 KiB 16dist/store/assets/index.f18c2b19.js 157.69 KiB / gzip: 51.26 KiB 17dist/store/assets/index.f18c2b19.js.map 565.79 KiB 18 19 20 ———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— 21 22 > NX Successfully ran target build for project store and 2 task(s) they depend on (42ms) 23 24 Nx read the output from the cache instead of running the command for 3 out of 3 tasks. 25

This time the build only took 42 ms. Also, if you delete the dist folder and run the command again, the build output will be recreated.

More Task Caching Details

See the documentation for more information on caching.

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.

More On Customizing Inputs

See the Customizing Inputs Guide for more details on how to set inputs for your tasks.

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:

shared/ui/project.json
1{ 2 "name": "shared-ui", 3 "targets": { 4 "build": { 5 "executor": "@nx/vite:build", 6 "outputs": ["{options.outputPath}"], 7 "options": { 8 "outputPath": "dist/shared/ui" 9 } 10 }, 11 "lint": { 12 "executor": "@nx/linter:eslint", 13 "outputs": ["{options.outputFile}"], 14 "options": { 15 "lintFilePatterns": ["shared/ui/**/*.{ts,tsx,js,jsx}"] 16 } 17 }, 18 "test": { 19 "executor": "@nx/vite:test", 20 "outputs": ["{projectRoot}/coverage"], 21 "options": { 22 "passWithNoTests": true 23 } 24 } 25 } 26} 27
Nx 15 and lower use @nrwl/ instead of @nx/

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:

git add . ; git commit -m "commiting to test affected"

Then make a change to the styles of your cart project:

cart/src/lib/cart.module.css
1.container { 2 color: blue; 3} 4

You can visualize how our workspace is affected by this change using the command:

npx nx affected:graph

Loading...

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:

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.

Affected Documentation

Checkout Affected documentation for more details

What's Next