docs(core): update angular monorepo tutorial

This commit is contained in:
Isaac Mann 2023-09-19 11:16:55 -04:00 committed by Juri Strumpflohner
parent 1024a77ef6
commit 6f754db84d
20 changed files with 50 additions and 960 deletions

View File

@ -528,95 +528,6 @@
"children": [],
"disableCollapsible": false
},
{
"name": "Angular Monorepo Tutorial",
"path": "/angular-tutorial",
"id": "angular-tutorial",
"isExternal": false,
"children": [
{
"name": "1 - Code Generation",
"path": "/angular-tutorial/1-code-generation",
"id": "1-code-generation",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "2 - Project Graph",
"path": "/angular-tutorial/2-project-graph",
"id": "2-project-graph",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "3 - Task Running",
"path": "/angular-tutorial/3-task-running",
"id": "3-task-running",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "4 - Workspace Optimization",
"path": "/angular-tutorial/4-workspace-optimization",
"id": "4-workspace-optimization",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "5 - Summary",
"path": "/angular-tutorial/5-summary",
"id": "5-summary",
"isExternal": false,
"children": [],
"disableCollapsible": false
}
],
"disableCollapsible": false
},
{
"name": "1 - Code Generation",
"path": "/angular-tutorial/1-code-generation",
"id": "1-code-generation",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "2 - Project Graph",
"path": "/angular-tutorial/2-project-graph",
"id": "2-project-graph",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "3 - Task Running",
"path": "/angular-tutorial/3-task-running",
"id": "3-task-running",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "4 - Workspace Optimization",
"path": "/angular-tutorial/4-workspace-optimization",
"id": "4-workspace-optimization",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "5 - Summary",
"path": "/angular-tutorial/5-summary",
"id": "5-summary",
"isExternal": false,
"children": [],
"disableCollapsible": false
},
{
"name": "Angular Standalone Tutorial",
"path": "/angular-standalone-tutorial",

View File

@ -655,117 +655,6 @@
"path": "/react-standalone-tutorial/5-summary",
"tags": []
},
"/angular-tutorial": {
"id": "angular-tutorial",
"name": "Angular Monorepo Tutorial",
"description": "Learn to use Nx with this Angular tutorial where you will learn about all its main feature with a real project.",
"file": "",
"itemList": [
{
"id": "1-code-generation",
"name": "1 - Code Generation",
"description": "",
"file": "shared/angular-tutorial/1-code-generation",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/1-code-generation",
"tags": []
},
{
"id": "2-project-graph",
"name": "2 - Project Graph",
"description": "",
"file": "shared/angular-tutorial/2-project-graph",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/2-project-graph",
"tags": []
},
{
"id": "3-task-running",
"name": "3 - Task Running",
"description": "",
"file": "shared/angular-tutorial/3-task-running",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/3-task-running",
"tags": []
},
{
"id": "4-workspace-optimization",
"name": "4 - Workspace Optimization",
"description": "",
"file": "shared/angular-tutorial/4-workspace-optimization",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/4-workspace-optimization",
"tags": []
},
{
"id": "5-summary",
"name": "5 - Summary",
"description": "",
"file": "shared/angular-tutorial/5-summary",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/5-summary",
"tags": []
}
],
"isExternal": false,
"path": "/angular-tutorial",
"tags": []
},
"/angular-tutorial/1-code-generation": {
"id": "1-code-generation",
"name": "1 - Code Generation",
"description": "",
"file": "shared/angular-tutorial/1-code-generation",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/1-code-generation",
"tags": []
},
"/angular-tutorial/2-project-graph": {
"id": "2-project-graph",
"name": "2 - Project Graph",
"description": "",
"file": "shared/angular-tutorial/2-project-graph",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/2-project-graph",
"tags": []
},
"/angular-tutorial/3-task-running": {
"id": "3-task-running",
"name": "3 - Task Running",
"description": "",
"file": "shared/angular-tutorial/3-task-running",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/3-task-running",
"tags": []
},
"/angular-tutorial/4-workspace-optimization": {
"id": "4-workspace-optimization",
"name": "4 - Workspace Optimization",
"description": "",
"file": "shared/angular-tutorial/4-workspace-optimization",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/4-workspace-optimization",
"tags": []
},
"/angular-tutorial/5-summary": {
"id": "5-summary",
"name": "5 - Summary",
"description": "",
"file": "shared/angular-tutorial/5-summary",
"itemList": [],
"isExternal": false,
"path": "/angular-tutorial/5-summary",
"tags": []
},
"/angular-standalone-tutorial": {
"id": "angular-standalone-tutorial",
"name": "Angular Standalone Tutorial",

View File

@ -173,38 +173,6 @@
}
]
},
{
"name": "Angular Monorepo Tutorial",
"id": "angular-tutorial",
"description": "Learn to use Nx with this Angular tutorial where you will learn about all its main feature with a real project.",
"itemList": [
{
"name": "1 - Code Generation",
"id": "1-code-generation",
"file": "shared/angular-tutorial/1-code-generation"
},
{
"name": "2 - Project Graph",
"id": "2-project-graph",
"file": "shared/angular-tutorial/2-project-graph"
},
{
"name": "3 - Task Running",
"id": "3-task-running",
"file": "shared/angular-tutorial/3-task-running"
},
{
"name": "4 - Workspace Optimization",
"id": "4-workspace-optimization",
"file": "shared/angular-tutorial/4-workspace-optimization"
},
{
"name": "5 - Summary",
"id": "5-summary",
"file": "shared/angular-tutorial/5-summary"
}
]
},
{
"name": "Angular Standalone Tutorial",
"id": "angular-standalone-tutorial",

View File

@ -1,151 +0,0 @@
---
title: 'Angular Monorepo 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 %}
# Angular Monorepo Tutorial - Part 1: Code Generation
## Contents
- [1 - Code Generation](/angular-tutorial/1-code-generation)
- [2 - Project Graph](/angular-tutorial/2-project-graph)
- [3 - Task Running](/angular-tutorial/3-task-running)
- [4 - Workspace Optimization](/angular-tutorial/4-workspace-optimization)
- [5 - Summary](/angular-tutorial/5-summary)
## Your Objective
For this tutorial, you'll create two Angular applications, an Angular lib for your common components, and a library for your business logic as follows:
![Our Workspace Requirements](/shared/angular-tutorial/requirements-diagram.svg)
## Creating an Nx Workspace
Run the command `npx create-nx-workspace@latest` and when prompted, provide the following responses:
```{% command="npx create-nx-workspace@latest" path="~" %}
> NX Let's create a new workspace [https://nx.dev/getting-started/intro]
✔ Where would you like to create your workspace? · myorg
✔ Which stack do you want to use? · angular
✔ Standalone project or integrated monorepo? · integrated
✔ Application name · store
✔ Default stylesheet format · css
✔ Would you like to use Standalone Components in your application? · No
✔ Would you like to add routing? · Yes
✔ Enable distributed caching to make your CI faster · Yes
```
{% card title="Opting into Nx Cloud" description="You will also be prompted whether to add Nx Cloud to your workspace. We won't address this in this tutorial, but you can see the introduction to Nx Cloud for more details." url="/nx-cloud/intro/what-is-nx-cloud" /%}
Once the command completes, notice two projects were added to the workspace:
- An Angular 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 @nx/cypress package page." url="/packages/cypress" /%}
## Adding Another Application to Your Workspace
Run this command to create your `admin` app:
```{% command="npx nx g @nx/angular:app admin --directory=apps/admin" path="~/myorg" %}
npx nx g @nx/angular:app admin --directory=apps/admin
> NX Generating @nx/angular:application
✔ Would you like to configure routing for this application? (y/N) · false
[NX] Angular devkit called `writeWorkspace`, this may have created 'workspace.json' or 'angular.json
[NX] Double check workspace configuration before proceeding
Skipping admin since apps/admin/project.json already exists.
CREATE apps/admin/tsconfig.app.json
CREATE apps/admin/tsconfig.spec.json
CREATE apps/admin/src/favicon.ico
CREATE apps/admin/src/index.html
CREATE apps/admin/src/main.ts
CREATE apps/admin/src/styles.css
CREATE apps/admin/src/assets/.gitkeep
CREATE apps/admin/src/app/app.module.ts
CREATE apps/admin/src/app/app.component.css
CREATE apps/admin/src/app/app.component.html
CREATE apps/admin/src/app/app.component.spec.ts
CREATE apps/admin/src/app/app.component.ts
CREATE apps/admin/project.json
CREATE apps/admin/tsconfig.editor.json
CREATE apps/admin/tsconfig.json
CREATE apps/admin/src/app/nx-welcome.component.ts
CREATE apps/admin/.eslintrc.json
CREATE apps/admin/jest.config.ts
CREATE apps/admin/src/test-setup.ts
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
```
![Nx Generator Syntax](/shared/angular-tutorial/generator-syntax.svg)
## Generating Libraries
To create the `common-ui` and `products` libraries, use the `@nx/angular:lib` and `@nx/js:lib` generators respectively:
```{% command="npx nx g @nx/angular:lib common-ui --directory=libs/common-ui" path="~/myorg" %}
> NX Generating @nx/angular:library
[NX] Angular devkit called `writeWorkspace`, this may have created 'workspace.json' or 'angular.json
[NX] Double check workspace configuration before proceeding
Skipping common-ui since libs/common-ui/project.json already exists.
CREATE libs/common-ui/README.md
CREATE libs/common-ui/tsconfig.lib.json
CREATE libs/common-ui/tsconfig.spec.json
CREATE libs/common-ui/src/index.ts
CREATE libs/common-ui/src/lib/common-ui.module.ts
CREATE libs/common-ui/project.json
CREATE libs/common-ui/tsconfig.json
UPDATE tsconfig.base.json
CREATE libs/common-ui/jest.config.ts
CREATE libs/common-ui/src/test-setup.ts
CREATE libs/common-ui/.eslintrc.json
```
```{% command="npx nx g @nx/js:lib products --directory=libs/products" path="~/myorg" %}
> NX Generating @nx/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/project.json
UPDATE tsconfig.base.json
CREATE libs/products/.eslintrc.json
CREATE libs/products/jest.config.ts
CREATE libs/products/tsconfig.spec.json
```
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](/angular-tutorial/2-project-graph)

