docs(core): react standalone tutorial (#13453)
This commit is contained in:
parent
a064252bcf
commit
2e544177ea
@ -114,6 +114,38 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "React Standalone Tutorial",
|
||||
"id": "react-standalone-tutorial",
|
||||
"description": "In this tutorial you'll create a frontend-focused workspace with Nx.",
|
||||
"itemList": [
|
||||
{
|
||||
"name": "1 - Code Generation",
|
||||
"id": "1-code-generation",
|
||||
"file": "shared/react-standalone-tutorial/1-code-generation"
|
||||
},
|
||||
{
|
||||
"name": "2 - Project Graph",
|
||||
"id": "2-project-graph",
|
||||
"file": "shared/react-standalone-tutorial/2-project-graph"
|
||||
},
|
||||
{
|
||||
"name": "3 - Task Running",
|
||||
"id": "3-task-running",
|
||||
"file": "shared/react-standalone-tutorial/3-task-running"
|
||||
},
|
||||
{
|
||||
"name": "4 - Task Pipelines",
|
||||
"id": "4-task-pipelines",
|
||||
"file": "shared/react-standalone-tutorial/4-task-pipelines"
|
||||
},
|
||||
{
|
||||
"name": "5 - Summary",
|
||||
"id": "5-summary",
|
||||
"file": "shared/react-standalone-tutorial/5-summary"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Angular Tutorial",
|
||||
"id": "angular-tutorial",
|
||||
|
||||
144
docs/shared/react-standalone-tutorial/1-code-generation.md
Normal file
144
docs/shared/react-standalone-tutorial/1-code-generation.md
Normal file
@ -0,0 +1,144 @@
|
||||
---
|
||||
title: 'React Standalone Tutorial - Part 1: Code Generation'
|
||||
description: In this tutorial you'll create a frontend-focused workspace with Nx.
|
||||
---
|
||||
|
||||
{% callout type="check" title="Standalone Repo" %}
|
||||
This tutorial sets up a repo with a single application at the root level that breaks out its code into libraries to add structure.
|
||||
|
||||
You can find more information on about other repo styles in [our introduction](/getting-started/intro).
|
||||
{% /callout %}
|
||||
|
||||
# React Standalone Tutorial - Part 1: Code Generation
|
||||
|
||||
## Contents
|
||||
|
||||
- [1 - Code Generation](/react-standalone-tutorial/1-code-generation)
|
||||
- [2 - Project Graph](/react-standalone-tutorial/2-project-graph)
|
||||
- [3 - Task Running](/react-standalone-tutorial/3-task-running)
|
||||
- [4 - Task Pipelines](/react-standalone-tutorial/4-task-pipelines)
|
||||
- [5 - Summary](/react-standalone-tutorial/5-summary)
|
||||
|
||||
## Creating a New Workspace
|
||||
|
||||
Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses:
|
||||
|
||||
```{% command="npx create-nx-workspace@latest" path="~" %}
|
||||
|
||||
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
|
||||
|
||||
✔ Choose what to create · react
|
||||
✔ Repository name · store
|
||||
✔ Application name · store
|
||||
✔ Default stylesheet format · css
|
||||
✔ Enable distributed caching to make your CI faster · No
|
||||
```
|
||||
|
||||
{% card title="Opting into Nx Cloud" description="You will also be prompted whether to add Nx Cloud to your workspace. We won't address this in this tutorial, but you can see the introduction to Nx Cloud for more details." url="/nx-cloud/intro/what-is-nx-cloud" /%}
|
||||
|
||||
Once the command completes, the file structure should look like this:
|
||||
|
||||
```treeview
|
||||
store/
|
||||
├── e2e/
|
||||
├── src/
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
├── project.json
|
||||
├── README.md
|
||||
├── tsconfig.base.json
|
||||
└── tsconfig.json
|
||||
```
|
||||
|
||||
There are two projects that have been created for you:
|
||||
|
||||
- A React application (`store`) with its configuration files at the root of the repo and source code in `src`.
|
||||
- A project for Cypress e2e tests for our `store` application in `e2e`.
|
||||
|
||||
As far as Nx is concerned, the root-level `store` app owns every file that doesn't belong to a different project. So files in the `e2e` folder belong to the `e2e` project, everything else belongs to `store`.
|
||||
|
||||
{% card title="Nx Cypress Support" description="While we see the Cypress project here, we won't go deeper on Cypress in this tutorial. You can find more materials on Nx Cypress support on the @nrwl/cypress package page." url="/packages/cypress" /%}
|
||||
|
||||
## Generating a Component for the Store
|
||||
|
||||
```{% command="npx nx g @nrwl/react:component shop" path="~/store" %}
|
||||
|
||||
> NX Generating @nrwl/react:component
|
||||
|
||||
✔ Should this component be exported in the project? (y/N) · false
|
||||
CREATE src/app/shop/shop.module.css
|
||||
CREATE src/app/shop/shop.spec.tsx
|
||||
CREATE src/app/shop/shop.tsx
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Generating Libraries
|
||||
|
||||
To create the `cart` and `shared/ui` libraries, use the `@nrwl/react:lib` generator:
|
||||
|
||||
{% side-by-side %}
|
||||
|
||||
```{% command="npx nx g @nrwl/react:library cart" path="~/store" %}
|
||||
|
||||
> NX Generating @nrwl/react:library
|
||||
|
||||
✔ Which bundler would you like to use to build the library? · vite
|
||||
UPDATE nx.json
|
||||
CREATE cart/project.json
|
||||
CREATE .eslintrc.store.json
|
||||
UPDATE project.json
|
||||
UPDATE .eslintrc.json
|
||||
UPDATE e2e/.eslintrc.json
|
||||
CREATE cart/.eslintrc.json
|
||||
CREATE cart/README.md
|
||||
CREATE cart/package.json
|
||||
CREATE cart/src/index.ts
|
||||
CREATE cart/tsconfig.json
|
||||
CREATE cart/tsconfig.lib.json
|
||||
CREATE cart/index.html
|
||||
CREATE cart/src/demo.tsx
|
||||
UPDATE tsconfig.base.json
|
||||
UPDATE package.json
|
||||
CREATE cart/vite.config.ts
|
||||
CREATE cart/tsconfig.spec.json
|
||||
CREATE cart/src/lib/cart.module.css
|
||||
CREATE cart/src/lib/cart.spec.tsx
|
||||
CREATE cart/src/lib/cart.tsx
|
||||
```
|
||||
|
||||
```{% command="npx nx g @nrwl/react:lib shared/ui" path="~/store" %}
|
||||
|
||||
> NX Generating @nrwl/react:library
|
||||
|
||||
✔ Which bundler would you like to use to build the library? · vite
|
||||
UPDATE nx.json
|
||||
CREATE shared/ui/project.json
|
||||
CREATE shared/ui/.eslintrc.json
|
||||
CREATE shared/ui/README.md
|
||||
CREATE shared/ui/package.json
|
||||
CREATE shared/ui/src/index.ts
|
||||
CREATE shared/ui/tsconfig.json
|
||||
CREATE shared/ui/tsconfig.lib.json
|
||||
CREATE shared/ui/index.html
|
||||
CREATE shared/ui/src/demo.tsx
|
||||
UPDATE tsconfig.base.json
|
||||
CREATE shared/ui/vite.config.ts
|
||||
CREATE shared/ui/tsconfig.spec.json
|
||||
CREATE shared/ui/src/lib/shared-ui.module.css
|
||||
CREATE shared/ui/src/lib/shared-ui.spec.tsx
|
||||
CREATE shared/ui/src/lib/shared-ui.tsx
|
||||
```
|
||||
|
||||
{% /side-by-side %}
|
||||
|
||||
You should now be able to see all three projects of our design:
|
||||
|
||||
- `store` in the root
|
||||
- `cart` in `cart`
|
||||
- `shared-ui` in `shared/ui`
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [2: Project Graph](/react-standalone-tutorial/2-project-graph)
|
||||
244
docs/shared/react-standalone-tutorial/2-project-graph.md
Normal file
244
docs/shared/react-standalone-tutorial/2-project-graph.md
Normal file
@ -0,0 +1,244 @@
|
||||
# React Standalone Tutorial - Part 2: Project Graph
|
||||
|
||||
Run the command: `npx nx graph`. A browser should open up with the following contents:
|
||||
|
||||
{% graph height="450px" %}
|
||||
|
||||
```json
|
||||
{
|
||||
"hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59",
|
||||
"projects": [
|
||||
{
|
||||
"name": "cart",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared-ui",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "e2e",
|
||||
"type": "e2e",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"type": "app",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"cart": [],
|
||||
"shared-ui": [],
|
||||
"e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }],
|
||||
"store": []
|
||||
},
|
||||
"workspaceLayout": { "appsDir": "apps", "libsDir": "libs" },
|
||||
"affectedProjectIds": [],
|
||||
"focus": null,
|
||||
"groupByFolder": false,
|
||||
"exclude": []
|
||||
}
|
||||
```
|
||||
|
||||
{% /graph %}
|
||||
|
||||
Nx creates the graph based on the source code. The projects are not linked in this diagram because we haven't actually finished our application. Once we use the shared components in another project, Nx will create the dependency in the graph. Let's do that now.
|
||||
|
||||
## Set Up the Router
|
||||
|
||||
Install the `react-router-dom` package:
|
||||
|
||||
```shell
|
||||
npm i react-router-dom
|
||||
```
|
||||
|
||||
And configure the routes:
|
||||
|
||||
```javascript {% fileName="src/main.tsx" %}
|
||||
import { StrictMode } from 'react';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import * as ReactDOM from 'react-dom/client';
|
||||
|
||||
import App from './app/app';
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</StrictMode>
|
||||
);
|
||||
```
|
||||
|
||||
```javascript {% fileName="src/app/app.tsx" %}
|
||||
import { RoutesCart } from '@store/cart';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import Shop from './shop/shop';
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Routes>
|
||||
<Route path="/" element={<Shop />}></Route>
|
||||
<Route path="/cart" element={<RoutesCart />}></Route>
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### `shared-ui`
|
||||
|
||||
Run the `@nrwl/react:component` generator with the command:
|
||||
|
||||
```{% command="npx nx g @nrwl/react:component banner --project=shared-ui --export" path="~/store" %}
|
||||
|
||||
> NX Generating @nrwl/react:component
|
||||
|
||||
CREATE shared/ui/src/lib/banner/banner.module.css
|
||||
CREATE shared/ui/src/lib/banner/banner.spec.tsx
|
||||
CREATE shared/ui/src/lib/banner/banner.tsx
|
||||
UPDATE shared/ui/src/index.ts
|
||||
```
|
||||
|
||||
Then create a simple `Banner` component in the generated file:
|
||||
|
||||
```javascript {% fileName="shared/ui/src/lib/banner/banner.tsx" %}
|
||||
export interface BannerProps {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function Banner(props: BannerProps) {
|
||||
return <header>{props.text}</header>;
|
||||
}
|
||||
|
||||
export default Banner;
|
||||
```
|
||||
|
||||
### `cart`
|
||||
|
||||
Add the `Banner` component to the cart route and link back to the main page:
|
||||
|
||||
```javascript {% fileName="cart/src/lib/cart.tsx" %}
|
||||
import { Banner } from '@store/shared/ui';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './cart.module.css';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface RoutesCartProps {}
|
||||
|
||||
export function RoutesCart(props: RoutesCartProps) {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<Banner text="Welcome to the cart." />
|
||||
<Link to="/">Continue Shopping</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RoutesCart;
|
||||
```
|
||||
|
||||
### `store`
|
||||
|
||||
Update the `shop` component to use the `Banner` component and link to the cart.
|
||||
|
||||
```javascript {% fileName="src/app/shop/shop.tsx" %}
|
||||
import { Banner } from '@store/shared/ui';
|
||||
import { Link } from 'react-router-dom';
|
||||
import styles from './shop.module.css';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface ShopProps {}
|
||||
|
||||
export function Shop(props: ShopProps) {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<Banner text="Here is a list of products to buy..." />
|
||||
<Link to="/cart">View Cart</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Shop;
|
||||
```
|
||||
|
||||
Now run `npx nx graph` again:
|
||||
|
||||
{% graph height="450px" %}
|
||||
|
||||
```json
|
||||
{
|
||||
"hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59",
|
||||
"projects": [
|
||||
{
|
||||
"name": "cart",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared-ui",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "e2e",
|
||||
"type": "e2e",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"type": "app",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"cart": [{ "source": "cart", "target": "shared-ui", "type": "static" }],
|
||||
"shared-ui": [],
|
||||
"e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }],
|
||||
"store": [
|
||||
{ "source": "store", "target": "cart", "type": "static" },
|
||||
{ "source": "store", "target": "shared-ui", "type": "static" }
|
||||
]
|
||||
},
|
||||
"workspaceLayout": { "appsDir": "apps", "libsDir": "libs" },
|
||||
"affectedProjectIds": [],
|
||||
"focus": null,
|
||||
"groupByFolder": false,
|
||||
"exclude": []
|
||||
}
|
||||
```
|
||||
|
||||
{% /graph %}
|
||||
|
||||
Your graph now shows the dependency lines we expected.
|
||||
|
||||
The Project Graph is more than just a visualization - Nx provides tooling to optimize your task-running and even automate your CI based on this graph. This will be covered in more detail in: [4: Task Pipelines](/react-standalone-tutorial/4-task-pipelines).
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [3: Task Running](/react-standalone-tutorial/3-task-running)
|
||||
100
docs/shared/react-standalone-tutorial/3-task-running.md
Normal file
100
docs/shared/react-standalone-tutorial/3-task-running.md
Normal file
@ -0,0 +1,100 @@
|
||||
# React Standalone Tutorial - 3: Task-Running
|
||||
|
||||
Common tasks include:
|
||||
|
||||
- Building an application
|
||||
- Serving a local web server with the built project
|
||||
- Running your unit tests
|
||||
- Linting your code
|
||||
- Running e2e tests
|
||||
|
||||
When you ran your generators in Part 1, you already set up these more common tasks for each project.
|
||||
|
||||
## Defining Targets
|
||||
|
||||
Here's the `project.json` file for your `shared-ui` project:
|
||||
|
||||
```json {% fileName="libs/common-ui/project.json" %}
|
||||
{
|
||||
"name": "shared-ui",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "shared/ui/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/vite:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/shared/ui"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["shared/ui/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/vite:test",
|
||||
"outputs": ["{projectRoot}/coverage"],
|
||||
"options": {
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can see that three targets are defined here: `build`, `test` and `lint`.
|
||||
|
||||
The properties inside each of these these targets is defined as follows:
|
||||
|
||||
- `executor` - which Nx executor to run. The syntax here is: `<plugin name>:<executor name>`
|
||||
- `outputs` - this is an array of files that would be created by running this target. (This informs Nx on what to save for it's caching mechanisms you'll learn about in [4 - Task Pipelines](/react-standalone-tutorial/4-task-pipelines)).
|
||||
- `options` - this is an object defining which executor options to use for the given target. Every Nx executor allows for options as a way to parameterize it's functionality.
|
||||
|
||||
## Running Tasks
|
||||
|
||||

|
||||
|
||||
Run the `test` target for your `shared-ui` project:
|
||||
|
||||
```{% command="npx nx test shared-ui" path="~/store" %}
|
||||
|
||||
> nx run shared-ui:test
|
||||
|
||||
RUN v0.25.3 /Users/isaac/Documents/code/store/shared/ui
|
||||
✓ src/lib/banner/banner.spec.tsx (1 test) 12ms
|
||||
✓ src/lib/shared-ui.spec.tsx (1 test) 10ms
|
||||
Test Files 2 passed (2)
|
||||
Tests 2 passed (2)
|
||||
Start at 15:00:09
|
||||
Duration 1.05s (transform 375ms, setup 1ms, collect 415ms, tests 22ms)
|
||||
|
||||
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target test for project shared-ui (2s)
|
||||
```
|
||||
|
||||
Next, run a lint check on your `shared-ui` project:
|
||||
|
||||
```{% command="npx nx lint shared-ui" path="~/store" %}
|
||||
|
||||
> nx run shared-ui:lint
|
||||
|
||||
|
||||
Linting "shared-ui"...
|
||||
|
||||
All files pass linting.
|
||||
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target lint for project shared-ui (2s)
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [4: Task Pipelines](/react-standalone-tutorial/4-task-pipelines)
|
||||
243
docs/shared/react-standalone-tutorial/4-task-pipelines.md
Normal file
243
docs/shared/react-standalone-tutorial/4-task-pipelines.md
Normal file
@ -0,0 +1,243 @@
|
||||
# React Standalone Tutorial - Part 4: Task Pipelines
|
||||
|
||||
## Running Dependent Tasks
|
||||
|
||||
Let's build the `store` application:
|
||||
|
||||
```{% command="npx nx build store" path="~/store" %}
|
||||
|
||||
✔ 2/2 dependent project tasks succeeded [0 read from cache]
|
||||
|
||||
Hint: you can run the command with --verbose to see the full dependent project outputs
|
||||
|
||||
————————————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
|
||||
> nx run store:build:production
|
||||
|
||||
|
||||
vite v3.2.4 building for production...
|
||||
✓ 43 modules transformed.
|
||||
dist/store/index.html 0.46 KiB
|
||||
dist/store/assets/index.50de2671.css 0.03 KiB / gzip: 0.05 KiB
|
||||
dist/store/assets/index.f18c2b19.js 157.69 KiB / gzip: 51.26 KiB
|
||||
dist/store/assets/index.f18c2b19.js.map 565.79 KiB
|
||||
|
||||
————————————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project store and 2 task(s) it depends on (6s)
|
||||
|
||||
```
|
||||
|
||||
Notice this line:
|
||||
|
||||
```shell
|
||||
✔ 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:
|
||||
|
||||
```json
|
||||
{
|
||||
"targetDefaults": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["production", "^production"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `"dependsOn": ["^build"]` line says that every `build` task depends on the `build` tasks for its project dependencies. You can override the `dependsOn` setting for individual projects in the `project.json` files.
|
||||
|
||||
{% card title="More On The Task Pipeline Configuration" description="See the Task Pipeline Configuration Guide for more details on how to configure your Task Graph." url="/concepts/task-pipeline-configuration" /%}
|
||||
|
||||
## Skip Repeated Tasks
|
||||
|
||||
Why does Nx always run the dependent tasks? Doesn't that waste time repeating the same work?
|
||||
|
||||
It would, if Nx didn't have a robust caching mechanism to take care of that problem for you. Let's build the `store` app again.
|
||||
|
||||
```{% command="npx nx build store" path="~/store" %}
|
||||
|
||||
✔ 2/2 dependent project tasks succeeded [2 read from cache]
|
||||
|
||||
Hint: you can run the command with --verbose to see the full dependent project outputs
|
||||
|
||||
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
|
||||
> nx run store:build:production [local cache]
|
||||
|
||||
|
||||
vite v3.2.4 building for production...
|
||||
✓ 43 modules transformed.
|
||||
dist/store/index.html 0.46 KiB
|
||||
dist/store/assets/index.50de2671.css 0.03 KiB / gzip: 0.05 KiB
|
||||
dist/store/assets/index.f18c2b19.js 157.69 KiB / gzip: 51.26 KiB
|
||||
dist/store/assets/index.f18c2b19.js.map 565.79 KiB
|
||||
|
||||
|
||||
————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project store and 2 task(s) it depends on (42ms)
|
||||
|
||||
Nx read the output from the cache instead of running the command for 3 out of 3 tasks.
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
{% card title="More Task Caching Details" description="See the documentation for more information on caching." url="/core-features/cache-task-results" /%}
|
||||
|
||||
## Cache Inputs and Outputs
|
||||
|
||||
How does Nx know when to replace a cached task result? And how does Nx know what should be cached?
|
||||
|
||||
Nx determines if a project has been modified by looking at the task's defined `inputs`. And then when the task is completed, it caches the terminal output and all the defined file `outputs`.
|
||||
|
||||
### Inputs
|
||||
|
||||
Inputs for your task caching includes by default any environment details and all the source code of the projects and dependencies affecting your project.
|
||||
|
||||
When you run a task, Nx uses the inputs for your task to create a hash that is used as an index for the task results. If the task has already been run with the same inputs, Nx replays the results stored in the cache.
|
||||
|
||||
If this index does not exist, Nx runs the command and if the command succeeds, it stores the result in the cache.
|
||||
|
||||
{% card title="More On Customizing Inputs" description="See the Customizing Inputs Guide for more details on how to set inputs for your tasks." url="/concepts/task-pipeline-configuration" /%}
|
||||
|
||||
### Outputs
|
||||
|
||||
Outputs of the cache include the terminal output created by the task, as well as any files created by the task - for example: the artifact created by running a `build` task.
|
||||
|
||||
Here are the outputs defined for the `shared-ui` project:
|
||||
|
||||
```json {% fileName="shared/ui/project.json" %}
|
||||
{
|
||||
"name": "shared-ui",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/vite:build",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/shared/ui"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["shared/ui/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/vite:test",
|
||||
"outputs": ["{projectRoot}/coverage"],
|
||||
"options": {
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Outputs are stored in the cache so that terminal output can be replayed, and any created files can be pulled from your cache, and placed where they were created the original time the task was run.
|
||||
|
||||
## Testing Affected Projects
|
||||
|
||||
Another way that Nx saves you from unnecessary work is the `affected` command. `affected` is a mechanism that relies on your git metadata to determine the projects in your workspace that were affected by a given commit.
|
||||
|
||||
Run the command:
|
||||
|
||||
```shell
|
||||
git add . && git commit -m "commiting to test affected"
|
||||
```
|
||||
|
||||
Then make a change to the styles of your `cart` project:
|
||||
|
||||
```css {% fileName="cart/src/lib/cart.module.css" %}
|
||||
.container {
|
||||
color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
You can visualize how our workspace is affected by this change using the command:
|
||||
|
||||
```shell
|
||||
npx nx affected:graph
|
||||
```
|
||||
|
||||
{% graph height="450px" %}
|
||||
|
||||
```json
|
||||
{
|
||||
"hash": "85fd0561bd88f0bcd8703a9e9369592e2805f390d04982fb2401e700dc9ebc59",
|
||||
"projects": [
|
||||
{
|
||||
"name": "cart",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared-ui",
|
||||
"type": "lib",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "e2e",
|
||||
"type": "e2e",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "store",
|
||||
"type": "app",
|
||||
"data": {
|
||||
"tags": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"cart": [{ "source": "cart", "target": "shared-ui", "type": "static" }],
|
||||
"shared-ui": [],
|
||||
"e2e": [{ "source": "e2e", "target": "store", "type": "implicit" }],
|
||||
"store": [
|
||||
{ "source": "store", "target": "cart", "type": "static" },
|
||||
{ "source": "store", "target": "shared-ui", "type": "static" }
|
||||
]
|
||||
},
|
||||
"workspaceLayout": { "appsDir": "apps", "libsDir": "libs" },
|
||||
"affectedProjectIds": ["cart", "store", "e2e"],
|
||||
"focus": null,
|
||||
"groupByFolder": false,
|
||||
"exclude": []
|
||||
}
|
||||
```
|
||||
|
||||
{% /graph %}
|
||||
|
||||
The change made to the `cart` project is also affecting the `store` project. This can be leveraged to run tasks only on the projects that were affected by this commit.
|
||||
|
||||
To run the `test` targets only for affected projects, run the command:
|
||||
|
||||
```shell
|
||||
npx nx affected --target=test
|
||||
```
|
||||
|
||||
This can be particularly helpful in CI pipelines for larger repos, where most commits only affect a small subset of the entire workspace.
|
||||
|
||||
{% card title="Affected Documentation" description="Checkout Affected documentation for more details" url="/nx/affected" /%}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [5: Summary](/react-standalone-tutorial/5-summary)
|
||||
22
docs/shared/react-standalone-tutorial/5-summary.md
Normal file
22
docs/shared/react-standalone-tutorial/5-summary.md
Normal file
@ -0,0 +1,22 @@
|
||||
# React Standalone Tutorial - Part 5: Summary
|
||||
|
||||
In this tutorial you:
|
||||
|
||||
- Learned how to use Nx's Generators to generate code for your workspace.
|
||||
- Learned how Nx determines a graph of your workspace
|
||||
- Learned how to configure and run tasks in your workspace
|
||||
- Learned how Nx's built-in optimizations work, and how to apply those to your own workspace
|
||||
|
||||
## Learn More
|
||||
|
||||
{% cards %}
|
||||
|
||||
{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%}
|
||||
|
||||
{% card title="Plugin Features" description="Read about the plugin features of Nx." url="/plugin-features" /%}
|
||||
|
||||
{% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%}
|
||||
|
||||
{% card title="Adopting Nx" description="Learn how to add Nx to your existing repo." url="/recipes/adopting-nx" /%}
|
||||
|
||||
{% /cards %}
|
||||
20
docs/shared/react-standalone-tutorial/generator-syntax.svg
Normal file
20
docs/shared/react-standalone-tutorial/generator-syntax.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 89 KiB |
17
docs/shared/react-standalone-tutorial/run-target-syntax.svg
Normal file
17
docs/shared/react-standalone-tutorial/run-target-syntax.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 54 KiB |
Loading…
x
Reference in New Issue
Block a user