docs(core): node and react tutorial rework (#12498)
* docs(react): update react tutorial text * docs(react): fixes to computation cache lesson * docs(react): reworking react tutorial * docs(react): fixing broken links in tutorial * docs(react): fixing broken more links in tutorial * docs(react): fixing last broken link in tutorial * docs(react): really fixing last broken link in tutorial * fixing images in preview * docs(react): cleaning up text and formatting issues * docs(react): more fixes and cleanup * docs(react): more fixes * docs(react): fixing nx console broken links * docs(react): adjusting ending summary cards * docs(react): more typo fixes * docs(react): incorporating victor and isaac's feedback * docs(react): fixing broken link * docs(react): a self-round of typo and formatting fixes * docs(react): another round of formatting fixes * docs(react): another small change * docs(react): another typo fix * docs(react): more typo fixed noticed working with node tutorial * docs(react): making h1's consistent * docs(react): fixing tab title for part 1 * docs(react): fixing the title * docs(react): escaping colon in title * docs(node): copying react tutorials as starting point * docs(node): fixing map.json and links to other lessons * docs(node): updating the copy-pasted react tutorial for the node example * docs(node): more fixes after self-review * docs(node): fixing another typo * docs(node): Making h1's consistent * docs(node): fixing tab title in step 1 * docs(node): fixing the title * docs(node): escaping colon in title * docs(core): nx graph => project graph * docs(core): fixing titles * docs(core): further shortening the text * docs(core): formatting fixes * docs(core): responding to victor comments * docs(core): switching to new terminal code blocks * docs(core): light and dark mode friendly images
@ -11,7 +11,7 @@
|
||||
"name": "Overview",
|
||||
"path": "/packages/nest",
|
||||
"file": "shared/nest-plugin",
|
||||
"content": "Nest.js is a framework designed for building scalable server-side applications. In many ways, Nest is familiar to Angular developers:\n\n- It has excellent TypeScript support.\n- Its dependency injection system is similar to the one in Angular.\n- It emphasises testability.\n- Its configuration APIs are similar to Angular as well.\n\nMany conventions and best practices used in Angular applications can be also be used in Nest.\n\n## Setting Up Nest\n\nTo create a new workspace with Nest, run the following command:\n\n```shell\nnpx create-nx-workspace my-workspace --preset=nest\n```\n\nYarn users can use the following command instead:\n\n```shell\nyarn create nx-workspace my-workspace --preset=nest\n```\n\nTo add the Nest plugin to an existing workspace, run one the following commands:\n\n```shell\nnpm install -D @nrwl/nest\n```\n\n```shell\nyarn add -D @nrwl/nest\n```\n\n### Create Applications\n\nYou can add a new Nest application with the following command:\n\n```shell\nnx g @nrwl/nest:app my-nest-app\n```\n\n#### Application Proxies\n\nGenerating Nest applications has an option to configure other projects in the workspace to proxy API requests. This can be done by passing the `--frontendProject` with the project name you wish to enable proxy support for.\n\n```shell\nnx g @nrwl/nest:app my-nest-app --frontendProject my-angular-app\n```\n\n### Create Libraries\n\nYou can add a new Nest library with the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib\n```\n\nTo make the library `buildable`, use the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib --buildable\n```\n\nTo make the library `publishable`, use the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib --publishable --importPath=@my-workspace/my-nest-lib\n```\n\n> Read more about [building and publishing libraries here](/more-concepts/buildable-and-publishable-libraries).\n\n### Nest Generators\n\nThe Nest plugin for Nx extends the generators provided by Nest. Any commands that can be used with the Nest CLI can also be used with the `nx` command. The `--project` flag should be used for all Nest generators.\n\n> `--project` is used to infer the root of the project where the generators will generate the files.\n\n## Using Nest\n\n### Build\n\nYou can build an application with the following command:\n\n```shell\nnx build my-nest-app\n```\n\nThis applies to `buildable` libraries as well\n\n```shell\nnx build my-nest-lib\n```\n\n#### Waiting for other builds\n\nSetting the `waitUntilTargets` option with an array of projects (with the following format: `\"project:architect\"`) will execute those commands before serving the Nest application.\n\n### Serve\n\nYou can serve an application with the following command:\n\n```shell\nnx serve my-nest-app\n```\n\nThe `serve` command runs the `build` target, and executes the application.\n\nBy default, the serve command will run in `watch` mode. This allows code to be changed, and the Nest application to be rebuilt automatically.\n\n#### Debugging\n\nNest applications also have the `inspect` flag set, so you can attach your debugger to the running instance.\n\nDebugging is set to use a random port that is available on the system. The port can be changed by setting the port option in the `serve` target in the `project.json`. Or by running the serve command with `--port <number>`.\n\nFor additional information on how to debug Node applications, see the [Node.js debugging getting started guide](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients).\n\n### Lint\n\nYou can lint an application with the following command:\n\n```shell\nnx lint my-nest-app\n```\n\nYou can lint a library with the following command:\n\n```shell\nnx lint my-nest-lib\n```\n\n### Unit Test\n\nYou can run unit test for an application with the following command:\n\n```shell\nnx test my-nest-app\n```\n\nYou can run unit test for a library with the following command:\n\n```shell\nnx test my-nest-lib\n```\n\n## More Documentation\n\n- [Todo Tutorial](/node-tutorial/01-create-application)\n- [Using Jest](/packages/jest)\n"
|
||||
"content": "Nest.js is a framework designed for building scalable server-side applications. In many ways, Nest is familiar to Angular developers:\n\n- It has excellent TypeScript support.\n- Its dependency injection system is similar to the one in Angular.\n- It emphasises testability.\n- Its configuration APIs are similar to Angular as well.\n\nMany conventions and best practices used in Angular applications can be also be used in Nest.\n\n## Setting Up Nest\n\nTo create a new workspace with Nest, run the following command:\n\n```shell\nnpx create-nx-workspace my-workspace --preset=nest\n```\n\nYarn users can use the following command instead:\n\n```shell\nyarn create nx-workspace my-workspace --preset=nest\n```\n\nTo add the Nest plugin to an existing workspace, run one the following commands:\n\n```shell\nnpm install -D @nrwl/nest\n```\n\n```shell\nyarn add -D @nrwl/nest\n```\n\n### Create Applications\n\nYou can add a new Nest application with the following command:\n\n```shell\nnx g @nrwl/nest:app my-nest-app\n```\n\n#### Application Proxies\n\nGenerating Nest applications has an option to configure other projects in the workspace to proxy API requests. This can be done by passing the `--frontendProject` with the project name you wish to enable proxy support for.\n\n```shell\nnx g @nrwl/nest:app my-nest-app --frontendProject my-angular-app\n```\n\n### Create Libraries\n\nYou can add a new Nest library with the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib\n```\n\nTo make the library `buildable`, use the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib --buildable\n```\n\nTo make the library `publishable`, use the following command:\n\n```shell\nnx g @nrwl/nest:lib my-nest-lib --publishable --importPath=@my-workspace/my-nest-lib\n```\n\n> Read more about [building and publishing libraries here](/more-concepts/buildable-and-publishable-libraries).\n\n### Nest Generators\n\nThe Nest plugin for Nx extends the generators provided by Nest. Any commands that can be used with the Nest CLI can also be used with the `nx` command. The `--project` flag should be used for all Nest generators.\n\n> `--project` is used to infer the root of the project where the generators will generate the files.\n\n## Using Nest\n\n### Build\n\nYou can build an application with the following command:\n\n```shell\nnx build my-nest-app\n```\n\nThis applies to `buildable` libraries as well\n\n```shell\nnx build my-nest-lib\n```\n\n#### Waiting for other builds\n\nSetting the `waitUntilTargets` option with an array of projects (with the following format: `\"project:architect\"`) will execute those commands before serving the Nest application.\n\n### Serve\n\nYou can serve an application with the following command:\n\n```shell\nnx serve my-nest-app\n```\n\nThe `serve` command runs the `build` target, and executes the application.\n\nBy default, the serve command will run in `watch` mode. This allows code to be changed, and the Nest application to be rebuilt automatically.\n\n#### Debugging\n\nNest applications also have the `inspect` flag set, so you can attach your debugger to the running instance.\n\nDebugging is set to use a random port that is available on the system. The port can be changed by setting the port option in the `serve` target in the `project.json`. Or by running the serve command with `--port <number>`.\n\nFor additional information on how to debug Node applications, see the [Node.js debugging getting started guide](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients).\n\n### Lint\n\nYou can lint an application with the following command:\n\n```shell\nnx lint my-nest-app\n```\n\nYou can lint a library with the following command:\n\n```shell\nnx lint my-nest-lib\n```\n\n### Unit Test\n\nYou can run unit test for an application with the following command:\n\n```shell\nnx test my-nest-app\n```\n\nYou can run unit test for a library with the following command:\n\n```shell\nnx test my-nest-lib\n```\n\n## More Documentation\n\n- [Using Jest](/packages/jest)\n"
|
||||
}
|
||||
],
|
||||
"generators": [
|
||||
|
||||
116
docs/map.json
@ -27,7 +27,7 @@
|
||||
{
|
||||
"name": "React Tutorial",
|
||||
"id": "react-tutorial",
|
||||
"file": "shared/react-tutorial/01-create-application"
|
||||
"file": "shared/react-tutorial/1-code-generation"
|
||||
},
|
||||
{
|
||||
"name": "Angular Tutorial",
|
||||
@ -37,7 +37,7 @@
|
||||
{
|
||||
"name": "Node Tutorial",
|
||||
"id": "node-tutorial",
|
||||
"file": "shared/node-tutorial/01-create-application"
|
||||
"file": "shared/node-tutorial/1-code-generation"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -81,67 +81,32 @@
|
||||
{
|
||||
"name": "React Tutorial",
|
||||
"id": "react-tutorial",
|
||||
"description": "Learn to use Nx with this React tutorial where you will learn about all its main feature with a real project.",
|
||||
"description": "In this tutorial you'll create a frontend-focused workspace with Nx.",
|
||||
"itemList": [
|
||||
{
|
||||
"name": "1 - Create Application",
|
||||
"id": "01-create-application",
|
||||
"file": "shared/react-tutorial/01-create-application"
|
||||
"name": "1 - Code Generation",
|
||||
"id": "1-code-generation",
|
||||
"file": "shared/react-tutorial/1-code-generation"
|
||||
},
|
||||
{
|
||||
"name": "2 - Add E2E Test",
|
||||
"id": "02-add-e2e-test",
|
||||
"file": "shared/react-tutorial/02-add-e2e-test"
|
||||
"name": "2 - Project Graph",
|
||||
"id": "2-project-graph",
|
||||
"file": "shared/react-tutorial/2-project-graph"
|
||||
},
|
||||
{
|
||||
"name": "3 - Display Todos",
|
||||
"id": "03-display-todos",
|
||||
"file": "shared/react-tutorial/03-display-todos"
|
||||
"name": "3 - Task Running",
|
||||
"id": "3-task-running",
|
||||
"file": "shared/react-tutorial/3-task-running"
|
||||
},
|
||||
{
|
||||
"name": "4 - Connect to API",
|
||||
"id": "04-connect-to-api",
|
||||
"file": "shared/react-tutorial/04-connect-to-api"
|
||||
"name": "4 - Workspace Optimization",
|
||||
"id": "4-workspace-optimization",
|
||||
"file": "shared/react-tutorial/4-workspace-optimization"
|
||||
},
|
||||
{
|
||||
"name": "5 - Add Node Application",
|
||||
"id": "05-add-node-app",
|
||||
"file": "shared/react-tutorial/05-add-node-app"
|
||||
},
|
||||
{
|
||||
"name": "6 - Proxy Configuration",
|
||||
"id": "06-proxy",
|
||||
"file": "shared/react-tutorial/06-proxy"
|
||||
},
|
||||
{
|
||||
"name": "7 - Share Code",
|
||||
"id": "07-share-code",
|
||||
"file": "shared/react-tutorial/07-share-code"
|
||||
},
|
||||
{
|
||||
"name": "8 - Create Libraries",
|
||||
"id": "08-create-libs",
|
||||
"file": "shared/react-tutorial/08-create-libs"
|
||||
},
|
||||
{
|
||||
"name": "9 - Project Graph",
|
||||
"id": "09-dep-graph",
|
||||
"file": "shared/react-tutorial/09-dep-graph"
|
||||
},
|
||||
{
|
||||
"name": "10 - Use Computation Caching",
|
||||
"id": "10-computation-caching",
|
||||
"file": "shared/react-tutorial/10-computation-caching"
|
||||
},
|
||||
{
|
||||
"name": "11 - Test Affected Projects",
|
||||
"id": "11-test-affected-projects",
|
||||
"file": "shared/react-tutorial/11-test-affected-projects"
|
||||
},
|
||||
{
|
||||
"name": "12 - Summary",
|
||||
"id": "12-summary",
|
||||
"file": "shared/react-tutorial/12-summary"
|
||||
"name": "5 - Summary",
|
||||
"id": "5-summary",
|
||||
"file": "shared/react-tutorial/5-summary"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -218,44 +183,29 @@
|
||||
"description": "Learn to use Nx with this Node tutorial where you will learn about all its main feature with a real project.",
|
||||
"itemList": [
|
||||
{
|
||||
"name": "1 - Create Application",
|
||||
"id": "01-create-application",
|
||||
"file": "shared/node-tutorial/01-create-application"
|
||||
"name": "1 - Code Generation",
|
||||
"id": "1-code-generation",
|
||||
"file": "shared/node-tutorial/1-code-generation"
|
||||
},
|
||||
{
|
||||
"name": "2 - Display Todos",
|
||||
"id": "02-display-todos",
|
||||
"file": "shared/node-tutorial/02-display-todos"
|
||||
"name": "2 - Project Graph",
|
||||
"id": "2-project-graph",
|
||||
"file": "shared/node-tutorial/2-project-graph"
|
||||
},
|
||||
{
|
||||
"name": "3 - Share Code",
|
||||
"id": "03-share-code",
|
||||
"file": "shared/node-tutorial/03-share-code"
|
||||
"name": "3 - Task Running",
|
||||
"id": "3-task-running",
|
||||
"file": "shared/node-tutorial/3-task-running"
|
||||
},
|
||||
{
|
||||
"name": "4 - Create Libraries",
|
||||
"id": "04-create-libs",
|
||||
"file": "shared/node-tutorial/04-create-libs"
|
||||
"name": "4 - Workspace Optimization",
|
||||
"id": "4-workspace-optimization",
|
||||
"file": "shared/node-tutorial/4-workspace-optimization"
|
||||
},
|
||||
{
|
||||
"name": "5 - Project Graph",
|
||||
"id": "05-dep-graph",
|
||||
"file": "shared/node-tutorial/05-dep-graph"
|
||||
},
|
||||
{
|
||||
"name": "6 - Use Computation Caching",
|
||||
"id": "06-computation-caching",
|
||||
"file": "shared/node-tutorial/06-computation-caching"
|
||||
},
|
||||
{
|
||||
"name": "7 - Test Affected Projects",
|
||||
"id": "07-test-affected-projects",
|
||||
"file": "shared/node-tutorial/07-test-affected-projects"
|
||||
},
|
||||
{
|
||||
"name": "8 - Summary",
|
||||
"id": "08-summary",
|
||||
"file": "shared/node-tutorial/08-summary"
|
||||
"name": "5 - Summary",
|
||||
"id": "5-summary",
|
||||
"file": "shared/node-tutorial/5-summary"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -145,5 +145,4 @@ nx test my-nest-lib
|
||||
|
||||
## More Documentation
|
||||
|
||||
- [Todo Tutorial](/node-tutorial/01-create-application)
|
||||
- [Using Jest](/packages/jest)
|
||||
|
||||
@ -1,161 +0,0 @@
|
||||
# Node Nx Tutorial - Step 1: Create Application
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/UcBSBQYNlhE"
|
||||
title="Nx.dev Tutorial | Node | Step 1: Create Application"
|
||||
width="100%" /%}
|
||||
|
||||
In this tutorial you use Nx to build a server application out of common libraries using modern technologies.
|
||||
|
||||
{% callout type="check" title="Integrated Repo" %}
|
||||
This tutorial sets up an [integrated repo](/concepts/integrated-vs-package-based). If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Package-Based Repo Tutorial](/getting-started/package-based-repo-tutorial).
|
||||
{% /callout %}
|
||||
|
||||
## Contents
|
||||
|
||||
- [1 - Create Application](/node-tutorial/01-create-application)
|
||||
- [2 - Display Todos](/node-tutorial/02-display-todos)
|
||||
- [3 - Share Code](/node-tutorial/03-share-code)
|
||||
- [4 - Create Libraries](/node-tutorial/04-create-libs)
|
||||
- [5 - Project Graph](/node-tutorial/05-dep-graph)
|
||||
- [6 - Use Computation Caching](/node-tutorial/06-computation-caching)
|
||||
- [7 - Test Affected Projects](/node-tutorial/07-test-affected-projects)
|
||||
- [8 - Summary](/node-tutorial/08-summary)
|
||||
|
||||
## Create a New Workspace
|
||||
|
||||
**Start by creating a new workspace.**
|
||||
|
||||
```shell
|
||||
npx create-nx-workspace@latest
|
||||
```
|
||||
|
||||
You then receive the following prompts in your command line:
|
||||
|
||||
```shell
|
||||
Workspace name (e.g., org name) myorg
|
||||
What to create in the new workspace nest
|
||||
Application name todos
|
||||
```
|
||||
|
||||
> You can also choose to add [Nx Cloud](https://nx.app), but its not required for the tutorial.
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── README.md
|
||||
├── apps/
|
||||
│ └── todos/
|
||||
│ ├── jest.config.ts
|
||||
│ ├── src/
|
||||
│ │ ├── app/
|
||||
│ │ │ ├── app.controller.spec.ts
|
||||
│ │ │ ├── app.controller.ts
|
||||
│ │ │ ├── app.module.ts
|
||||
│ │ │ ├── app.service.spec.ts
|
||||
│ │ │ └── app.service.ts
|
||||
│ │ ├── assets/
|
||||
│ │ ├── environments/
|
||||
│ │ │ ├── environment.prod.ts
|
||||
│ │ │ └── environment.ts
|
||||
│ │ └── main.ts
|
||||
│ ├── tsconfig.app.json
|
||||
│ ├── tsconfig.json
|
||||
│ └── tsconfig.spec.json
|
||||
├── libs/
|
||||
├── tools/
|
||||
├── .eslintrc.json
|
||||
├── .prettierrc
|
||||
├── jest.config.ts
|
||||
├── jest.preset.js
|
||||
├── nx.json
|
||||
├── package.json
|
||||
├── README.md
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
The generate command added one project to our workspace:
|
||||
|
||||
- A Nest application
|
||||
|
||||
## Note on the Nx CLI
|
||||
|
||||
Depending on how your dev env is set up, the command above might result in `Command 'nx' not found`.
|
||||
|
||||
To fix it, you can either install the `nx` cli globally by running:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn global add nx
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npm install -g nx
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
Or you can prepend every command with `npm run`:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn nx serve todos
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npx nx serve todos
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
## Project.json, Targets, Executors
|
||||
|
||||
You configure your projects in `project.json` files. These files contains the workspace projects with their command targets. For instance, `todos` has the `build`, `serve`, `lint`, and `test` targets. This means that you can run `nx build todos`, `nx serve todos`, etc..
|
||||
|
||||
Every target uses an executor which actually runs this target. So targets are analogous to typed npm scripts, and executors are analogous to typed shell scripts.
|
||||
|
||||
**Why not use shell scripts and npm scripts directly?**
|
||||
|
||||
There are a lot of advantages to providing additional metadata to the build tool. For instance, you can introspect targets. `nx serve todos --help` results in:
|
||||
|
||||
```shell
|
||||
nx run todos:serve [options,...]
|
||||
|
||||
Options:
|
||||
--buildTarget The target to run to build you the app
|
||||
--waitUntilTargets The targets to run to before starting the node app (default: )
|
||||
--host The host to inspect the process on (default: localhost)
|
||||
--port The port to inspect the process on. Setting port to 0 will assign random free ports to all forked processes.
|
||||
--watch Run build when files change (default: true)
|
||||
--inspect Ensures the app is starting with debugging (default: inspect)
|
||||
--runtimeArgs Extra args passed to the node process (default: )
|
||||
--args Extra args when starting the app (default: )
|
||||
--help Show available options for project target.
|
||||
```
|
||||
|
||||
It helps with good editor integration (see [VSCode Support](/core-features/integrate-with-editors#nx-console-for-vscode)).
|
||||
|
||||
But, most importantly, it provides a holistic dev experience regardless of the tools used, and enables advanced build features like distributed computation caching and distributed builds).
|
||||
|
||||
## Serve the newly created application
|
||||
|
||||
Now that the application is set up, run it locally via:
|
||||
|
||||
```shell
|
||||
nx serve todos
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 2: Display todos](/node-tutorial/02-display-todos)
|
||||
@ -1,167 +0,0 @@
|
||||
# Node Nx Tutorial - Step 2: Display todos
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/I4-sO2LeVbU"
|
||||
title="Nx.dev Tutorial | Node | Step 2: Display Todos"
|
||||
width="100%" /%}
|
||||
|
||||
Great! you now have a server application set up to show some data when going to the `/api` route.
|
||||
|
||||
Next, you're going to add a new service, and set up some server side templates.
|
||||
|
||||
## Creating a todos service
|
||||
|
||||
With Nx, you have the ability to scaffold out new code for your application. Create a Todos service and populate some todos!
|
||||
|
||||
**Run `nx generate @nrwl/nest:service todo --project todos --directory app` to generate our new service**
|
||||
|
||||
```shell
|
||||
$ nx generate @nrwl/nest:service todos --project todos --directory app
|
||||
CREATE apps/todos/src/app/todos/todos.service.spec.ts (453 bytes)
|
||||
CREATE apps/todos/src/app/todos/todos.service.ts (89 bytes)
|
||||
UPDATE apps/todos/src/app/app.module.ts (318 bytes)
|
||||
```
|
||||
|
||||
{% callout type="check" title="Get more info on plugins" %}
|
||||
Services are not the only things that the `@nrwl/nest` plugin can create. Run `nx list @nrwl/nest` to see other capabilities that the plugin provides.
|
||||
{% /callout %}
|
||||
|
||||
Open the newly created file in `apps/todos/src/app/todos/todos.service.ts` and paste the following code:
|
||||
|
||||
```typescript
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
export type Todo = {
|
||||
message: string;
|
||||
done: boolean;
|
||||
};
|
||||
|
||||
const todos: Todo[] = [
|
||||
{ message: 'Take out trash', done: false },
|
||||
{ message: 'Continue using Nx', done: false },
|
||||
];
|
||||
|
||||
@Injectable()
|
||||
export class TodosService {
|
||||
getTodos(): Todo[] {
|
||||
return todos;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% callout type="note" title="We keep things simple here" %}
|
||||
Usually services should call some kind of data source (like a database or even a file) but for this tutorial, just populate todos manually.
|
||||
{% /callout %}
|
||||
|
||||
You now have your Todos service ready!
|
||||
|
||||
## Install template engine
|
||||
|
||||
In order to render some views, you need to install a template engine:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn add hbs
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npm install --save hbs
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
Once the installation process is complete, you need to configure the `main.ts` file with the following code:
|
||||
|
||||
```typescript
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
import { NestExpressApplication } from '@nestjs/platform-express';
|
||||
import { join } from 'path';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestExpressApplication>(AppModule);
|
||||
|
||||
app.setBaseViewsDir(join(__dirname, 'assets', 'views'));
|
||||
app.setViewEngine('hbs');
|
||||
|
||||
const port = process.env.PORT || 3333;
|
||||
await app.listen(port, () => {
|
||||
Logger.log('Listening at http://localhost:' + port);
|
||||
});
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
```
|
||||
|
||||
You added configuration for setting up the view engine, and removed the `globalPrefix` option.
|
||||
|
||||
## Template rendering
|
||||
|
||||
Under the `assets` directory of the todo's project, you create a `views` directory with an `index.hbs` file inside with the following content:
|
||||
|
||||
```handlebars
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>App</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul class="todos">
|
||||
{{#each todos}}
|
||||
<li><input type="checkbox" {{#if done}}checked{{/if}} /> {{message}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Next, update the `app.controller.ts` file with the following:
|
||||
|
||||
```typescript
|
||||
import { Controller, Get, Render } from '@nestjs/common';
|
||||
|
||||
import { AppService } from './app.service';
|
||||
import { TodosService } from './todos/todos.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(
|
||||
private readonly appService: AppService,
|
||||
private todosService: TodosService
|
||||
) {}
|
||||
|
||||
@Get('api')
|
||||
getData() {
|
||||
return this.todosService.getTodos();
|
||||
}
|
||||
|
||||
@Get()
|
||||
@Render('index')
|
||||
root() {
|
||||
return {
|
||||
todos: this.getData(),
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You changed the `@Get` decorator for the `getData` function to point to the `api` route. You also changed this to call the `todosService.getTodos()` method. \
|
||||
Then you added the `root` function which renders the `index` file from our `views` directory.
|
||||
|
||||
{% callout type="note" title="Serve is running" %}
|
||||
The serve process should still be running. If it isn't, restart the process with `nx serve todos`
|
||||
{% /callout %}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 3: Share code](/node-tutorial/03-share-code)
|
||||
@ -1,80 +0,0 @@
|
||||
# Node Nx Tutorial - Step 3: Share Code
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/MqqwOoKa-Ho"
|
||||
title="Nx.dev Tutorial | Node | Step 3: Share Code"
|
||||
width="100%" /%}
|
||||
|
||||
Awesome! The application is working as expected!
|
||||
|
||||
Next, work on refactoring a bit. The next work to do is move the `Todo` type to it's own library. This is important when you want to share the type between multiple applications, without having to duplicate the same type everywhere.
|
||||
|
||||
**Run the following generator to create a library:**
|
||||
|
||||
```shell
|
||||
nx g @nrwl/workspace:lib data
|
||||
```
|
||||
|
||||
The result should look like this:
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ └── todos/
|
||||
├── libs/
|
||||
│ └── data/
|
||||
│ ├── src/
|
||||
│ │ ├── lib/
|
||||
│ │ │ └── data.ts
|
||||
│ │ └── index.ts
|
||||
│ ├── jest.config.js
|
||||
│ ├── tsconfig.lib.json
|
||||
│ ├── tsconfig.json
|
||||
│ └── tsconfig.spec.json
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
**Copy the type into `libs/data/src/lib/data.ts`.**
|
||||
|
||||
```typescript
|
||||
export type Todo = {
|
||||
message: string;
|
||||
done: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
### A note about VS Code :
|
||||
|
||||
If you're using [VS Code](https://code.visualstudio.com/) it may be necessary at this point to restart the TS server so that the new `@myorg/data` package is recognised. This needs to be done **every time a new workspace library is added**.
|
||||
|
||||
Use the command palette with a `*.ts` file open and choose `Restart TS Server`.
|
||||
|
||||
## Refactor the todos service
|
||||
|
||||
**Now update `apps/todos/src/app/todos/todos.service.ts` to import the type:**
|
||||
|
||||
```typescript
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Todo } from '@myorg/data';
|
||||
|
||||
const todos: Todo[] = [
|
||||
{ message: 'Take out trash', done: false },
|
||||
{ message: 'Continue using Nx', done: false },
|
||||
];
|
||||
|
||||
@Injectable()
|
||||
export class TodosService {
|
||||
getTodos(): Todo[] {
|
||||
return todos;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Every time you add a new library, you have to restart `nx serve`. **So restart `nx serve todos` and you should see the application running.**
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 4: Create libraries](/node-tutorial/04-create-libs)
|
||||
@ -1,97 +0,0 @@
|
||||
# Node Nx Tutorial - Step 4: Create Libraries
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/V29I_DHGlB8"
|
||||
title="Nx.dev Tutorial | Node | Step 4: Create Libraries"
|
||||
width="100%" /%}
|
||||
|
||||
Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API.
|
||||
|
||||
## Public API
|
||||
|
||||
Every library has an `index.ts` file, which defines its public API. Other applications and libraries should only access what the `index.ts` exports. Everything else in the library is private.
|
||||
|
||||
## Controller libraries
|
||||
|
||||
To illustrate how useful libraries can be, create a new Auth library with a controller.
|
||||
|
||||
Run
|
||||
|
||||
```shell
|
||||
nx g @nrwl/nest:lib auth --controller
|
||||
```
|
||||
|
||||
{% callout type="note" title="--controller" %}
|
||||
We added the `--controller` flag here to generate a controller along with the library scaffolding.
|
||||
{% /callout %}
|
||||
|
||||
You should see the following:
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ └── todos/
|
||||
├── libs/
|
||||
│ ├── auth/
|
||||
│ │ ├── jest.config.ts
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── index.ts
|
||||
│ │ │ └── lib/
|
||||
│ │ │ ├── auth.controller.spec.ts
|
||||
│ │ │ ├── auth.controller.ts
|
||||
│ │ │ └── auth.module.ts
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ ├── tsconfig.lib.json
|
||||
│ │ └── tsconfig.spec.json
|
||||
│ └── data/
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
Modify the `libs/auth/src/lib/auth.controller.ts` file like this:
|
||||
|
||||
```typescript
|
||||
import { Controller, Get } from '@nestjs/common';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
@Get()
|
||||
auth() {
|
||||
return {
|
||||
authenticated: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
{% callout type="note" title="We keep things simple here" %}
|
||||
In code destined for production, you would actually have a proper authentication check here.
|
||||
{% /callout %}
|
||||
|
||||
## Use the new library
|
||||
|
||||
**Now import `AuthModule` into `apps/todos/src/app/app.module.ts`.**
|
||||
|
||||
```typescript
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
import { TodosService } from './todos/todos.service';
|
||||
import { AuthModule } from '@myorg/auth';
|
||||
|
||||
@Module({
|
||||
imports: [AuthModule],
|
||||
controllers: [AppController],
|
||||
providers: [AppService, TodosService],
|
||||
})
|
||||
export class AppModule {}
|
||||
```
|
||||
|
||||
Restart `nx serve todos` then go to http://localhost:3333/auth. You should see `{ authenticated: true }`.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 5: Dep graph](/node-tutorial/05-dep-graph)
|
||||
@ -1,16 +0,0 @@
|
||||
# Node Nx Tutorial - Step 5: Project Graph
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/l9MjZ9IPdu4"
|
||||
title="Nx.dev Tutorial | Node | Step 5: Dep Graph"
|
||||
width="100%" /%}
|
||||
|
||||
An Nx workspace can contain dozens or hundreds of applications and libraries. As a codebase grows, it becomes more difficult to understand how they depend on each other and the implications of making a particular change.
|
||||
|
||||
Previously, some senior architect would create an ad-hoc dependency diagram and upload it to a corporate wiki. The diagram is not correct even on Day 1 and gets more and more out of sync with every passing day.
|
||||
|
||||
With Nx, you can do better than that.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 6: Computation Caching](/node-tutorial/06-computation-caching)
|
||||
@ -1,41 +0,0 @@
|
||||
# Node Nx Tutorial - Step 6: Computation Caching
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/gXChzhI1Qpg"
|
||||
title="Nx.dev Tutorial | Node | Step 6: Computation Caching"
|
||||
width="100%" /%}
|
||||
|
||||
Nx has built-in computation caching, which drastically improves the performance of the commands.
|
||||
|
||||
**To see it in action, run `nx build todos`:**
|
||||
|
||||
```shell
|
||||
> nx run todos:build
|
||||
Starting type checking service...
|
||||
Using 14 workers with 2048MB memory limit
|
||||
Hash: 51f23143c450a9f931a7
|
||||
Built at: 09/04/2020 4:03:20 PM
|
||||
Entrypoint main = main.js main.js.map
|
||||
chunk {main} main.js, main.js.map (main) 4.17 KiB [entry] [rendered]
|
||||
```
|
||||
|
||||
**Now, run `nx build todos` again, and you will see the results appearing instantly:**
|
||||
|
||||
```shell
|
||||
> nx run todos:build
|
||||
|
||||
> NX NOTE Cached Output:
|
||||
|
||||
Starting type checking service...
|
||||
Using 14 workers with 2048MB memory limit
|
||||
Hash: 51f23143c450a9f931a7
|
||||
Built at: 09/04/2020 4:03:20 PM
|
||||
Entrypoint main = main.js main.js.map
|
||||
chunk {main} main.js, main.js.map (main) 4.17 KiB [entry] [rendered]
|
||||
```
|
||||
|
||||
Based on the state of the source code and the environment, Nx was able to figure out that it had already run this exact command. Nx found the artifact in the local cache and replayed the output and restored the necessary files.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 7: Test affected projects](/node-tutorial/07-test-affected-projects)
|
||||
@ -1,80 +0,0 @@
|
||||
# Node Nx Tutorial - Step 7: Test Affected Projects
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/TRRVLyHfN60"
|
||||
title="Nx.dev Tutorial | Node | Step 7: Test Affected Projects"
|
||||
width="100%" /%}
|
||||
|
||||
In addition to supporting computation caching, Nx scales your development by doing code change analysis to see what apps or libraries are affected by a particular pull request.
|
||||
|
||||
**Commit all the changes in the repo**:
|
||||
|
||||
```shell
|
||||
git add .
|
||||
git commit -am 'init'
|
||||
git checkout -b testbranch
|
||||
```
|
||||
|
||||
**Open `libs/auth/src/lib/auth.controller.ts` and change the controller:**
|
||||
|
||||
```typescript
|
||||
import { Body, Controller, Get, Post } from '@nestjs/common';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
@Get()
|
||||
auth() {
|
||||
return {
|
||||
authenticated: true,
|
||||
};
|
||||
}
|
||||
|
||||
@Post()
|
||||
authenticate(@Body() postData: { username: string; password: string }) {
|
||||
const { username, password } = postData;
|
||||
// check the database
|
||||
console.log(username, password);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Run `nx affected:apps`**, and you should see `todos` printed out. The `affected:apps` looks at what you have changed and uses the project graph to figure out which apps are affected by this change.
|
||||
|
||||
**Run `nx affected:libs`**, and you should see `auth` printed out. This command works similarly, but instead of printing the affected apps, it prints the affected libs.
|
||||
|
||||
## Test Affected Projects
|
||||
|
||||
Printing the affected projects can be handy, but usually you want to do something with them. For instance, you may want to test everything that has been affected.
|
||||
|
||||
**Run `nx affected:test` to retest only the projects affected by the change.**
|
||||
|
||||
As you can see, because the code was updated without updating the tests, the unit tests failed.
|
||||
|
||||
```shell
|
||||
> NX Running target test for projects:
|
||||
|
||||
- auth
|
||||
- todos
|
||||
|
||||
...
|
||||
|
||||
Failed projects:
|
||||
|
||||
- todos
|
||||
```
|
||||
|
||||
Note that Nx only tried to retest `auth` and `todos`. It didn't retest `data` because there is no way that library could be affected by the changes in this branch.
|
||||
|
||||
## Affected:\*
|
||||
|
||||
You can run any target against the affected projects in the graph like this:
|
||||
|
||||
```shell
|
||||
# The following are equivalent
|
||||
nx affected --target=build
|
||||
nx affected:build
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 8: Summary](/node-tutorial/08-summary)
|
||||
@ -1,17 +0,0 @@
|
||||
# Node Nx Tutorial - Step 8: Summary
|
||||
|
||||
In this tutorial you:
|
||||
|
||||
- Built a full Node application with an API and server side rendered pages
|
||||
- Shared code
|
||||
- Created a controller library
|
||||
- Used Nx affected commands to only retest and rebuild what is affected
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Free Nx Course on YouTube](https://www.youtube.com/playlist?list=PLakNactNC1dH38AfqmwabvOszDmKriGco)
|
||||
|
||||
**Dive Deep:**
|
||||
|
||||
- [Computation Caching](/concepts/how-caching-works)
|
||||
- [Rebuilding What is Affected](/concepts/affected)
|
||||
99
docs/shared/node-tutorial/1-code-generation.md
Normal file
@ -0,0 +1,99 @@
|
||||
---
|
||||
title: 'Node Tutorial - Part 1: Code Generation'
|
||||
description: In this tutorial you'll create a backend-focused workspace with Nx.
|
||||
---
|
||||
|
||||
{% callout type="check" title="Two Styles of Repo" %}
|
||||
There are two styles of repos: integrated and package-based. This tutorial shows the integrated style.
|
||||
|
||||
You can find more information on the difference between the two in [our introduction](/getting-started/intro).
|
||||
{% /callout %}
|
||||
|
||||
# Node Tutorial - Part 1: Code Generation
|
||||
|
||||
In this tutorial you'll create a backend-focused workspace with Nx.
|
||||
|
||||
## Contents
|
||||
|
||||
- [1 - Code Generation](/node-tutorial/1-code-generation)
|
||||
- [2 - Project Graph](/node-tutorial/2-project-graph)
|
||||
- [3 - Task Running](/node-tutorial/3-task-running)
|
||||
- [4 - Workspace Optimization](/node-tutorial/4-workspace-optimization)
|
||||
- [5 - Summary](/node-tutorial/5-summary)
|
||||
|
||||
## Your Objective
|
||||
|
||||
For this tutorial, you'll create an Express API application, a CLI (command-line interface) application, and a library for a data client that these two applications will use to interact with a data-source.
|
||||
|
||||

|
||||
|
||||
## Creating an Nx Workspace
|
||||
|
||||
Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses:
|
||||
|
||||
```{% command="npx create-nx-workspace@latest" path="~" %}
|
||||
✔ Choose your style · integrated
|
||||
✔ What to create in the new workspace · express
|
||||
✔ Repository name · my-products
|
||||
✔ Application name · products-api
|
||||
✔ 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 complete, you can find your Express API application in `apps/products-api`.
|
||||
|
||||
## Adding Another Application to Your Workspace
|
||||
|
||||
Run this command to create your `products-cli` app:
|
||||
|
||||
```{% command="npx nx g @nrwl/node:app products-cli" path="~/my-products" %}
|
||||
|
||||
> NX Generating @nrwl/node:application
|
||||
|
||||
CREATE apps/products-cli/src/app/.gitkeep
|
||||
CREATE apps/products-cli/src/assets/.gitkeep
|
||||
CREATE apps/products-cli/src/environments/environment.prod.ts
|
||||
CREATE apps/products-cli/src/environments/environment.ts
|
||||
CREATE apps/products-cli/src/main.ts
|
||||
CREATE apps/products-cli/tsconfig.app.json
|
||||
CREATE apps/products-cli/tsconfig.json
|
||||
CREATE apps/products-cli/project.json
|
||||
CREATE apps/products-cli/.eslintrc.json
|
||||
CREATE apps/products-cli/jest.config.ts
|
||||
CREATE apps/products-cli/tsconfig.spec.json
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Generating Libraries
|
||||
|
||||
To create the `products-data-client` library, use the `@nrwl/js:lib` generator:
|
||||
|
||||
```{% command="npx nx g @nrwl/js:lib products-data-client" path="~/my-products" %}
|
||||
|
||||
> NX Generating @nrwl/js:library
|
||||
|
||||
CREATE libs/products-data-client/README.md
|
||||
CREATE libs/products-data-client/package.json
|
||||
CREATE libs/products-data-client/src/index.ts
|
||||
CREATE libs/products-data-client/src/lib/products-data-client.spec.ts
|
||||
CREATE libs/products-data-client/src/lib/products-data-client.ts
|
||||
CREATE libs/products-data-client/tsconfig.json
|
||||
CREATE libs/products-data-client/tsconfig.lib.json
|
||||
CREATE libs/products-data-client/project.json
|
||||
UPDATE tsconfig.base.json
|
||||
CREATE libs/products-data-client/.eslintrc.json
|
||||
CREATE libs/products-data-client/jest.config.ts
|
||||
CREATE libs/products-data-client/tsconfig.spec.json
|
||||
```
|
||||
|
||||
You have now created all three projects from the design:
|
||||
|
||||
- `products-api` in `apps/products-api`
|
||||
- `products-cli` in `apps/products-cli`
|
||||
- `products-data-client` in `libs/products-data-client`
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [2: Project Graph](/node-tutorial/2-project-graph)
|
||||
127
docs/shared/node-tutorial/2-project-graph.md
Normal file
@ -0,0 +1,127 @@
|
||||
# Node Tutorial - Part 2: Project Graph
|
||||
|
||||
Run the command: `npx nx graph`. A browser should open up with the following contents:
|
||||
|
||||

|
||||
|
||||
This is still different from the design from the start of Part 1:
|
||||
|
||||

|
||||
|
||||
The Project Graph is derived from the source code of your workspace. Make the following adjustments to your existing projects, so that our Project Graph will match the design:
|
||||
|
||||
### `products-data-client`
|
||||
|
||||
Update the contents of the generated `products-data-client.ts` file:
|
||||
|
||||
```typescript {% fileName="libs/products-data-client/src/lib/products-data-client.ts" %}
|
||||
export interface Product {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
export interface ProductsDataClient {
|
||||
getProducts(): Promise<Product[]>;
|
||||
getProductById(id: string): Promise<Product | undefined>;
|
||||
}
|
||||
|
||||
export const exampleProducts: Record<string, Product> = {
|
||||
'1': { id: '1', name: 'Product 1', price: 100 },
|
||||
'2': { id: '2', name: 'Product 2', price: 200 },
|
||||
};
|
||||
|
||||
export function createProductsDataClient(): ProductsDataClient {
|
||||
return {
|
||||
getProducts() {
|
||||
return Promise.resolve(Object.values(exampleProducts));
|
||||
},
|
||||
getProductById(id) {
|
||||
return Promise.resolve(exampleProducts[id]);
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### `products-cli`
|
||||
|
||||
Update the generated `main.ts` file of this project to import the `createProductsDataClient()` function.
|
||||
|
||||
Use the data client to print the product matching the id provided at the command-line. If no id was provided, print all products as an array:
|
||||
|
||||
```typescript {% fileName="apps/products-cli/src/main.ts" %}
|
||||
import { createProductsDataClient } from '@my-products/products-data-client';
|
||||
|
||||
main();
|
||||
|
||||
async function main() {
|
||||
const productsDataClient = createProductsDataClient();
|
||||
const id = getProvidedId();
|
||||
if (id != null) {
|
||||
const product = await productsDataClient.getProductById(id);
|
||||
console.log(JSON.stringify(product, null, 2));
|
||||
} else {
|
||||
const products = await productsDataClient.getProducts();
|
||||
console.log(JSON.stringify(products, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
function getProvidedId() {
|
||||
return process.argv[2];
|
||||
}
|
||||
```
|
||||
|
||||
### `products-api`
|
||||
|
||||
Update the generated `main.ts` file of this project to also import the `createProductsDataClient()` function.
|
||||
|
||||
Use the data client and Express to create an Express app with 2 GET request handlers:
|
||||
|
||||
```javascript {% fileName="apps/products-api/src/main.ts" %}
|
||||
/**
|
||||
* This is not a production server yet!
|
||||
* This is only a minimal backend to get started.
|
||||
*/
|
||||
import * as express from 'express';
|
||||
import { createProductsDataClient } from '@my-products/products-data-client';
|
||||
|
||||
const app = express();
|
||||
const productsDataClient = createProductsDataClient();
|
||||
|
||||
app.get('/products', async (_req, res) => {
|
||||
const products = await productsDataClient.getProducts();
|
||||
res.send(products);
|
||||
});
|
||||
|
||||
app.get('/products/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
const product = await productsDataClient.getProductById(id);
|
||||
if (product == null) {
|
||||
res.status(404).send();
|
||||
return;
|
||||
}
|
||||
res.send(product);
|
||||
});
|
||||
|
||||
const port = process.env.port || 3333;
|
||||
const server = app.listen(port, () => {
|
||||
console.log(`Listening at http://localhost:${port}`);
|
||||
});
|
||||
server.on('error', console.error);
|
||||
```
|
||||
|
||||
Now run `npx nx graph` again:
|
||||
|
||||
{% side-by-side %}
|
||||

|
||||
|
||||

|
||||
{% /side-by-side %}
|
||||
|
||||
Your graph now matches the original design.
|
||||
|
||||
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: Workspace Optimization](/node-tutorial/4-workspace-optimization).
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [3: Task Running](/node-tutorial/3-task-running)
|
||||
145
docs/shared/node-tutorial/3-task-running.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Node Tutorial - Part 3: Task-Running
|
||||
|
||||
Common tasks include:
|
||||
|
||||
- Building an application
|
||||
- Serving an application locally for development purposes
|
||||
- Running your unit tests
|
||||
- Linting your code
|
||||
|
||||
When you ran your generators in Part 1, you already set up these more common tasks for each project.
|
||||
|
||||
## Defining Targets
|
||||
|
||||
Here's the `project.json` file for your `products-data-client` project:
|
||||
|
||||
```json {% fileName="libs/products-data-client/project.json" %}
|
||||
{
|
||||
"name": "products-data-client",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/products-data-client/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/products-data-client",
|
||||
"main": "libs/products-data-client/src/index.ts",
|
||||
"tsConfig": "libs/products-data-client/tsconfig.lib.json",
|
||||
"assets": ["libs/products-data-client/*.md"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/products-data-client/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/libs/products-data-client"],
|
||||
"options": {
|
||||
"jestConfig": "libs/products-data-client/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
```
|
||||
|
||||
You can see that three targets are defined here: `build`, `lint` and `test`.
|
||||
|
||||
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 - Workspace Optimizations](/node-tutorial/4-workspace-optimization)).
|
||||
- `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 `build` target for your `products-data-client` project:
|
||||
|
||||
```{% command="npx nx build products-data-client" path="~/my-products" %}
|
||||
|
||||
> nx run products-data-client:build
|
||||
|
||||
Compiling TypeScript files for project "products-data-client"...
|
||||
Done compiling TypeScript files for project "products-data-client".
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project products-data-client (780ms)
|
||||
```
|
||||
|
||||
You can now find your built `products-data-client` distributable in your `dist/libs/products-data-client` directory, as specified in the `outputPath` property of the `build` target options in your `project.json` file.
|
||||
|
||||
Next, run a lint check on `products-data-client`:
|
||||
|
||||
```{% command="npx nx lint products-data-client" path="~/my-products" %}
|
||||
|
||||
> nx run products-data-client:lint
|
||||
|
||||
|
||||
Linting "products-data-client"...
|
||||
|
||||
All files pass linting.
|
||||
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target lint for project products-data-client (777ms)
|
||||
```
|
||||
|
||||
Next, add some tests to your data client in the `products-data-client.spec.ts` file:
|
||||
|
||||
```typescript {% fileName="libs/products-data-client/src/lib/products-data-client.spec.ts" %}
|
||||
import {
|
||||
createProductsDataClient,
|
||||
exampleProducts,
|
||||
} from './products-data-client';
|
||||
|
||||
describe('productsDataClient', () => {
|
||||
it('should get all example products', async () => {
|
||||
const productsDataClient = createProductsDataClient();
|
||||
const products = await productsDataClient.getProducts();
|
||||
expect(products).toEqual(Object.values(exampleProducts));
|
||||
});
|
||||
|
||||
it('should get example product by id', async () => {
|
||||
const productsDataClient = createProductsDataClient();
|
||||
const product = await productsDataClient.getProductById('1');
|
||||
expect(product).toEqual(exampleProducts['1']);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
And then run your `test` target:
|
||||
|
||||
```{% command="npx nx test products-data-client" path="~/my-products" %}
|
||||
|
||||
> nx run products-data-client:test
|
||||
|
||||
PASS products-data-client libs/products-data-client/src/lib/products-data-client.spec.ts
|
||||
productsDataClient
|
||||
✓ should get all example products (1 ms)
|
||||
✓ should get example product by id
|
||||
|
||||
Test Suites: 1 passed, 1 total
|
||||
Tests: 2 passed, 2 total
|
||||
Snapshots: 0 total
|
||||
Time: 0.843 s
|
||||
Ran all test suites.
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target test for project products-data-client (2s)
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [4: Workspace Optimization](/node-tutorial/4-workspace-optimization)
|
||||
213
docs/shared/node-tutorial/4-workspace-optimization.md
Normal file
@ -0,0 +1,213 @@
|
||||
# Node Tutorial - Part 4: Workspace Optimization
|
||||
|
||||
## Testing Affected Projects
|
||||
|
||||
`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:
|
||||
|
||||
```{% command="git add . && git commit -m 'commiting to test affected'" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||
Then make a change to your example products in your `products-data-client` project:
|
||||
|
||||
```typescript {% fileName="libs/products-data-client/src/lib/products-data-client.ts" %}
|
||||
export const exampleProducts: Record<string, Product> = {
|
||||
'1': { id: '1', name: 'Product 1', price: 100 },
|
||||
'2': { id: '2', name: 'Product 2', price: 400 }, // changed here
|
||||
};
|
||||
```
|
||||
|
||||
Run the following command to visualize how our workspace is affected by this change:
|
||||
|
||||
```{% command="npx nx affected:graph" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
The change made to the `products-data-client` project is also affecting the `products-api` and `products-cli` projects, since both of those projects import from the `products-data-client` project.
|
||||
|
||||
Next, stash your changes since the commit:
|
||||
|
||||
```{% command="git stash" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||
And then make a minor adjustment to the `products-cli` project:
|
||||
|
||||
```typescript {% fileName="apps/products-clit/src/main.ts" %}
|
||||
import { createProductsDataClient } from '@my-products/products-data-client';
|
||||
|
||||
main();
|
||||
|
||||
async function main() {
|
||||
const productsDataClient = createProductsDataClient();
|
||||
const id = getProvidedId();
|
||||
if (id != null) {
|
||||
const product = await productsDataClient.getProductById(id);
|
||||
if (!product) {
|
||||
throw new Error(`Product with id ${id} not found`);
|
||||
}
|
||||
console.log(JSON.stringify(product, null, 2));
|
||||
} else {
|
||||
const products = await productsDataClient.getProducts();
|
||||
console.log(JSON.stringify(products, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
function getProvidedId() {
|
||||
return process.argv[2];
|
||||
}
|
||||
```
|
||||
|
||||
Now run the command to visualize the affected graph again:
|
||||
|
||||
```{% command="npx nx affected:graph" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
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:
|
||||
|
||||
```{% command="npx nx affected --target=test" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||
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" /%}
|
||||
|
||||
## Task Caching
|
||||
|
||||
`affected` allows you to "skip" tasks that couldn't possibly be affected by your changes. Task Caching allows you to "replay" tasks that have already been run.
|
||||
|
||||
Task Caching is informed by "inputs" and "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 running a task, Nx will determine all the inputs for your task and create a hash that will be used to index your cache. If you've already run this task with the same inputs, your cache will already be populated at this index, and Nx will replay the results stored in the cache.
|
||||
|
||||
If this index does not exist, Nx will run the command and if the command succeeds, it will store the result in the cache.
|
||||
|
||||
### 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.
|
||||
|
||||
Outputs are defined for every target in your workspace:
|
||||
|
||||
```json {% fileName="libs/products-data-client/project.json" %}
|
||||
{
|
||||
"name": "products-data-client",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/products-data-client/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/products-data-client",
|
||||
"main": "libs/products-data-client/src/index.ts",
|
||||
"tsConfig": "libs/products-data-client/tsconfig.lib.json",
|
||||
"assets": ["libs/products-data-client/*.md"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/products-data-client/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/libs/products-data-client"],
|
||||
"options": {
|
||||
"jestConfig": "libs/products-data-client/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
```
|
||||
|
||||
Outputs are stored in the cache so that terminal output can be replayed, and any created files can be pulled from your cache and placed where they were created the original time the task was run.
|
||||
|
||||
### Example
|
||||
|
||||
To see caching in action, first clear your `dist` directory:
|
||||
|
||||
```{% command="rm -rf dist/" path="~/my-products" %}
|
||||
|
||||
```
|
||||
|
||||
And run the command `npx nx build products-data-client`. (Recall that you had already run this target in [3- Task Running](/node-tutorial/3-task-running))
|
||||
|
||||
```{% command="npx nx build products-data-client" path="~/my-products" %}
|
||||
|
||||
> nx run products-data-client:build [local cache]
|
||||
|
||||
Compiling TypeScript files for project "products-data-client"...
|
||||
Done compiling TypeScript files for project "products-data-client".
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project products-data-client (32ms)
|
||||
|
||||
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.
|
||||
```
|
||||
|
||||
Notice that `[local cache]` is mentioned in the terminal output, and that this time the command only took 32ms to run.
|
||||
|
||||
Also notice that the result of your build has been added back to the `dist/libs/products-data-client` directory.
|
||||
|
||||
{% card title="More Task Caching Details" description="See the documentation for more information on caching." url="/core-features/cache-task-results" /%}
|
||||
|
||||
## Configuring Task Pipelines
|
||||
|
||||
Next, run the command `npx nx build products-cli`:
|
||||
|
||||
```{% command="npx nx build products-cli" path="~/my-products" %}
|
||||
|
||||
✔ 1/1 dependent project tasks succeeded [1 read from cache]
|
||||
|
||||
Hint: you can run the command with --verbose to see the full dependent project outputs
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
|
||||
> nx run products-cli:build
|
||||
|
||||
chunk (runtime: main) main.js (main) 1.71 KiB [entry] [rendered]
|
||||
webpack compiled successfully (bafa37be9890ecb2)
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project products-cli and 1 task(s) it depends on (2s)
|
||||
|
||||
Nx read the output from the cache instead of running the command for 1 out of 2 tasks.
|
||||
```
|
||||
|
||||
Notice the line here:
|
||||
|
||||
```plain
|
||||
✔ 1/1 dependent project tasks succeeded [1 read from cache]
|
||||
```
|
||||
|
||||
This is because your `products-cli` project depends on your `products-data-client` project, which also has a `build` target. By default Nx is configured to run (or read from cache) the `build` target for any dependencies that have a `build` target, before running the `build` on the original project.
|
||||
|
||||
This feature allows the Nx graph to dynamically maintain task dependencies, rather than having to manually maintain those task dependencies as your workspace continues to grow.
|
||||
|
||||
{% 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" /%}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [5: Summary](/node-tutorial/5-summary)
|
||||
26
docs/shared/node-tutorial/5-summary.md
Normal file
@ -0,0 +1,26 @@
|
||||
# Node 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="Free Nx Course on YouTube" description="Follow up this tutorial with our free Nx Course." type="video" url="https://www.youtube.com/playlist?list=PLakNactNC1dH38AfqmwabvOszDmKriGco" /%}
|
||||
|
||||
{% card title="Nx React Tutorial" description="Follow up this tutorial the React tutorial to see how Nx can be used in the frontend space." url="/tutorials/react-tutorial" /%}
|
||||
|
||||
{% card title="Core Features" description="Learn more about the Core Features of Nx." url="/core-features" /%}
|
||||
|
||||
{% card title="The Nx Mental Model" description="Expand your Mental Model of Nx." url="/concepts/mental-model" /%}
|
||||
|
||||
{% card title="Distributed Task Execution" description="Learn how to use Nx Cloud for Distributed Task Execution to speed up your CI times even more." url="/concepts/dte" /%}
|
||||
|
||||
{% card title="Configure CI For Your Workspace" description="Learn how to create CI configuration for your workspace using our ci-workflow generator, or by creating your own workflow." url="/recipes/ci-setup" /%}
|
||||
|
||||
{% /cards %}
|
||||
BIN
docs/shared/node-tutorial/generator-syntax.png
Normal file
|
After Width: | Height: | Size: 94 KiB |
BIN
docs/shared/node-tutorial/initial-project-graph.png
Normal file
|
After Width: | Height: | Size: 564 KiB |
BIN
docs/shared/node-tutorial/matching-graph.png
Normal file
|
After Width: | Height: | Size: 720 KiB |
BIN
docs/shared/node-tutorial/project-graph-with-all-affected.png
Normal file
|
After Width: | Height: | Size: 679 KiB |
BIN
docs/shared/node-tutorial/project-graph-with-one-affected.png
Normal file
|
After Width: | Height: | Size: 695 KiB |
BIN
docs/shared/node-tutorial/requirements-diagram.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
docs/shared/node-tutorial/run-target-syntax.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
@ -1,165 +0,0 @@
|
||||
# React Nx Tutorial - Step 1: Create Application
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/HcQE5R6ucng"
|
||||
title="Nx.dev Tutorial | React | Step 1: Create Application"
|
||||
width="100%" /%}
|
||||
|
||||
In this tutorial you use Nx to build a full-stack application out of common libraries using modern technologies.
|
||||
|
||||
{% callout type="note" title="Nx has first-class Next.js support" %}
|
||||
Nx has first-class Next.js support, if you are looking to use it for your project. Read more about it [here](/packages/next)
|
||||
{% /callout %}
|
||||
|
||||
{% callout type="check" title="Integrated Repo" %}
|
||||
This tutorial sets up an [integrated](/concepts/integrated-vs-package-based) repo. If you prefer a [package-based repo](/concepts/integrated-vs-package-based), check out the [Package-Based Repo Tutorial](/getting-started/package-based-repo-tutorial).
|
||||
{% /callout %}
|
||||
|
||||
## Contents
|
||||
|
||||
- [1 - Create Application](/react-tutorial/01-create-application)
|
||||
- [2 - Add E2E Test](/react-tutorial/02-add-e2e-test)
|
||||
- [3 - Display Todos](/react-tutorial/03-display-todos)
|
||||
- [4 - Connect to API](/react-tutorial/04-connect-to-api)
|
||||
- [5 - Add Node Application](/react-tutorial/05-add-node-app)
|
||||
- [6 - Proxy Configuration](/react-tutorial/06-proxy)
|
||||
- [7 - Share Code](/react-tutorial/07-share-code)
|
||||
- [8 - Create Libraries](/react-tutorial/08-create-libs)
|
||||
- [9 - Project Graph](/react-tutorial/09-dep-graph)
|
||||
- [10 - Use Computation Caching](/react-tutorial/10-computation-caching)
|
||||
- [11 - Test Affected Projects](/react-tutorial/11-test-affected-projects)
|
||||
- [12 - Summary](/react-tutorial/12-summary)
|
||||
|
||||
## Create a new workspace
|
||||
|
||||
Start by creating a new workspace.
|
||||
|
||||
```shell
|
||||
npx create-nx-workspace@latest
|
||||
```
|
||||
|
||||
You then receive the following prompts in your command line:
|
||||
|
||||
```shell
|
||||
Workspace name (e.g., org name) myorg
|
||||
What to create in the new workspace react
|
||||
Application name todos
|
||||
Default stylesheet format CSS
|
||||
```
|
||||
|
||||
Enter the indicated answers.
|
||||
|
||||
> You can also choose to add [Nx Cloud](https://nx.app), but its not required for the tutorial.
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ ├── todos/
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── app/
|
||||
│ │ │ ├── assets/
|
||||
│ │ │ ├── environments/
|
||||
│ │ │ ├── favicon.ico
|
||||
│ │ │ ├── index.html
|
||||
│ │ │ ├── main.tsx
|
||||
│ │ │ ├── polyfills.ts
|
||||
│ │ │ └── styles.css
|
||||
│ │ ├── .babelrc
|
||||
│ │ ├── .browserslistrc
|
||||
│ │ ├── .eslintrc.json
|
||||
│ │ ├── jest.config.ts
|
||||
│ │ ├── project.json
|
||||
│ │ ├── tsconfig.app.json
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ └── tsconfig.spec.json
|
||||
│ └── todos-e2e/
|
||||
│ ├── src/
|
||||
│ │ ├── fixtures/
|
||||
│ │ │ └── example.json
|
||||
│ │ ├── e2e/
|
||||
│ │ │ └── app.cy.ts
|
||||
│ │ └── support/
|
||||
│ │ ├── app.po.ts
|
||||
│ │ ├── commands.ts
|
||||
│ │ └── e2e.ts
|
||||
│ ├── .eslintrc.json
|
||||
│ ├── cypress.config.ts
|
||||
│ ├── project.json
|
||||
│ └── tsconfig.json
|
||||
├── libs/
|
||||
├── tools/
|
||||
├── .eslintrc.json
|
||||
├── .prettierrc
|
||||
├── babel.config.json
|
||||
├── jest.config.ts
|
||||
├── jest.preset.js
|
||||
├── nx.json
|
||||
├── package.json
|
||||
├── README.md
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
Two projects were added to the workspace:
|
||||
|
||||
- A React application
|
||||
- E2E tests for the React application
|
||||
|
||||
## Serve the newly created application
|
||||
|
||||
Now that the application is set up, run it locally via:
|
||||
|
||||
```shell
|
||||
npx nx serve todos
|
||||
```
|
||||
|
||||
## Note on the Nx CLI
|
||||
|
||||
If you prefer to run using a global installation of Nx, you can run:
|
||||
|
||||
```shell
|
||||
nx serve todos
|
||||
```
|
||||
|
||||
Depending on how your dev env is set up, the command above might result in `Command 'nx' not found`.
|
||||
|
||||
To fix it, you can either install the `nx` cli globally by running:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn global add nx
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npm install -g nx
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
Alternatively, you can run the local installation of Nx by prepending every command with `npx`:
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn nx serve todos
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npx nx serve todos
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 2: Add E2E Tests](/react-tutorial/02-add-e2e-test)
|
||||
@ -1,45 +0,0 @@
|
||||
# React Nx Tutorial - Step 2: Add E2E Tests
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/3HSzqt3WiVg"
|
||||
title="Nx.dev Tutorial | React | Step 2: Add E2E Tests"
|
||||
width="100%" /%}
|
||||
|
||||
By default, Nx uses [Cypress](https://cypress.io) to run E2E tests.
|
||||
|
||||
Open **`apps/todos-e2e/src/support/app.po.ts`.** It's a page object file that contains helpers for querying the page.
|
||||
|
||||
**Add the following two helpers:**
|
||||
|
||||
```typescript
|
||||
export const getTodos = () => cy.get('li.todo');
|
||||
export const getAddTodoButton = () => cy.get('button#add-todo');
|
||||
```
|
||||
|
||||
**Next, update `apps/todos-e2e/src/e2e/app.cy.ts`.**
|
||||
|
||||
```typescript
|
||||
import { getAddTodoButton, getTodos } from '../support/app.po';
|
||||
|
||||
describe('TodoApps', () => {
|
||||
beforeEach(() => cy.visit('/'));
|
||||
|
||||
it('should display todos', () => {
|
||||
getTodos().should((t) => expect(t.length).equal(2));
|
||||
getAddTodoButton().click();
|
||||
getTodos().should((t) => expect(t.length).equal(3));
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
This is a simple example of an E2E test, only to verify the todos are displayed correctly.
|
||||
|
||||
If you have not done so already, stop the `npx nx serve` command and run `npx nx e2e todos-e2e --watch`.
|
||||
|
||||
Once the Cypress UI opens, select any browser you want. You'll see the `app.cy.ts` file that you just updated. Click on the file and the test will run. Keep the E2E tests running.
|
||||
|
||||
As you progress through the tutorial, you work on making these E2E tests pass.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 3: Display Todos](/react-tutorial/03-display-todos)
|
||||
@ -1,96 +0,0 @@
|
||||
# React Nx Tutorial - Step 3: Display Todos
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/fNehP0WX__c"
|
||||
title="Nx.dev Tutorial | React | Step 3: Display Todos"
|
||||
width="100%" /%}
|
||||
|
||||
Great! You have a failing E2E test. Now you can make it pass!
|
||||
|
||||
The best way to work with Cypress is to keep the failing E2E test running while working on the app. This helps you see the progress you are making.
|
||||
|
||||
## Show todos
|
||||
|
||||
**Open `apps/todos`.**
|
||||
|
||||
To make the first assertion of the e2e test pass, update `apps/todos/src/app/app.tsx`:
|
||||
|
||||
```typescript
|
||||
import { useState } from 'react';
|
||||
|
||||
interface Todo {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const App = () => {
|
||||
const [todos, setTodos] = useState<Todo[]>([
|
||||
{ title: 'Todo 1' },
|
||||
{ title: 'Todo 2' },
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Todos</h1>
|
||||
<ul>
|
||||
{todos.map((t) => (
|
||||
<li className={'todo'}>{t.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
**Rerun the specs by clicking the button in the top right corner of the left pane.** Now the test fails while trying to find the add todo button.
|
||||
|
||||
## Add todos
|
||||
|
||||
**Add the `add-todo` button with the corresponding click handler.**
|
||||
|
||||
```typescript
|
||||
import { useState } from 'react';
|
||||
|
||||
interface Todo {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export const App = () => {
|
||||
const [todos, setTodos] = useState<Todo[]>([
|
||||
{ title: 'Todo 1' },
|
||||
{ title: 'Todo 2' },
|
||||
]);
|
||||
|
||||
function addTodo() {
|
||||
setTodos([
|
||||
...todos,
|
||||
{
|
||||
title: `New todo ${Math.floor(Math.random() * 1000)}`,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Todos</h1>
|
||||
<ul>
|
||||
{todos.map((t) => (
|
||||
<li className={'todo'}>{t.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
<button id={'add-todo'} onClick={addTodo}>
|
||||
Add Todo
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
The tests should pass now.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 4: Connect to an API](/react-tutorial/04-connect-to-api)
|
||||
@ -1,59 +0,0 @@
|
||||
# React Nx Tutorial - Step 4: Connect to an API
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/HexxYHpIfAo"
|
||||
title="Nx.dev Tutorial | React | Step 4: Connect to an API"
|
||||
width="100%" /%}
|
||||
|
||||
Real-world applications do not live in isolation — they need APIs to talk to. Setup your app to talk to an API.
|
||||
|
||||
**Let's change our application to fetch the data from the API.**
|
||||
|
||||
```typescript
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
interface Todo {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const [todos, setTodos] = useState<Todo[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/todos')
|
||||
.then((_) => _.json())
|
||||
.then(setTodos);
|
||||
}, []);
|
||||
|
||||
function addTodo() {
|
||||
fetch('/api/addTodo', {
|
||||
method: 'POST',
|
||||
body: '',
|
||||
})
|
||||
.then((_) => _.json())
|
||||
.then((newTodo) => {
|
||||
setTodos([...todos, newTodo]);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Todos</h1>
|
||||
<ul>
|
||||
{todos.map((t) => (
|
||||
<li className={'todo'}>{t.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
<button id={'add-todo'} onClick={addTodo}>
|
||||
Add Todo
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 5: Add Node Application Implementing an API](/react-tutorial/05-add-node-app)
|
||||
@ -1,166 +0,0 @@
|
||||
# React Nx Tutorial - Step 5: Add Node Application Implementing API
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/XgfknOqgxQ0"
|
||||
title="Nx.dev Tutorial | React | Step 5: Add Node Application Implementing API"
|
||||
width="100%" /%}
|
||||
|
||||
The requests fail because the API has not been created yet. Using Nx you develop node applications next to your React applications. You can use same commands to run and test them. You share code between the backend and the frontend. Use this capability to implement the API service.
|
||||
|
||||
## Add Express plugin to your workspace
|
||||
|
||||
Nx is an open platform with plugins for many modern tools and frameworks. **To see some plugins, run `npx nx list`:**
|
||||
|
||||
```shell
|
||||
> NX Installed plugins:
|
||||
|
||||
@nrwl/cypress (executors,generators)
|
||||
@nrwl/jest (executors,generators)
|
||||
@nrwl/linter (executors,generators)
|
||||
@nrwl/nx-cloud (generators)
|
||||
@nrwl/react (generators)
|
||||
@nrwl/storybook (executors,generators)
|
||||
@nrwl/web (executors,generators)
|
||||
@nrwl/workspace (executors,generators)
|
||||
|
||||
|
||||
> NX Also available:
|
||||
|
||||
@nrwl/angular (generators)
|
||||
@nrwl/express (executors,generators)
|
||||
@nrwl/nest (executors,generators)
|
||||
@nrwl/next (executors,generators)
|
||||
@nrwl/node (executors,generators)
|
||||
@nrwl/nx-plugin (executors,generators)
|
||||
|
||||
|
||||
> NX Community plugins:
|
||||
|
||||
nx-plugins - Nx plugin integrations with ESBuild / Vite / Snowpack / Prisma, with derived ESBuild / nowpack / ... plugins.
|
||||
@codebrew/nx-aws-cdk - An Nx plugin for aws cdk develop.
|
||||
...
|
||||
```
|
||||
|
||||
**Add the dependency:**
|
||||
|
||||
{% tabs %}
|
||||
{% tab label="yarn" %}
|
||||
|
||||
```shell
|
||||
yarn add --dev @nrwl/express
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% tab label="npm" %}
|
||||
|
||||
```shell
|
||||
npm install --save-dev @nrwl/express
|
||||
```
|
||||
|
||||
{% /tab %}
|
||||
{% /tabs %}
|
||||
|
||||
{% callout type="check" title="List plugins" %}
|
||||
When installing `@nrwl/express`, it also automatically added `@nrwl/node` for you. Run `npx nx list @nrwl/express` and `npx nx list @nrwl/node` to see what those plugins provide.
|
||||
{% /callout %}
|
||||
|
||||
## Generate an Express application
|
||||
|
||||
**Run the following to generate a new Express application:**
|
||||
|
||||
```shell
|
||||
npx nx g @nrwl/express:app api --frontendProject=todos
|
||||
```
|
||||
|
||||
After this is done, you should see something like this:
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ ├── api/
|
||||
│ │ ├── src/
|
||||
│ │ │ ├── app/
|
||||
│ │ │ ├── assets/
|
||||
│ │ │ ├── environments/
|
||||
│ │ │ │ ├── environment.ts
|
||||
│ │ │ │ └── environment.prod.ts
|
||||
│ │ │ └── main.ts
|
||||
│ │ ├── jest.config.ts
|
||||
│ │ ├── project.json
|
||||
│ │ ├── tsconfig.app.json
|
||||
│ │ ├── tsconfig.json
|
||||
│ │ └── tsconfig.spec.json
|
||||
│ ├── todos/
|
||||
│ │ ├── src/
|
||||
│ │ ├── project.json
|
||||
│ │ └── proxy.conf.json
|
||||
│ └── todos-e2e/
|
||||
├── libs/
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
The `apps` directory is where Nx places anything you can run: frontend applications, backend applications, e2e test suites. That's why the `api` application appeared there.
|
||||
|
||||
You can run:
|
||||
|
||||
| Command | Description |
|
||||
| ---------------- | --------------------- |
|
||||
| npx nx serve api | serve the application |
|
||||
| npx nx build api | build the application |
|
||||
| npx nx test api | test the application |
|
||||
|
||||
**Add a file `apps/api/src/app/todos.ts`.**
|
||||
|
||||
```typescript
|
||||
import { Express } from 'express';
|
||||
|
||||
interface Todo {
|
||||
title: string;
|
||||
}
|
||||
|
||||
const todos: Todo[] = [{ title: 'Todo 1' }, { title: 'Todo 2' }];
|
||||
|
||||
export function addTodoRoutes(app: Express) {
|
||||
app.get('/api/todos', (req, resp) => resp.send(todos));
|
||||
app.post('/api/addTodo', (req, resp) => {
|
||||
const newTodo = {
|
||||
title: `New todo ${Math.floor(Math.random() * 1000)}`,
|
||||
};
|
||||
todos.push(newTodo);
|
||||
resp.send(newTodo);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Here, you are building an Express application with Nx. Nx also comes with Next support, and you can also use any other node library you want.
|
||||
|
||||
**Next update `apps/api/src/main.ts` to register the routes**
|
||||
|
||||
```typescript
|
||||
import * as express from 'express';
|
||||
import { addTodoRoutes } from './app/todos';
|
||||
|
||||
const app = express();
|
||||
|
||||
app.get('/api', (req, res) => {
|
||||
res.send({ message: 'Welcome to api!' });
|
||||
});
|
||||
addTodoRoutes(app);
|
||||
|
||||
const port = process.env.port || 3333;
|
||||
const server = app.listen(port, () => {
|
||||
console.log(`Listening at http://localhost:${port}/api`);
|
||||
});
|
||||
server.on('error', console.error);
|
||||
```
|
||||
|
||||
**Now run `npx nx serve api` to run the api server**
|
||||
|
||||
Refresh the application in the browser. The React app is now able to fetch and create todos by calling the API.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 6: Proxy](/react-tutorial/06-proxy)
|
||||
@ -1,85 +0,0 @@
|
||||
# React Nx Tutorial - Step 6: Proxy Configuration
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/xfvCz-yLeEw"
|
||||
title="Nx.dev Tutorial | React | Step 6: Proxy"
|
||||
width="100%" /%}
|
||||
|
||||
You passed `--frontendProject=todos` when creating the node application. What did that argument do?
|
||||
|
||||
It created a proxy configuration that allows the React application to talk to the API in development.
|
||||
|
||||
**To see how it works, open `apps/todos/project.json` and find the `serve` target.**
|
||||
|
||||
```json
|
||||
{
|
||||
"serve": {
|
||||
"executor": "@nrwl/web:dev-server",
|
||||
"options": {
|
||||
"buildTarget": "todos:build",
|
||||
"hmr": true,
|
||||
"proxyConfig": "apps/todos/proxy.conf.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"buildTarget": "todos:build:production",
|
||||
"hmr": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the `proxyConfig` property which points to `apps/todos/proxy.conf.json`. Open this file.
|
||||
|
||||
```json
|
||||
{
|
||||
"/api": {
|
||||
"target": "http://localhost:3333",
|
||||
"secure": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This configuration tells `npx nx serve` to forward all requests starting with `/api` to the process listening on port `3333`.
|
||||
|
||||
## Project.json, Targets, Executors
|
||||
|
||||
You configure your apps in `apps/[app-name]/project.json`. Open `apps/todos/project.json` to see an example. This file contains configuration for the todos app. For instance, you can see the `build`, `serve`, `lint`, and `test` targets. This means that you can run `npx nx build todos`, `npx nx serve todos`, etc..
|
||||
|
||||
Every target uses an executor which actually runs this target. So targets are analogous to typed npm scripts, and executors are analogous to typed shell scripts.
|
||||
|
||||
**Why not use shell scripts and npm scripts directly?**
|
||||
|
||||
There are a lot of advantages to providing additional metadata to the build tool. For instance, you can introspect targets. `npx nx serve todos --help` results in:
|
||||
|
||||
```shell
|
||||
nx run todos:serve [options,...]
|
||||
|
||||
Options:
|
||||
--buildTarget Target which builds the application
|
||||
--port Port to listen on. (default: 4200)
|
||||
--host Host to listen on. (default: localhost)
|
||||
--ssl Serve using HTTPS.
|
||||
--sslKey SSL key to use for serving HTTPS.
|
||||
--sslCert SSL certificate to use for serving HTTPS.
|
||||
--watch Watches for changes and rebuilds application (default: true)
|
||||
--liveReload Whether to reload the page on change, using live-reload. (default: true)
|
||||
--hmr Enable hot module replacement.
|
||||
--publicHost Public URL where the application will be served
|
||||
--open Open the application in the browser.
|
||||
--allowedHosts This option allows you to whitelist services that are allowed to access the dev server.
|
||||
--memoryLimit Memory limit for type checking service process in MB.
|
||||
--maxWorkers Number of workers to use for type checking.
|
||||
--baseHref Base url for the application being built.
|
||||
--skip-nx-cache Skip the use of Nx cache.
|
||||
--help Show available options for project target.
|
||||
```
|
||||
|
||||
It helps with good editor integration (see [VSCode Support](/core-features/integrate-with-editors#nx-console-for-vscode)).
|
||||
|
||||
But, most importantly, it provides a holistic dev experience regardless of the tools used, and enables advanced build features like distributed [computation caching](/concepts/how-caching-works) and [distributed builds](/concepts/dte).
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 7: Share Code](/react-tutorial/07-share-code)
|
||||
@ -1,96 +0,0 @@
|
||||
# React Nx Tutorial - Step 7: Share Code
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/-zzw4_oT_2I"
|
||||
title="Nx.dev Tutorial | React | Step 7: Share Code"
|
||||
width="100%" /%}
|
||||
|
||||
Awesome! The application is working end to end! However, there is a problem. Both the backend and the frontend define the `Todo` interface. The interface is in sync now, but in a real application, over time, it diverges, and, as a result, runtime errors creep in. You should share this interface between the backend and the frontend. In Nx, you do this by creating a library.
|
||||
|
||||
**Run the following generator to create a library:**
|
||||
|
||||
```shell
|
||||
npx nx g @nrwl/workspace:lib data
|
||||
```
|
||||
|
||||
The result should look like this:
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ ├── todos/
|
||||
│ ├── todos-e2e/
|
||||
│ └── api/
|
||||
├── libs/
|
||||
│ └── data/
|
||||
│ ├── src/
|
||||
│ │ ├── lib/
|
||||
│ │ │ └── data.ts
|
||||
│ │ └── index.ts
|
||||
│ ├── jest.config.ts
|
||||
│ ├── project.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── tsconfig.lib.json
|
||||
│ └── tsconfig.spec.json
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
**Copy the interface into `libs/data/src/lib/data.ts`.**
|
||||
|
||||
```typescript
|
||||
export interface Todo {
|
||||
title: string;
|
||||
}
|
||||
```
|
||||
|
||||
### A note about VS Code :
|
||||
|
||||
If you're using [VS Code](https://code.visualstudio.com/) it may be necessary at this point to restart the TS server so that the new `@myorg/data` package is recognised. This may need to be done **every time a new workspace library is added**. If you install the [Nx Console](/core-features/integrate-with-editors) extension you won't need to take this step.
|
||||
|
||||
## Refactor the API
|
||||
|
||||
**Now update `apps/api/src/app/todos.ts` to import the interface:**
|
||||
|
||||
```typescript
|
||||
import { Express } from 'express';
|
||||
import { Todo } from '@myorg/data';
|
||||
|
||||
const todos: Todo[] = [{ title: 'Todo 1' }, { title: 'Todo 2' }];
|
||||
|
||||
export function addTodoRoutes(app: Express) {
|
||||
app.get('/api/todos', (req, resp) => resp.send(todos));
|
||||
app.post('/api/addTodo', (req, resp) => {
|
||||
const newTodo = {
|
||||
title: `New todo ${Math.floor(Math.random() * 1000)}`,
|
||||
};
|
||||
todos.push(newTodo);
|
||||
resp.send(newTodo);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Update the React application
|
||||
|
||||
**Next import the interface in `apps/todos/src/app/app.tsx`:**
|
||||
|
||||
```typescript
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Todo } from '@myorg/data';
|
||||
|
||||
export const App = () => {
|
||||
...
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
Every time you add a new library, you have to restart `npx nx serve`.
|
||||
|
||||
**So restart both `npx nx serve api` and `npx nx serve todos` and you should see the application running.**
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 8: Create Libraries](/react-tutorial/08-create-libs)
|
||||
@ -1,187 +0,0 @@
|
||||
# React Nx Tutorial - Step 8: Create Libs
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/a1CAYlXizWM"
|
||||
title="Nx.dev Tutorial | React | Step 8: Create Libs"
|
||||
width="100%" /%}
|
||||
|
||||
Libraries are not just a way to share code in Nx. They are also useful for factoring out code into small units with a well-defined public API.
|
||||
|
||||
## Public API
|
||||
|
||||
Every library has an `index.ts` file, which defines its public API. Other applications and libraries should only access what the `index.ts` exports. Everything else in the library is private.
|
||||
|
||||
## UI libraries
|
||||
|
||||
To illustrate how useful libraries can be, create a library of React components.
|
||||
|
||||
Run
|
||||
|
||||
```shell
|
||||
npx nx g @nrwl/react:lib ui
|
||||
```
|
||||
|
||||
You should see the following:
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ ├── todos/
|
||||
│ ├── todos-e2e/
|
||||
│ └── api/
|
||||
├── libs/
|
||||
│ ├── data/
|
||||
│ └── ui/
|
||||
│ ├── src/
|
||||
│ │ ├── lib/
|
||||
│ │ │ ├── ui.module.css
|
||||
│ │ │ ├── ui.spec.tsx
|
||||
│ │ │ └── ui.tsx
|
||||
│ │ └── index.ts
|
||||
│ ├── jest.config.ts
|
||||
│ ├── project.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── tsconfig.lib.json
|
||||
│ └── tsconfig.spec.json
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
The `libs/ui/src/lib/ui.tsx` file looks like this:
|
||||
|
||||
```typescript
|
||||
import './ui.module.css';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface UiProps {}
|
||||
|
||||
export function Ui(props: UiProps) {
|
||||
return (
|
||||
<div>
|
||||
<h1>Welcome to Ui!</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Ui;
|
||||
```
|
||||
|
||||
## Add a component
|
||||
|
||||
Here, you can either change the UI component or generate a new one.
|
||||
|
||||
**Add a component to the newly created ui library by running:**
|
||||
|
||||
```shell
|
||||
npx nx g @nrwl/react:component todos --project=ui --export
|
||||
```
|
||||
|
||||
```treeview
|
||||
myorg/
|
||||
├── apps/
|
||||
│ ├── todos/
|
||||
│ ├── todos-e2e/
|
||||
│ └── api/
|
||||
├── libs/
|
||||
│ ├── data/
|
||||
│ └── ui/
|
||||
│ ├── src/
|
||||
│ │ ├── lib/
|
||||
│ │ │ └── todos/
|
||||
│ │ │ │ ├── todos.module.css
|
||||
│ │ │ │ ├── todos.spec.tsx
|
||||
│ │ │ │ └── todos.tsx
|
||||
│ │ │ ├── ui.css
|
||||
│ │ │ ├── ui.spec.tsx
|
||||
│ │ │ └── ui.tsx
|
||||
│ │ └── index.ts
|
||||
│ ├── jest.config.ts
|
||||
│ ├── project.json
|
||||
│ ├── tsconfig.json
|
||||
│ ├── tsconfig.lib.json
|
||||
│ └── tsconfig.spec.json
|
||||
├── tools/
|
||||
├── nx.json
|
||||
├── package.json
|
||||
└── tsconfig.base.json
|
||||
```
|
||||
|
||||
**Implement the Todos component.**
|
||||
|
||||
`libs/ui/src/lib/todos/todos.tsx`
|
||||
|
||||
```typescript
|
||||
import { Todo } from '@myorg/data';
|
||||
import './todos.module.css';
|
||||
|
||||
export interface TodosProps {
|
||||
todos: Todo[];
|
||||
}
|
||||
|
||||
export function Todos(props: TodosProps) {
|
||||
return (
|
||||
<ul>
|
||||
{props.todos.map((t) => (
|
||||
<li className={'todo'}>{t.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Todos;
|
||||
```
|
||||
|
||||
## Use the UI library
|
||||
|
||||
**Now import `Todos` into `apps/todos/src/app/app.tsx`.**
|
||||
|
||||
```typescript
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Todo } from '@myorg/data';
|
||||
import { Todos } from '@myorg/ui';
|
||||
|
||||
const App = () => {
|
||||
const [todos, setTodos] = useState<Todo[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/todos')
|
||||
.then((_) => _.json())
|
||||
.then(setTodos);
|
||||
}, []);
|
||||
|
||||
function addTodo() {
|
||||
fetch('/api/addTodo', {
|
||||
method: 'POST',
|
||||
body: '',
|
||||
})
|
||||
.then((_) => _.json())
|
||||
.then((newTodo) => {
|
||||
setTodos([...todos, newTodo]);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Todos</h1>
|
||||
<Todos todos={todos} />
|
||||
<button id={'add-todo'} onClick={addTodo}>
|
||||
Add Todo
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
**Restart both `npx nx serve api` and `npx nx serve todos` and you should see the application running.**
|
||||
|
||||
{% callout type="note" title="Nx helps you" %}
|
||||
Nx helps you explore code generation options. Run `npx nx g @nrwl/react:component --help` to see all options available. Pass `--dry-run` to the command to see what would be generated without actually changing anything, like this: `npx nx g @nrwl/react:component mycmp --project=ui --dry-run`.
|
||||
{% /callout %}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 9: Using the Project Graph](/react-tutorial/09-dep-graph)
|
||||
@ -1,24 +0,0 @@
|
||||
# React Nx Tutorial - Step 9: Project Graph
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/Dr7jI9RYcmY"
|
||||
title="Nx.dev Tutorial | React | Step 9: Dep Graph"
|
||||
width="100%" /%}
|
||||
|
||||
An Nx workspace can contain dozens or hundreds of applications and libraries. As a codebase grows, it can be difficult to understand how they depend on each other and the implications of making a particular change.
|
||||
|
||||
Previously, some senior architect would create an ad-hoc dependency diagram and upload it to a corporate wiki. The diagram is not correct even on Day 1 and gets more and more out of sync with every passing day.
|
||||
|
||||
With Nx, you can do better than that.
|
||||
|
||||
Run
|
||||
|
||||
```shell
|
||||
npx nx graph
|
||||
```
|
||||
|
||||
The project graph page opens in a new browser window. Click on "Show all projects" to see all the apps and libraries in the workspace.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 10: Using Computation Caching](/react-tutorial/10-computation-caching)
|
||||
147
docs/shared/react-tutorial/1-code-generation.md
Normal file
@ -0,0 +1,147 @@
|
||||
---
|
||||
title: 'React Tutorial - Part 1: Code Generation'
|
||||
description: In this tutorial you'll create a frontend-focused workspace with Nx.
|
||||
---
|
||||
|
||||
{% callout type="check" title="Two Styles of Repo" %}
|
||||
There are two styles of repos: integrated and package-based. This tutorial shows the integrated style.
|
||||
|
||||
You can find more information on the difference between the two in [our introduction](/getting-started/intro).
|
||||
{% /callout %}
|
||||
|
||||
# React Tutorial - Part 1: Code Generation
|
||||
|
||||
## Contents
|
||||
|
||||
- [1 - Code Generation](/react-tutorial/1-code-generation)
|
||||
- [2 - Project Graph](/react-tutorial/2-project-graph)
|
||||
- [3 - Task Running](/react-tutorial/3-task-running)
|
||||
- [4 - Workspace Optimization](/react-tutorial/4-workspace-optimization)
|
||||
- [5 - Summary](/react-tutorial/5-summary)
|
||||
|
||||
## Your Objective
|
||||
|
||||
For this tutorial, you'll create two React applications, a React lib for your common components, and a library for your business logic as follows:
|
||||
|
||||

|
||||
|
||||
## Creating an Nx Workspace
|
||||
|
||||
Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses:
|
||||
|
||||
```{% command="npx create-nx-workspace@latest" path="~" %}
|
||||
|
||||
✔ Choose your style · integrated
|
||||
✔ What to create in the new workspace · react
|
||||
✔ Repository name · myorg
|
||||
✔ 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, notice two projects were added to the workspace:
|
||||
|
||||
- A React application located in `apps/store`.
|
||||
- A Project for Cypress e2e tests for our `store` application in `apps/store-e2e`.
|
||||
|
||||
{% 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" /%}
|
||||
|
||||
## Adding Another Application to Your Workspace
|
||||
|
||||
Run this command to create your `admin` app:
|
||||
|
||||
```{% command="npx nx g @nrwl/react:app admin" path="~/myorg" %}
|
||||
|
||||
> NX Generating @nrwl/react:application
|
||||
|
||||
CREATE apps/admin/.babelrc
|
||||
CREATE apps/admin/.browserslistrc
|
||||
CREATE apps/admin/src/app/app.spec.tsx
|
||||
CREATE apps/admin/src/app/nx-welcome.tsx
|
||||
CREATE apps/admin/src/assets/.gitkeep
|
||||
CREATE apps/admin/src/environments/environment.prod.ts
|
||||
CREATE apps/admin/src/environments/environment.ts
|
||||
CREATE apps/admin/src/favicon.ico
|
||||
CREATE apps/admin/src/index.html
|
||||
CREATE apps/admin/src/main.tsx
|
||||
CREATE apps/admin/src/polyfills.ts
|
||||
CREATE apps/admin/tsconfig.app.json
|
||||
CREATE apps/admin/tsconfig.json
|
||||
CREATE apps/admin/src/app/app.module.css
|
||||
CREATE apps/admin/src/app/app.tsx
|
||||
CREATE apps/admin/src/styles.css
|
||||
CREATE apps/admin/project.json
|
||||
CREATE apps/admin/.eslintrc.json
|
||||
CREATE apps/admin-e2e/cypress.config.ts
|
||||
CREATE apps/admin-e2e/src/e2e/app.cy.ts
|
||||
CREATE apps/admin-e2e/src/fixtures/example.json
|
||||
CREATE apps/admin-e2e/src/support/app.po.ts
|
||||
CREATE apps/admin-e2e/src/support/commands.ts
|
||||
CREATE apps/admin-e2e/src/support/e2e.ts
|
||||
CREATE apps/admin-e2e/tsconfig.json
|
||||
CREATE apps/admin-e2e/project.json
|
||||
CREATE apps/admin-e2e/.eslintrc.json
|
||||
CREATE apps/admin/jest.config.ts
|
||||
CREATE apps/admin/tsconfig.spec.json
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Generating Libraries
|
||||
|
||||
To create the `common-ui` and `products` libraries, use the `@nrwl/react:lib` and `@nrwl/js:lib` generators respectively:
|
||||
|
||||
{% side-by-side %}
|
||||
|
||||
```{% command="npx nx g @nrwl/react:lib common-ui" path="~/myorg" %}
|
||||
|
||||
> NX Generating @nrwl/react:library
|
||||
|
||||
CREATE libs/common-ui/project.json
|
||||
CREATE libs/common-ui/.eslintrc.json
|
||||
CREATE libs/common-ui/.babelrc
|
||||
CREATE libs/common-ui/README.md
|
||||
CREATE libs/common-ui/src/index.ts
|
||||
CREATE libs/common-ui/tsconfig.json
|
||||
CREATE libs/common-ui/tsconfig.lib.json
|
||||
UPDATE tsconfig.base.json
|
||||
CREATE libs/common-ui/jest.config.ts
|
||||
CREATE libs/common-ui/tsconfig.spec.json
|
||||
CREATE libs/common-ui/src/lib/common-ui.module.css
|
||||
CREATE libs/common-ui/src/lib/common-ui.spec.tsx
|
||||
CREATE libs/common-ui/src/lib/common-ui.tsx
|
||||
```
|
||||
|
||||
```{% command="npx nx g @nrwl/js:lib products" path="~/myorg" %}
|
||||
|
||||
> NX Generating @nrwl/js:library
|
||||
|
||||
CREATE libs/products/README.md
|
||||
CREATE libs/products/package.json
|
||||
CREATE libs/products/src/index.ts
|
||||
CREATE libs/products/src/lib/products.spec.ts
|
||||
CREATE libs/products/src/lib/products.ts
|
||||
CREATE libs/products/tsconfig.json
|
||||
CREATE libs/products/tsconfig.lib.json
|
||||
CREATE libs/products/.babelrc
|
||||
CREATE libs/products/project.json
|
||||
UPDATE tsconfig.base.json
|
||||
CREATE libs/products/.eslintrc.json
|
||||
CREATE libs/products/jest.config.ts
|
||||
CREATE libs/products/tsconfig.spec.json
|
||||
```
|
||||
|
||||
{% /side-by-side %}
|
||||
|
||||
You should now be able to see all four projects of our design:
|
||||
|
||||
- `store` in `apps/store`
|
||||
- `admin` in `apps/admin`
|
||||
- `products` in `libs/products`
|
||||
- `common-ui` in `libs/common-ui`
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [2: Project Graph](/react-tutorial/2-project-graph)
|
||||
@ -1,64 +0,0 @@
|
||||
# React Nx Tutorial - Step 10: Computation Caching
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/aNjvT3VX1Ts"
|
||||
title="Nx.dev Tutorial | React | step 10: Computation Caching"
|
||||
width="100%" /%}
|
||||
|
||||
Nx has built-in computation caching, which helps drastically improve the performance of the commands.
|
||||
|
||||
**To see it in action, run `npx nx build todos`:**
|
||||
|
||||
```shell
|
||||
> npx nx run todos:build
|
||||
|
||||
Starting type checking service...
|
||||
Using 14 workers with 2048MB memory limit
|
||||
Hash: c38fbdb8b372af447180
|
||||
Built at: 03/26/2020 11:03:57 AM
|
||||
Entrypoint main = runtime.ff0534391bf88384547e.js main.b8dbcd3d3fd2900377f2.esm.js
|
||||
Entrypoint polyfills = runtime.ff0534391bf88384547e.js polyfills.55535a35b1529d884ca3.esm.js
|
||||
Entrypoint styles = runtime.ff0534391bf88384547e.js styles.3ff695c00d717f2d2a11.css
|
||||
chunk {0} runtime.ff0534391bf88384547e.js (runtime) 0 bytes ={1}= ={2}= ={3}= [entry] [rendered]
|
||||
chunk {1} main.b8dbcd3d3fd2900377f2.esm.js (main) 155 KiB ={0}= [initial] [rendered]
|
||||
chunk {2} polyfills.55535a35b1529d884ca3.esm.js (polyfills) 239 KiB ={0}= [initial] [rendered]
|
||||
chunk {3} styles.3ff695c00d717f2d2a11.css (styles) 147 bytes ={0}= [initial] [rendered]
|
||||
```
|
||||
|
||||
**Now, run `npx nx build todos` again, and you see the results appearing instantly:**
|
||||
|
||||
```shell
|
||||
> npx nx run todos:build
|
||||
|
||||
> NX NOTE Cached Output:
|
||||
|
||||
Starting type checking service...
|
||||
Using 14 workers with 2048MB memory limit
|
||||
Hash: c38fbdb8b372af447180
|
||||
Built at: 03/26/2020 11:05:06 AM
|
||||
Entrypoint main = runtime.ff0534391bf88384547e.js main.b8dbcd3d3fd2900377f2.esm.js
|
||||
Entrypoint polyfills = runtime.ff0534391bf88384547e.js polyfills.55535a35b1529d884ca3.esm.js
|
||||
Entrypoint styles = runtime.ff0534391bf88384547e.js styles.3ff695c00d717f2d2a11.css
|
||||
chunk {0} runtime.ff0534391bf88384547e.js (runtime) 0 bytes ={1}= ={2}= ={3}= [entry] [rendered]
|
||||
chunk {1} main.b8dbcd3d3fd2900377f2.esm.js (main) 155 KiB ={0}= [initial] [rendered]
|
||||
chunk {2} polyfills.55535a35b1529d884ca3.esm.js (polyfills) 239 KiB ={0}= [initial] [rendered]
|
||||
chunk {3} styles.3ff695c00d717f2d2a11.css (styles) 147 bytes ={0}= [initial] [rendered]
|
||||
```
|
||||
|
||||
Based on the state of the source code and the environment, Nx figured out that it had already run this exact command. Nx found the artifact in the local cache and replayed the output and restored the necessary files.
|
||||
|
||||
## Building multiple projects
|
||||
|
||||
**Now, run `npx nx run-many --target=build --projects=todos,api` to rebuild the two applications:**
|
||||
|
||||
```shell
|
||||
Nx read the output from the cache instead of running the command for 1 out of 2 projects.
|
||||
```
|
||||
|
||||
Nx built `api` and retrieved `todos` from its computation cache. Read more about the cache [here](/concepts/how-caching-works).
|
||||
|
||||
> Add --parallel to any command, and Nx does most of the work in parallel.
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 11: Test Affected Projects](/react-tutorial/11-test-affected-projects)
|
||||
@ -1,81 +0,0 @@
|
||||
# React Nx Tutorial - Step 11: Test Affected Projects
|
||||
|
||||
{% youtube
|
||||
src="https://www.youtube.com/embed/_mBBFRjs01g"
|
||||
title="Nx.dev Tutorial | React | Step 11: Test Affected Projects"
|
||||
width="100%" /%}
|
||||
|
||||
In addition to supporting computation caching, Nx scales your development by doing code change analysis to see what is affected by a particular pull request.
|
||||
|
||||
**Commit all the changes you have made so far**:
|
||||
|
||||
```shell
|
||||
git add .
|
||||
git commit -am 'init'
|
||||
git checkout -b testbranch
|
||||
```
|
||||
|
||||
**Open `libs/ui/src/lib/todos/todos.tsx` and change the component by updating the `<li>` content to `{t.title}!!`:**
|
||||
|
||||
```typescript
|
||||
import { Todo } from '@myorg/data';
|
||||
import './todos.module.css';
|
||||
|
||||
export interface TodosProps {
|
||||
todos: Todo[];
|
||||
}
|
||||
|
||||
export function Todos(props: TodosProps) {
|
||||
return (
|
||||
<ul>
|
||||
{props.todos.map((t) => (
|
||||
<li className={'todo'}>{t.title}!!</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export default Todos;
|
||||
```
|
||||
|
||||
**Run `npx nx print-affected --type=app --select=projects`**, and you should see `todos` printed out. The `print-affected` looks at what you have changed and uses the project graph to figure out which apps can be affected by this change.
|
||||
|
||||
**Run `npx nx print-affected --type=lib --select=projects`**, and you should see `ui` printed out. This command works similarly, but instead of printing the affected apps, it prints the affected libs.
|
||||
|
||||
## Test Affected Projects
|
||||
|
||||
Printing the affected projects can be handy, but usually you want to do something with them. For instance, you may want to test everything that has been affected.
|
||||
|
||||
**Run `npx nx affected:test` to retest only the projects affected by the change.**
|
||||
|
||||
As you can see, since we updated the code, without updating the tests, the unit tests failed.
|
||||
|
||||
```shell
|
||||
> NX Running target test for projects:
|
||||
|
||||
- ui
|
||||
- todos
|
||||
|
||||
...
|
||||
|
||||
Failed projects:
|
||||
|
||||
- todos
|
||||
- ui
|
||||
```
|
||||
|
||||
Note that Nx only tried to retest `ui` and `todos`. It didn't retest `api` or `data` because there is no way that could be affected by the changes in this branch.
|
||||
|
||||
## Affected:\*
|
||||
|
||||
You can run any target against the affected projects in the graph like this:
|
||||
|
||||
```shell
|
||||
# The following are equivalent
|
||||
npx nx affected --target=build
|
||||
npx nx affected:build
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [Step 12: Summary](/react-tutorial/12-summary)
|
||||
@ -1,17 +0,0 @@
|
||||
# React Nx Tutorial - Step 12: Summary
|
||||
|
||||
In this tutorial you:
|
||||
|
||||
- Built a full stack application using React and Express
|
||||
- Shared code between the frontend and the backend
|
||||
- Created a UI library
|
||||
- Used Nx affected commands to only retest and rebuild what is affected
|
||||
|
||||
## Learn more
|
||||
|
||||
- [Free Nx Course on YouTube](https://www.youtube.com/playlist?list=PLakNactNC1dH38AfqmwabvOszDmKriGco)
|
||||
|
||||
**Dive Deep:**
|
||||
|
||||
- [Computation Caching](/concepts/how-caching-works)
|
||||
- [Rebuilding What is Affected](/concepts/affected)
|
||||
126
docs/shared/react-tutorial/2-project-graph.md
Normal file
@ -0,0 +1,126 @@
|
||||
# React Tutorial - Part 2: Project Graph
|
||||
|
||||
Run the command: `npx nx graph`. A browser should open up with the following contents:
|
||||
|
||||

|
||||
|
||||
This is still different than the design from the start of Part 1:
|
||||
|
||||

|
||||
|
||||
The Project Graph is derived from the source code of your workspace. Make the following adjustments to your existing projects, so that our Project Graph will match the design:
|
||||
|
||||
### `common-ui`
|
||||
|
||||
Run the `@nrwl/react:component` generator with the command:
|
||||
|
||||
```{% command="npx nx g @nrwl/react:component banner --project=common-ui --export" path="~/myorg" %}
|
||||
|
||||
> NX Generating @nrwl/react:component
|
||||
|
||||
CREATE libs/common-ui/src/lib/banner/banner.module.css
|
||||
CREATE libs/common-ui/src/lib/banner/banner.spec.tsx
|
||||
CREATE libs/common-ui/src/lib/banner/banner.tsx
|
||||
UPDATE libs/common-ui/src/index.ts
|
||||
```
|
||||
|
||||
Then create a simple `Banner` component in the generated file:
|
||||
|
||||
```javascript {% fileName="libs/common-ui/src/lib/banner/banner.tsx" %}
|
||||
export interface BannerProps {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export function Banner(props: BannerProps) {
|
||||
return <header>{props.text}</header>;
|
||||
}
|
||||
|
||||
export default Banner;
|
||||
```
|
||||
|
||||
### `admin`
|
||||
|
||||
Add the `Banner` component to the admin app:
|
||||
|
||||
```javascript {% fileName="apps/admin/src/app/app.tsx" %}
|
||||
import { Banner } from '@myorg/common-ui';
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Banner text="Welcome to our admin app." />
|
||||
<div />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### `products`
|
||||
|
||||
Export a `Product` TS interface and some example products:
|
||||
|
||||
```javascript {% fileName="libs/products/src/lib/products.ts" %}
|
||||
export interface Product {
|
||||
id: string;
|
||||
name: string;
|
||||
price: number;
|
||||
}
|
||||
|
||||
export const exampleProducts: Product[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'Product 1',
|
||||
price: 100,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: 'Product 2',
|
||||
price: 200,
|
||||
},
|
||||
];
|
||||
```
|
||||
|
||||
### `store`
|
||||
|
||||
Use both the `Banner` component from your `common-ui` lib, and the `exampleProducts` from your `products` lib:
|
||||
|
||||
```javascript {% fileName="apps/store/src/app/app.tsx" %}
|
||||
import { Banner } from '@myorg/common-ui';
|
||||
import { exampleProducts } from '@myorg/products';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Banner text="Welcome to the store!" />
|
||||
<ul>
|
||||
{exampleProducts.map((product) => (
|
||||
<li key={product.id}>
|
||||
<strong>{product.name}</strong> Price: {product.price}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
Now run `npx nx graph` again:
|
||||
|
||||
{% side-by-side %}
|
||||

|
||||
|
||||

|
||||
{% /side-by-side %}
|
||||
|
||||
Your graph now matches the original design.
|
||||
|
||||
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: Workspace Optimization](/react-tutorial/4-workspace-optimization).
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [3: Task Running](/react-tutorial/3-task-running)
|
||||
95
docs/shared/react-tutorial/3-task-running.md
Normal file
@ -0,0 +1,95 @@
|
||||
# React 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 `common-ui` project:
|
||||
|
||||
```json {% fileName="libs/common-ui/project.json" %}
|
||||
{
|
||||
"name": "common-ui",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/common-ui/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/common-ui/**/*.{ts,tsx,js,jsx}"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/libs/common-ui"],
|
||||
"options": {
|
||||
"jestConfig": "libs/common-ui/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can see that two targets are defined here: `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 - Workspace Optimizations](/react-tutorial/4-workspace-optimization)).
|
||||
- `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 `common-ui` project:
|
||||
|
||||
```{% command="npx nx test common-ui" path="~/myorg" %}
|
||||
|
||||
> nx run common-ui:test
|
||||
|
||||
PASS common-ui libs/common-ui/src/lib/common-ui.spec.tsx
|
||||
PASS common-ui libs/common-ui/src/lib/banner/banner.spec.tsx
|
||||
|
||||
Test Suites: 2 passed, 2 total
|
||||
Tests: 2 passed, 2 total
|
||||
Snapshots: 0 total
|
||||
Time: 0.84 s, estimated 1 s
|
||||
Ran all test suites.
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target test for project common-ui (2s)
|
||||
```
|
||||
|
||||
Next, run a lint check on your `common-ui` project:
|
||||
|
||||
```{% command="npx nx lint common-ui" path="~/myorg" %}
|
||||
|
||||
> nx run common-ui:lint
|
||||
|
||||
|
||||
Linting "common-ui"...
|
||||
|
||||
All files pass linting.
|
||||
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target lint for project common-ui (2s)
|
||||
```
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [4: Workspace Optimization](/react-tutorial/4-workspace-optimization)
|
||||
201
docs/shared/react-tutorial/4-workspace-optimization.md
Normal file
@ -0,0 +1,201 @@
|
||||
# React Tutorial - Part 4: Workspace Optimization
|
||||
|
||||
## Testing Affected Projects
|
||||
|
||||
`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:
|
||||
|
||||
```{% command="git add . && git commit -m 'commiting to test affected'" path="~/myorg" %}
|
||||
|
||||
```
|
||||
|
||||
Then make a change to the styles of your `common-ui` project:
|
||||
|
||||
```css {% fileName="libs/common-ui/src/lib/common-ui.module.css" %}
|
||||
.container {
|
||||
color: 'blue;';
|
||||
}
|
||||
```
|
||||
|
||||
You can visualize how our workspace is affected by this change using the command:
|
||||
|
||||
```{% command="npx nx affected:graph" path="~/myorg" %}
|
||||
|
||||
```
|
||||
|
||||

|
||||
|
||||
The change made to the `common-ui` project is also affecting the `admin` and `store` projects. This can be leveraged run tasks only on the projects that were affected by this commit.
|
||||
|
||||
To run the `test` targets only for affected projects, run the command:
|
||||
|
||||
```{% command="npx nx affected --target=test" path="~/myorg" %}
|
||||
|
||||
```
|
||||
|
||||
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" /%}
|
||||
|
||||
## Task Caching
|
||||
|
||||
`affected` allows you to "skip" tasks that couldn't possibly be affected by your changes. Task Caching allows you to "replay" tasks that have already been run.
|
||||
|
||||
Task Caching is informed by "inputs" and "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 running a task, Nx will determine all the inputs for your task and create a hash that will be used to index your cache. If you've already run this task with the same inputs, your cache will already be populated at this index, and Nx will replay the results stored in the cache.
|
||||
|
||||
If this index does not exist, Nx will run the command and if the command succeeds, it will store the result in the cache.
|
||||
|
||||
### 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.
|
||||
|
||||
Outputs are defined for every target in your workspace:
|
||||
|
||||
```json {% fileName="libs/products/project.json" %}
|
||||
{
|
||||
"name": "products",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/products/src",
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/products",
|
||||
"main": "libs/products/src/index.ts",
|
||||
"tsConfig": "libs/products/tsconfig.lib.json",
|
||||
"assets": ["libs/products/*.md"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nrwl/linter:eslint",
|
||||
"outputs": ["{options.outputFile}"],
|
||||
"options": {
|
||||
"lintFilePatterns": ["libs/products/**/*.ts"]
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nrwl/jest:jest",
|
||||
"outputs": ["coverage/libs/products"],
|
||||
"options": {
|
||||
"jestConfig": "libs/products/jest.config.ts",
|
||||
"passWithNoTests": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": []
|
||||
}
|
||||
```
|
||||
|
||||
Outputs are stored in the cache so that terminal output can be replayed, and any created files can be pulled from your cache, and placed where they were created the original time the task was run.
|
||||
|
||||
### Example
|
||||
|
||||
To see caching in action, run the command:
|
||||
|
||||
```{% command="npx nx build admin" path="~/myorg" %}
|
||||
|
||||
> nx run admin:build:production
|
||||
|
||||
Entrypoint main 139 KiB = runtime.54e36ebee261465d.js 1.19 KiB main.623d91691bdb6754.css 42 bytes main.303fe7c1dcf5306b.js 137 KiB
|
||||
Entrypoint polyfills 93.5 KiB = runtime.54e36ebee261465d.js 1.19 KiB polyfills.bd0d0abec287a28e.js 92.3 KiB
|
||||
Entrypoint styles 1.19 KiB = runtime.54e36ebee261465d.js 1.19 KiB styles.ef46db3751d8e999.css 0 bytes
|
||||
chunk (runtime: runtime) main.623d91691bdb6754.css, main.303fe7c1dcf5306b.js (main) 144 KiB (javascript) 50 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) polyfills.bd0d0abec287a28e.js (polyfills) 301 KiB [initial] [rendered]
|
||||
chunk (runtime: runtime) styles.ef46db3751d8e999.css (styles) 50 bytes (javascript) 80 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) runtime.54e36ebee261465d.js (runtime) 3.23 KiB [entry] [rendered]
|
||||
webpack compiled successfully (0c0df3e6c70c6b7b)
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project admin (4s)
|
||||
```
|
||||
|
||||
Since you have not run the `build` target before for the `admin` project, Nx runs the `build`, and populates the results in `dist/apps/admin` as specified in the `admin` project's `project.json` file for the `build` target.
|
||||
|
||||
Next, remove your dist directory:
|
||||
|
||||
```{% command="rm -rf dist" path="~/myorg" %}
|
||||
|
||||
```
|
||||
|
||||
And run the command again:
|
||||
|
||||
```{% command="npx nx build admin" path="~/myorg" %}
|
||||
|
||||
> nx run admin:build:production [local cache]
|
||||
|
||||
Entrypoint main 139 KiB = runtime.54e36ebee261465d.js 1.19 KiB main.623d91691bdb6754.css 42 bytes main.303fe7c1dcf5306b.js 137 KiB
|
||||
Entrypoint polyfills 93.5 KiB = runtime.54e36ebee261465d.js 1.19 KiB polyfills.bd0d0abec287a28e.js 92.3 KiB
|
||||
Entrypoint styles 1.19 KiB = runtime.54e36ebee261465d.js 1.19 KiB styles.ef46db3751d8e999.css 0 bytes
|
||||
chunk (runtime: runtime) main.623d91691bdb6754.css, main.303fe7c1dcf5306b.js (main) 144 KiB (javascript) 50 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) polyfills.bd0d0abec287a28e.js (polyfills) 301 KiB [initial] [rendered]
|
||||
chunk (runtime: runtime) styles.ef46db3751d8e999.css (styles) 50 bytes (javascript) 80 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) runtime.54e36ebee261465d.js (runtime) 3.23 KiB [entry] [rendered]
|
||||
webpack compiled successfully (0c0df3e6c70c6b7b)
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project admin (59ms)
|
||||
|
||||
Nx read the output from the cache instead of running the command for 1 out of 1 tasks.
|
||||
```
|
||||
|
||||
Notice that `[local cache]` is mentioned in the terminal output, and that this time the command only took 59ms to run.
|
||||
|
||||
Also notice that the result of your build has been added back to the `dist/apps/admin` directory.
|
||||
|
||||
{% card title="More Task Caching Details" description="See the documentation for more information on caching." url="/core-features/cache-task-results" /%}
|
||||
|
||||
## Configuring Task Pipelines
|
||||
|
||||
Next, run the command `npx nx build store`:
|
||||
|
||||
```{% command="npx nx build store" path="~/myorg" %}
|
||||
|
||||
✔ 1/1 dependent project tasks succeeded [0 read from cache]
|
||||
|
||||
Hint: you can run the command with --verbose to see the full dependent project outputs
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
|
||||
> nx run store:build:production
|
||||
|
||||
Entrypoint main 139 KiB = runtime.54e36ebee261465d.js 1.19 KiB main.623d91691bdb6754.css 42 bytes main.94f9a4a3cec4f056.js 138 KiB
|
||||
Entrypoint polyfills 93.5 KiB = runtime.54e36ebee261465d.js 1.19 KiB polyfills.bd0d0abec287a28e.js 92.3 KiB
|
||||
Entrypoint styles 1.19 KiB = runtime.54e36ebee261465d.js 1.19 KiB styles.ef46db3751d8e999.css 0 bytes
|
||||
chunk (runtime: runtime) main.623d91691bdb6754.css, main.94f9a4a3cec4f056.js (main) 145 KiB (javascript) 50 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) polyfills.bd0d0abec287a28e.js (polyfills) 301 KiB [initial] [rendered]
|
||||
chunk (runtime: runtime) styles.ef46db3751d8e999.css (styles) 50 bytes (javascript) 80 bytes (css/mini-extract) [initial] [rendered]
|
||||
chunk (runtime: runtime) runtime.54e36ebee261465d.js (runtime) 3.23 KiB [entry] [rendered]
|
||||
webpack compiled successfully (06e95dfdacea84c7)
|
||||
|
||||
———————————————————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
> NX Successfully ran target build for project store and 1 task(s) it depends on (5s)
|
||||
```
|
||||
|
||||
Notice the line here:
|
||||
|
||||
```plain
|
||||
✔ 1/1 dependent project tasks succeeded [0 read from cache]
|
||||
```
|
||||
|
||||
This is because your `store` project depends on your `products` project, which also has a `build` target. By default Nx is configured to run the `build` target for any dependencies that have a `build` target, before running the `build` on the original project.
|
||||
|
||||
This feature allows the Nx graph to dynamically maintain task dependencies, rather than having to manually maintain those task dependencies as your workspace continues to grow.
|
||||
|
||||
{% 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" /%}
|
||||
|
||||
## What's Next
|
||||
|
||||
- Continue to [5: Summary](/react-tutorial/5-summary)
|
||||
26
docs/shared/react-tutorial/5-summary.md
Normal file
@ -0,0 +1,26 @@
|
||||
# React 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="Free Nx Course on YouTube" description="Follow up this tutorial with our free Nx Course." type="video" url="https://www.youtube.com/playlist?list=PLakNactNC1dH38AfqmwabvOszDmKriGco" /%}
|
||||
|
||||
{% card title="Free Nx Course From Egghead" type="external" description="Follow up this tutorial with a free course on React development with Nx we made in collaboration with Egghead." url="https://egghead.io/courses/scale-react-development-with-nx-4038" /%}
|
||||
|
||||
{% card title="Core Features" description="Learn more about the Core Features of Nx." url="/core-features" /%}
|
||||
|
||||
{% card title="The Nx Mental Model" description="Expand your Mental Model of Nx." url="/concepts/mental-model" /%}
|
||||
|
||||
{% card title="Distributed Task Execution" description="Learn how to use Nx Cloud for Distributed Task Execution to speed up your CI times even more." url="/concepts/dte" /%}
|
||||
|
||||
{% card title="Configure CI For Your Workspace" description="Learn how to create CI configuration for your workspace using our ci-workflow generator, or by creating your own workflow." url="/recipes/ci-setup" /%}
|
||||
|
||||
{% /cards %}
|
||||
BIN
docs/shared/react-tutorial/generator-syntax.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
docs/shared/react-tutorial/initial-project-graph.png
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
docs/shared/react-tutorial/matching-graph.png
Normal file
|
After Width: | Height: | Size: 213 KiB |
BIN
docs/shared/react-tutorial/project-graph-with-affected.png
Normal file
|
After Width: | Height: | Size: 294 KiB |
BIN
docs/shared/react-tutorial/requirements-diagram.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/shared/react-tutorial/run-target-syntax.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
@ -54,8 +54,8 @@ module.exports = withNx({
|
||||
permanent: true,
|
||||
});
|
||||
rules.push({
|
||||
source: '/(l|latest)/(n|node)/tutorial/01-create-application',
|
||||
destination: '/node-tutorial/01-create-application',
|
||||
source: '/(l|latest)/(n|node)/tutorial/1-code-generation',
|
||||
destination: '/node-tutorial/1-code-generation',
|
||||
permanent: true,
|
||||
});
|
||||
|
||||
|
||||
@ -1046,11 +1046,11 @@ function pointToTutorialAndCourse(preset: Preset) {
|
||||
bodyLines: [`https://nx.dev/angular-tutorial/01-create-application`],
|
||||
});
|
||||
break;
|
||||
case Preset.Nest:
|
||||
case Preset.Express:
|
||||
output.addVerticalSeparator();
|
||||
output.note({
|
||||
title,
|
||||
bodyLines: [`https://nx.dev/node-tutorial/01-create-application`],
|
||||
bodyLines: [`https://nx.dev/node-tutorial/1-code-generation`],
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||