View File

@ -1,157 +0,0 @@
# Angular Monorepo Tutorial - Part 2: Project Graph
Run the command: `npx nx graph`. A browser should open up with the following contents:
![Initial Project Graph](/shared/angular-tutorial/initial-project-graph.png)
This is still different than the design from the start of Part 1:
![Our Workspace Requirements](/shared/angular-tutorial/requirements-diagram.svg)
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 `@nx/angular:component` generator with the command:
```{% command="npx nx g @nx/angular:component banner --project=common-ui --export" path="~/myorg" %}
> NX Generating @nx/angular:component
CREATE libs/common-ui/src/lib/banner/banner.component.css
CREATE libs/common-ui/src/lib/banner/banner.component.html
CREATE libs/common-ui/src/lib/banner/banner.component.spec.ts
CREATE libs/common-ui/src/lib/banner/banner.component.ts
UPDATE libs/common-ui/src/lib/common-ui.module.ts
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.component.ts" %}
import { Component, Input } from '@angular/core';
@Component({
selector: 'myorg-banner',
template: `<header>{{ title }}</header>`,
styleUrls: ['./banner.component.css'],
})
export class BannerComponent {
@Input() title = '';
}
```
### `admin`
Add the `Banner` component to the admin app:
```javascript {% fileName="apps/admin/src/app/app.component.ts" %}
import { Component } from '@angular/core';
@Component({
selector: 'myorg-root',
template: `
<myorg-banner title="Welcome to our admin app."> </myorg-banner>
`,
})
export class AppComponent {}
```
```javascript {% fileName="apps/admin/src/app/app.module.ts" %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonUiModule } from '@myorg/common-ui';
import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
@NgModule({
declarations: [AppComponent, NxWelcomeComponent],
imports: [BrowserModule, CommonUiModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
```
### `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.component.ts" %}
import { exampleProducts } from '@myorg/products';
import { Component } from '@angular/core';
@Component({
selector: 'myorg-root',
template: `
<myorg-banner title="Welcome to the store!"> </myorg-banner>
<ul>
<li *ngFor="let product of products">
<strong>{{ product.name }}</strong> Price: {{ product.price }}
</li>
</ul>
`,
})
export class AppComponent {
products = exampleProducts;
}
```
```javascript {% fileName="apps/store/src/app/app.module.ts" %}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CommonUiModule } from '@myorg/common-ui';
import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
@NgModule({
declarations: [AppComponent, NxWelcomeComponent],
imports: [BrowserModule, CommonUiModule],
providers: [],
bootstrap: [AppComponent],
})
export class AppModule {}
```
Now run `npx nx graph` again:
{% side-by-side %}
![Matching Graph](/shared/angular-tutorial/matching-graph.png)
![Our Workspace Requirements](/shared/angular-tutorial/requirements-diagram.svg)
{% /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](/angular-tutorial/4-workspace-optimization).
## What's Next
- Continue to [3: Task Running](/angular-tutorial/3-task-running)

View File

@ -1,101 +0,0 @@
# Angular Monorepo Tutorial - 3: Task-Running
Common tasks include:
- Building an application
- Serving a local web server with the built project
- Running your unit tests
- Linting your code
- Running e2e tests
When you ran your generators in Part 1, you already set up these common tasks for each project.
## Defining Targets
Here's the `project.json` file for your `common-ui` project:
```json {% fileName="libs/common-ui/project.json" %}
{
"name": "common-ui",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "library",
"sourceRoot": "libs/common-ui/src",
"prefix": "myorg",
"targets": {
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/common-ui/jest.config.ts",
"passWithNoTests": true
}
},
"lint": {
"executor": "@nx/linter:eslint",
"options": {
"lintFilePatterns": [
"libs/common-ui/**/*.ts",
"libs/common-ui/**/*.html"
]
}
}
},
"tags": []
}
```
You can see that two targets are defined here: `test` and `lint`.
The properties inside each of 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](/angular-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
![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg)
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/banner/banner.component.spec.ts
BannerComponent
✓ should create (22 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.192 s
Ran all test suites.
————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target test for project common-ui (4s)
```
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 (1s)
```
## What's Next
- Continue to [4: Workspace Optimization](/angular-tutorial/4-workspace-optimization)

View File

@ -1,216 +0,0 @@
# Angular Monorepo 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:
```shell
git add . ; git commit -m "commiting to test affected"
```
Then make a change to the styles of your `common-ui` project:
```css {% fileName="libs/common-ui/src/lib/banner/banner.component.css" %}
header {
color: 'blue;';
}
```
You can visualize how our workspace is affected by this change using the command:
```shell
npx nx affected:graph
```
![Project Graph with Affected](/shared/angular-tutorial/project-graph-with-affected.png)
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:
```shell
npx nx affected -t test
```
This can be particularly helpful in CI pipelines for larger repos, where most commits only affect a small subset of the entire workspace.
{% card title="Affected Documentation" description="Checkout Affected documentation for more details" url="/packages/nx/documents/affected" /%}
{% callout type="warning" title="Not too fast!" %}
Running this at this stage may result in some runtime errors being logged to the terminal.
The apps that use `<myorg-banner></myorg-banner>` wil need to have the `TestBed.configureTestingModule` in their `app.component.spec.ts` file updated to import `CommonUiModule`.
{% /callout %}
## 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
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": "@nx/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": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/products/**/*.ts"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"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
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.
Initial Chunk Files | Names | Raw Size | Estimated Transfer Size
main.b937601e1488b89e.js | main | 86.65 kB | 25.97 kB
polyfills.0b28149b40699473.js | polyfills | 33.04 kB | 10.61 kB
runtime.f826166b3c370f7e.js | runtime | 888 bytes | 512 bytes
styles.ef46db3751d8e999.css | styles | 0 bytes | -
| Initial Total | 120.55 kB | 37.08 kB
Build at: 2022-11-23T22:51:54.223Z - Hash: c67a92dd8266dfbe - Time: 7877ms
————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for project admin (11s)
```
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:
```shell
rm -rf dist
```
And run the command again:
```{% command="npx nx build admin" path="~/myorg" %}
> nx run admin:build:production [local cache]
Initial Chunk Files | Names | Raw Size | Estimated Transfer Size
main.b937601e1488b89e.js | main | 86.65 kB | 25.97 kB
polyfills.0b28149b40699473.js | polyfills | 33.04 kB | 10.61 kB
runtime.f826166b3c370f7e.js | runtime | 888 bytes | 512 bytes
styles.ef46db3751d8e999.css | styles | 0 bytes | -
| Initial Total | 120.55 kB | 37.08 kB
Build at: 2022-11-23T22:51:54.223Z - Hash: c67a92dd8266dfbe - Time: 7877ms
————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for project admin (37ms)
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
✔ Browser application bundle generation complete.
✔ Copying assets complete.
✔ Index html generation complete.
Initial Chunk Files | Names | Raw Size | Estimated Transfer Size
main.5995a14e3c34a711.js | main | 101.39 kB | 29.83 kB
polyfills.19459ef8805e51da.js | polyfills | 33.04 kB | 10.64 kB
runtime.5d40e95cc0c0e0d1.js | runtime | 888 bytes | 512 bytes
styles.ef46db3751d8e999.css | styles | 0 bytes | -
| Initial Total | 135.29 kB | 40.97 kB
Build at: 2022-11-23T22:53:29.097Z - Hash: 3cd478c78ebeead2 - Time: 5154ms
————————————————————————————————————————————————————————————————————————————————————————————————
> NX Successfully ran target build for project store and 1 task(s) they depend on (8s)
```
Notice the line here:
```text
✔ 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](/angular-tutorial/5-summary)

View File

@ -1,22 +0,0 @@
# Angular Monorepo Tutorial - Part 5: Summary
In this tutorial you:
- Learned how to use Nx's Generators to generate code for your workspace.
- Learned how Nx determines a graph of your workspace
- Learned how to configure and run tasks in your workspace
- Learned how Nx's built-in optimizations work, and how to apply those to your own workspace
## Learn More
{% cards %}
{% card title="Core Features" description="Read about the core features of Nx." url="/core-features" /%}
{% card title="Plugin Features" description="Read about the plugin features of Nx." url="/core-features/plugin-features" /%}
{% card title="Mental Model" description="Get a deeper understanding of the mental model." url="/concepts/mental-model" /%}
{% card title="Adopting Nx" description="Learn how to add Nx to your existing repo." url="/recipes/adopting-nx" /%}
{% /cards %}

View File

@ -18,22 +18,17 @@ What are you going to learn?
Note, this tutorial sets up a repo with applications and libraries in their own subfolders. If you are looking for an Angular standalone app setup then check out our [Angular standalone app tutorial](/getting-started/tutorials/angular-standalone-tutorial).
{% /callout %}
## Why Use an Integrated Monorepo?
## Nx CLI vs. Angular CLI
An integrated monorepo is a repository configured with a set of features that work together toward the goal of allowing developers to focus on building features rather than the configuration, coordination and maintenance of the tooling in the repo.
Nx evolved from being an extension of the Angular CLI to a [fully standalone CLI working with multiple frameworks](/getting-started/why-nx#how-does-nx-work). As a result, adopting Nx as an Angular user is relatively straightforward. Your existing code, including builders and schematics, will still work as before, but you'll also have access to all the benefits Nx offers.
You'll notice that instead of using npm/yarn/pnpm workspaces, projects within the repository are linked using typescript path aliases that are defined in the `tsconfig.base.json` file. Also, since we're creating projects using Nx plugin generators, all new projects come preconfigured with useful tools like Prettier, ESLint and Jest.
Advantages of Nx over the Angular CLI:
Nx Plugins are optional packages that extend the capabilities of Nx, catering to various specific technologies. For instance, we have plugins tailored to Angular (e.g., `@nx/angular`), Vite (`@nx/vite`), Cypress (`@nx/cypress`), and more. These plugins offer additional features, making your development experience more efficient and enjoyable when working with specific tech stacks.
- [Split a large angular.json into multiple project.json files](/concepts/more-concepts/nx-and-angular#projectjson-vs-angularjson)
- [Integrate with modern tools](/concepts/more-concepts/nx-and-angular#integrating-with-modern-tools)
- [Controllable update process](/concepts/more-concepts/nx-and-angular#ng-update-vs-nx-migrate)
Features of an integrated monorepo:
- [Install dependencies at the root by default](/concepts/more-concepts/dependency-management#single-version-policy)
- [Scaffold new code with generators](/core-features/plugin-features/use-code-generators)
- [Run tasks with executors](/core-features/plugin-features/use-task-executors)
- [Updates dependencies with automated migrations](/core-features/automate-updating-dependencies)
Visit our ["Why Nx" page](/getting-started/why-nx) for more details.
Visit our ["Nx and the Angular CLI" page](/concepts/more-concepts/nx-and-angular) for more details.
## Warm Up
@ -403,9 +398,18 @@ Make sure the `ProductListComponent` is exported via the `index.ts` file of our
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProductListComponent } from './product-list/product-list.component';
import { RouterModule } from '@angular/router';
@NgModule({
imports: [CommonModule],
imports: [
CommonModule,
RouterModule.forChild([
{
path: '',
component: ProductListComponent,
},
]),
],
declarations: [ProductListComponent],
exports: [ProductListComponent],
})
@ -453,15 +457,15 @@ export const appRoutes: Route[] = [
},
{
path: 'products',
loadComponent: () =>
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
loadChildren: () =>
import('@angular-monorepo/products').then((m) => m.ProductsModule),
},
];
```
Serving your app (`nx serve angular-store`) and then navigating to `/products` should give you the following result:
![products route](/shared/images/tutorial-angular-standalone/app-products-route.png)
![products route](/shared/angular-tutorial/app-products-route.png)
Let's apply the same for our `orders` library.
@ -482,13 +486,13 @@ export const appRoutes: Route[] = [
},
{
path: 'products',
loadComponent: () =>
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
loadChildren: () =>
import('@angular-monorepo/products').then((m) => m.ProductsModule),
},
{
path: 'orders',
loadComponent: () =>
import('@angular-monorepo/orders').then((m) => m.OrderListComponent),
loadChildren: () =>
import('@angular-monorepo/orders').then((m) => m.OrdersModule),
},
];
```
@ -635,7 +639,7 @@ nx e2e angular-store-e2e # runs e2e tests for the angular-store
More conveniently, we can also run tasks in parallel using the following syntax:
```shell
nx run-many -t test
nx run-many -t test lint e2e
```
### Caching
@ -937,12 +941,21 @@ To test it, go to your `libs/products/src/lib/products.module.ts` file and impor
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProductListComponent } from './product-list/product-list.component';
import { RouterModule } from '@angular/router';
// This import is not allowed 👇
import { OrderListComponent } from '@angular-monorepo/orders';
@NgModule({
imports: [CommonModule],
imports: [
CommonModule,
RouterModule.forChild([
{
path: '',
component: ProductListComponent,
},
]),
],
declarations: [ProductListComponent],
exports: [ProductListComponent],
})
@ -986,7 +999,7 @@ If you lint your workspace you'll get an error now:
If you have the ESLint plugin installed in your IDE you should immediately see an error:
![ESLint module boundary error](/shared/images/tutorial-angular-standalone/angular-standalone-module-boundaries.png)
![ESLint module boundary error](/shared/angular-tutorial/module-boundary-lint-rule.png)
Learn more about how to [enforce module boundaries](/core-features/enforce-module-boundaries).
@ -1018,6 +1031,7 @@ This will create a default CI configuration that sets up Nx Cloud to [use distri
Here's some more things you can dive into next:
- Read more about [how Nx compares to the Angular CLI](/concepts/more-concepts/nx-and-angular)
- Learn more about the [underlying mental model of Nx](/concepts/mental-model)
- Learn about popular generators such as [how to setup Tailwind](/recipes/angular/using-tailwind-css-with-angular-projects)
- Learn how to [migrate your existing Angular CLI repo to Nx](/recipes/angular/migration/angular)
@ -1028,7 +1042,7 @@ Here's some more things you can dive into next:
Also, make sure you
- [Join the Nx community Slack](https://go.nrwl.io/join-slack) to ask questions and find out the latest news about Nx.
- [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx.
- [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news
- [Read our Nx blog](https://blog.nrwl.io/)
- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 294 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@ -1033,7 +1033,7 @@ Here's some more things you can dive into next:
Also, make sure you
- [Join the Nx community Slack](https://go.nrwl.io/join-slack) to ask questions and find out the latest news about Nx.
- [Join the Official Nx Discord Server](https://go.nx.dev/community) to ask questions and find out the latest news about Nx.
- [Follow Nx on Twitter](https://twitter.com/nxdevtools) to stay up to date with Nx news
- [Read our Nx blog](https://blog.nrwl.io/)
- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights

View File

@ -31,12 +31,6 @@
- [3 - Task Running](/react-standalone-tutorial/3-task-running)
- [4 - Task Pipelines](/react-standalone-tutorial/4-task-pipelines)
- [5 - Summary](/react-standalone-tutorial/5-summary)
- [Angular Monorepo Tutorial](/angular-tutorial)
- [1 - Code Generation](/angular-tutorial/1-code-generation)
- [2 - Project Graph](/angular-tutorial/2-project-graph)
- [3 - Task Running](/angular-tutorial/3-task-running)
- [4 - Workspace Optimization](/angular-tutorial/4-workspace-optimization)
- [5 - Summary](/angular-tutorial/5-summary)
- [Angular Standalone Tutorial](/angular-standalone-tutorial)
- [1 - Code Generation](/angular-standalone-tutorial/1-code-generation)
- [2 - Project Graph](/angular-standalone-tutorial/2-project-graph)

View File

@ -680,6 +680,17 @@ const nested5minuteTutorialUrls = {
'/getting-started/tutorials/angular-standalone-tutorial',
'/tutorials/node-server-tutorial':
'/getting-started/tutorials/node-server-tutorial',
'/angular-tutorial': '/getting-started/tutorials/angular-monorepo-tutorial',
'/angular-tutorial/1-code-generation':
'/getting-started/tutorials/angular-monorepo-tutorial',
'/angular-tutorial/2-project-graph':
'/getting-started/tutorials/angular-monorepo-tutorial',
'/angular-tutorial/3-task-running':
'/getting-started/tutorials/angular-monorepo-tutorial',
'/angular-tutorial/4-workspace-optimization':
'/getting-started/tutorials/angular-monorepo-tutorial',
'/angular-tutorial/5-summary':
'/getting-started/tutorials/angular-monorepo-tutorial',
};
const pluginUrls = {