diff --git a/docs/blog/2022-10-14-whats-new-in-nx-15.md b/docs/blog/2022-10-14-whats-new-in-nx-15.md index cff4a875d6..6088caf669 100644 --- a/docs/blog/2022-10-14-whats-new-in-nx-15.md +++ b/docs/blog/2022-10-14-whats-new-in-nx-15.md @@ -50,8 +50,8 @@ There will be more content around choosing which style and even how to mix the t We also updated our docs to have two super short tutorials that illustrate the two approaches: -- [/tutorials/1-ts-packages/1t-introduction/1-welcome](/tutorials/1-ts-packages/1t-introduction/1-welcome) -- [/tutorials/2-react-monorepo/1r-introduction/1-welcome](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +- [/getting-started/tutorials/typescript-packages-tutorial](/getting-started/tutorials/typescript-packages-tutorial) +- [/getting-started/tutorials/react-monorepo-tutorial](/getting-started/tutorials/react-monorepo-tutorial) You can also read more about the concept here: [/deprecated/integrated-vs-package-based](/deprecated/integrated-vs-package-based) @@ -179,9 +179,9 @@ It is an ongoing process, and we have a lot of content to cover! We follow the [ - you want to learn something new ("Tutorial" section) or - you want a solution to a specific problem ("Recipes" section). -Besides the two new [package-based](/tutorials/1-ts-packages/1t-introduction/1-welcome) and [integrated style tutorials](/tutorials/2-react-monorepo/1r-introduction/1-welcome) we also have two brand new reworked tutorials +Besides the two new [package-based](/getting-started/tutorials/typescript-packages-tutorial) and [integrated style tutorials](/getting-started/tutorials/react-monorepo-tutorial) we also have two brand new reworked tutorials -- [/tutorials](/tutorials) +- [/getting-started/tutorials](/getting-started/tutorials) Stay tuned for more updates to come. diff --git a/docs/blog/2023-02-09-setup-react-and-tailwind-the-easy-way.md b/docs/blog/2023-02-09-setup-react-and-tailwind-the-easy-way.md index 9f3a5eae0f..7a8fb1af4f 100644 --- a/docs/blog/2023-02-09-setup-react-and-tailwind-the-easy-way.md +++ b/docs/blog/2023-02-09-setup-react-and-tailwind-the-easy-way.md @@ -59,7 +59,7 @@ You can pass `--vite=false` if you still want to keep the Webpack configuration ## Generating a Tailwind Setup -Once you have a [Nx-based React](/tutorials/2-react-monorepo/1r-introduction/1-welcome) setup, adding Tailwind is as easy as running: +Once you have a [Nx-based React](/getting-started/tutorials/react-monorepo-tutorial) setup, adding Tailwind is as easy as running: ```shell $ npx nx g @nrwl/react:setup-tailwind @@ -79,7 +79,7 @@ You'll get You should be all setup and ready now! Here are some related resources to explore: -- [Nx docs: React Monorepo tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +- [Nx docs: React Monorepo tutorial](/getting-started/tutorials/react-monorepo-tutorial) - [Youtube: Is CRA Dead](https://youtu.be/fkTz6KJxhhE) - [Nx docs: Migrate CRA to React and Vite](/recipes/adopting-nx/adding-to-existing-project) diff --git a/docs/blog/2023-08-10-create-your-own-create-react-app-cli.md b/docs/blog/2023-08-10-create-your-own-create-react-app-cli.md index c5aa6c2f32..6b1cbeb4a2 100644 --- a/docs/blog/2023-08-10-create-your-own-create-react-app-cli.md +++ b/docs/blog/2023-08-10-create-your-own-create-react-app-cli.md @@ -636,7 +636,7 @@ This should give you a good insight into how to get started. But there's more to - We could also include "[executors](/extending-nx/recipes/local-executors)", which are wrappers around tasks to abstract the lower-level details of it - etc. -Now clearly this was a simple example of how you could build your own CRA using Nx. If you want to see a real-world React setup powered by Nx, check out our React Tutorial: [/tutorials/2-react-monorepo/1r-introduction/1-welcome](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +Now clearly this was a simple example of how you could build your own CRA using Nx. If you want to see a real-world React setup powered by Nx, check out our React Tutorial: [/getting-started/tutorials/react-monorepo-tutorial](/getting-started/tutorials/react-monorepo-tutorial) ## Learn more diff --git a/docs/blog/2023-10-13-nx-conf-2023-recap.md b/docs/blog/2023-10-13-nx-conf-2023-recap.md index 0c096e6ab1..ffb55a6ac1 100644 --- a/docs/blog/2023-10-13-nx-conf-2023-recap.md +++ b/docs/blog/2023-10-13-nx-conf-2023-recap.md @@ -26,7 +26,7 @@ Juri also dives deeper into efforts from the team to provide high quality educat ![](/blog/images/2023-10-13/bodyimg2.webp) -This makes it easier to find keep the content organized and focused and makes it easier for the reader to choose between solution-oriented [recipes](/recipes) vs learning-oriented [tutorials](/tutorials). +This makes it easier to find keep the content organized and focused and makes it easier for the reader to choose between solution-oriented [recipes](/recipes) vs learning-oriented [tutorials](/getting-started/tutorials). The Nx team not only produces written content, but also video content mainly on the [Nx YouTube Channel](https://www.youtube.com/@nxdevtools). Juri shows some of the growth stats, with the channel now having more than 14k subscribers and around 3.7k hours of watch time per month. The channel serves mostly short-form videos about new releases, highlighting new features as well as longer-form tutorial videos. diff --git a/docs/blog/2023-12-28-highlights-2023.md b/docs/blog/2023-12-28-highlights-2023.md index 99a3912cde..fea9ce50eb 100644 --- a/docs/blog/2023-12-28-highlights-2023.md +++ b/docs/blog/2023-12-28-highlights-2023.md @@ -315,7 +315,7 @@ We also poured a lot of [effort into the docs](/getting-started/intro). We restr - [**Concept docs**](/concepts) — which explain some of the inner workings and mental model behind certain features. Like [how caching works](/concepts/how-caching-works). - [**Recipes**](/recipes) — which are solution oriented. You already know how to cook, we provide the exact recipe for it. -- [**Tutorials**](/tutorials) — for when you just want to sit down and follow along, step by step to learn how to use Nx in a certain context. +- [**Tutorials**](/getting-started/tutorials) — for when you just want to sit down and follow along, step by step to learn how to use Nx in a certain context. - [**Reference**](/reference) and [**API docs**](/nx-api) — pure, raw and to the point. We created a brand new ["Why Nx"](/getting-started/why-nx) page explaining the overall architecture of Nx including a [brand new video](https://www.youtube.com/watch?v=-_4WMl-Fn0w) giving you a holistic overview of what Nx is capable of. diff --git a/docs/blog/2024-05-08-nx-19-release.md b/docs/blog/2024-05-08-nx-19-release.md index b395af8779..a46340cc16 100644 --- a/docs/blog/2024-05-08-nx-19-release.md +++ b/docs/blog/2024-05-08-nx-19-release.md @@ -52,7 +52,7 @@ Emily, the engineer that worked on this effort, posted an entire article where y Thanks to the benefits of Project Crystal - which allows us to determine information to create Nx Tasks based on the way your Gradle projects are setup - by adding this plugin, it makes it easy to add Gradle into an existing workspace without needing any Nx-specific configuration. -In addition, you can now find [a new tutorial on using Nx with Gradle](/tutorials/4-gradle/1g-introduction/1-welcome) which will expand on the [Spring framework](https://spring.io/)'s tutorial for multi-module projects and show you how Nx further enhances the developer experience of that workspace. This tutorial takes you all the way through setting up your CI pipeline with Nx Cloud, so be sure to check it out! +In addition, you can now find [a new tutorial on using Nx with Gradle](/getting-started/tutorials/gradle-tutorial) which will expand on the [Spring framework](https://spring.io/)'s tutorial for multi-module projects and show you how Nx further enhances the developer experience of that workspace. This tutorial takes you all the way through setting up your CI pipeline with Nx Cloud, so be sure to check it out! As an editorial note, this Gradle plugin is a big step for Nx, as it represents the first major step we're taking outside of the Javascript ecosystem. This has always been the goal: to robustly support monorepos and full-stack development, even across language and ecosystem barriers. We're using this Gradle plugin internally for our closed-sourced projects (in particular Nx Cloud) and in [Nx Console](https://github.com/nrwl/nx-console/blob/master/package.json#L74) and we're very proud of this plugin and all that it represents. diff --git a/docs/blog/2024-12-22-nx-highlights-2024.md b/docs/blog/2024-12-22-nx-highlights-2024.md index b0aad419d6..c70578cb3a 100644 --- a/docs/blog/2024-12-22-nx-highlights-2024.md +++ b/docs/blog/2024-12-22-nx-highlights-2024.md @@ -103,7 +103,7 @@ Gradle projects were traditionally tricky to manage alongside JavaScript librari **Composite Build Support** takes this further by pulling in dependencies from composite builds and reflecting them in the task graph. This release reflects our larger goal of breaking down barriers between ecosystems. Nx aims to enable efficient workflows across different languages and technologies, moving closer to a seamless polyglot monorepo experience. -For more details, check out the blog post ["Manage Your Gradle Project using Nx"](/blog/manage-your-gradle-project-using-nx) and our [Gradle tutorial](/tutorials/4-gradle/1g-introduction/1-welcome). +For more details, check out the blog post ["Manage Your Gradle Project using Nx"](/blog/manage-your-gradle-project-using-nx) and our [Gradle tutorial](/getting-started/tutorials/gradle-tutorial). ### Nx Import diff --git a/docs/generated/manifests/menus.json b/docs/generated/manifests/menus.json index a117664e15..0e2c21080e 100644 --- a/docs/generated/manifests/menus.json +++ b/docs/generated/manifests/menus.json @@ -42,39 +42,39 @@ }, { "name": "Tutorials", - "path": "/tutorials", + "path": "/getting-started/tutorials", "id": "tutorials", "isExternal": false, "children": [ { "name": "TypeScript Monorepo", - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "path": "/getting-started/tutorials/typescript-packages-tutorial", "id": "typescript-packages-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "React Monorepo", - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "path": "/getting-started/tutorials/react-monorepo-tutorial", "id": "react-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Angular Monorepo", - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "id": "angular-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Gradle Monorepo", - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "path": "/getting-started/tutorials/gradle-tutorial", "id": "gradle-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false } @@ -118,39 +118,39 @@ }, { "name": "Tutorials", - "path": "/tutorials", + "path": "/getting-started/tutorials", "id": "tutorials", "isExternal": false, "children": [ { "name": "TypeScript Monorepo", - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "path": "/getting-started/tutorials/typescript-packages-tutorial", "id": "typescript-packages-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "React Monorepo", - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "path": "/getting-started/tutorials/react-monorepo-tutorial", "id": "react-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Angular Monorepo", - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "id": "angular-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Gradle Monorepo", - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "path": "/getting-started/tutorials/gradle-tutorial", "id": "gradle-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false } @@ -159,33 +159,33 @@ }, { "name": "TypeScript Monorepo", - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "path": "/getting-started/tutorials/typescript-packages-tutorial", "id": "typescript-packages-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "React Monorepo", - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "path": "/getting-started/tutorials/react-monorepo-tutorial", "id": "react-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Angular Monorepo", - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "id": "angular-monorepo-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, { "name": "Gradle Monorepo", - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "path": "/getting-started/tutorials/gradle-tutorial", "id": "gradle-tutorial", - "isExternal": true, + "isExternal": false, "children": [], "disableCollapsible": false }, diff --git a/docs/generated/manifests/nx.json b/docs/generated/manifests/nx.json index 2a2b0b8cd5..993ba62429 100644 --- a/docs/generated/manifests/nx.json +++ b/docs/generated/manifests/nx.json @@ -62,10 +62,10 @@ "name": "TypeScript Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/typescript-packages", "itemList": [], - "isExternal": true, - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/typescript-packages-tutorial", "tags": [] }, { @@ -73,10 +73,10 @@ "name": "React Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/react-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/react-monorepo-tutorial", "tags": [] }, { @@ -84,10 +84,10 @@ "name": "Angular Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/angular-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "tags": [] }, { @@ -95,15 +95,15 @@ "name": "Gradle Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/gradle", "itemList": [], - "isExternal": true, - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/gradle-tutorial", "tags": [] } ], "isExternal": false, - "path": "/tutorials", + "path": "/getting-started/tutorials", "tags": [] } ], @@ -155,7 +155,7 @@ "path": "/getting-started/editor-setup", "tags": ["editor-setup"] }, - "/tutorials": { + "/getting-started/tutorials": { "id": "tutorials", "name": "Tutorials", "description": "Get started with basic information, concepts and tutorials.", @@ -167,10 +167,10 @@ "name": "TypeScript Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/typescript-packages", "itemList": [], - "isExternal": true, - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/typescript-packages-tutorial", "tags": [] }, { @@ -178,10 +178,10 @@ "name": "React Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/react-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/react-monorepo-tutorial", "tags": [] }, { @@ -189,10 +189,10 @@ "name": "Angular Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/angular-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "tags": [] }, { @@ -200,59 +200,59 @@ "name": "Gradle Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/gradle", "itemList": [], - "isExternal": true, - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/gradle-tutorial", "tags": [] } ], "isExternal": false, - "path": "/tutorials", + "path": "/getting-started/tutorials", "tags": [] }, - "/tutorials/1-ts-packages/1t-introduction/1-welcome": { + "/getting-started/tutorials/typescript-packages-tutorial": { "id": "typescript-packages-tutorial", "name": "TypeScript Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/typescript-packages", "itemList": [], - "isExternal": true, - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/typescript-packages-tutorial", "tags": [] }, - "/tutorials/2-react-monorepo/1r-introduction/1-welcome": { + "/getting-started/tutorials/react-monorepo-tutorial": { "id": "react-monorepo-tutorial", "name": "React Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/react-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/react-monorepo-tutorial", "tags": [] }, - "/tutorials/3-angular-monorepo/1a-introduction/1-welcome": { + "/getting-started/tutorials/angular-monorepo-tutorial": { "id": "angular-monorepo-tutorial", "name": "Angular Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/angular-monorepo", "itemList": [], - "isExternal": true, - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/angular-monorepo-tutorial", "tags": [] }, - "/tutorials/4-gradle/1g-introduction/1-welcome": { + "/getting-started/tutorials/gradle-tutorial": { "id": "gradle-tutorial", "name": "Gradle Monorepo", "description": "", "mediaImage": "", - "file": "", + "file": "shared/tutorials/gradle", "itemList": [], - "isExternal": true, - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", + "isExternal": false, + "path": "/getting-started/tutorials/gradle-tutorial", "tags": [] }, "/features": { diff --git a/docs/generated/packages/angular/documents/nx-and-angular.md b/docs/generated/packages/angular/documents/nx-and-angular.md index 54800c37db..7cf032e569 100644 --- a/docs/generated/packages/angular/documents/nx-and-angular.md +++ b/docs/generated/packages/angular/documents/nx-and-angular.md @@ -41,7 +41,7 @@ Here's a quick side-by-side overview comparing the features between the Angular | Advanced Generators (e.g. Module Federation, Tailwind,...) | ❌ | ✅ | | Integrated Tooling (Jest, Cypress, Playwright etc.) | ❌ | ✅ | | Support for single-project Workspaces | ✅ | ✅ | -| First-Class [Monorepo Support](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) | ❌\* | ✅ | +| First-Class [Monorepo Support](/getting-started/tutorials/angular-monorepo-tutorial) | ❌\* | ✅ | | [Enforced Module Boundaries](/features/enforce-module-boundaries) | ❌ | ✅ | | Interactive [Project Graph](/features/explore-graph) | ❌ | ✅ | | Task Graph | ❌ | ✅ | @@ -411,4 +411,4 @@ There is also a guide describing how to [consolidate multiple Angular CLI projec You can learn more about Angular & Nx by following our dedicated tutorials: -- [Tutorial: Building Angular Apps in an Nx Monorepo](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +- [Tutorial: Building Angular Apps in an Nx Monorepo](/getting-started/tutorials/angular-monorepo-tutorial) diff --git a/docs/generated/packages/angular/documents/overview.md b/docs/generated/packages/angular/documents/overview.md index 368cbcbf98..579abcea17 100644 --- a/docs/generated/packages/angular/documents/overview.md +++ b/docs/generated/packages/angular/documents/overview.md @@ -46,7 +46,7 @@ nx add @nx/angular This will install the correct version of `@nx/angular`. {% callout type="note" title="Angular Tutorial" %} -For a full tutorial experience, follow the [Angular Monorepo Tutorial](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +For a full tutorial experience, follow the [Angular Monorepo Tutorial](/getting-started/tutorials/angular-monorepo-tutorial) {% /callout %} ## Using the Angular Plugin @@ -113,7 +113,7 @@ nx g @nx/angular:service apps/appName/src/lib/my-service/my-service ## More Documentation -- [Angular Monorepo Tutorial](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +- [Angular Monorepo Tutorial](/getting-started/tutorials/angular-monorepo-tutorial) - [Migrating from the Angular CLI](/recipes/angular/migration/angular) - [Setup Module Federation with Angular and Nx](/concepts/module-federation/faster-builds-with-module-federation) - [Using Tailwind CSS with Angular projects](/recipes/angular/using-tailwind-css-with-angular-projects) diff --git a/docs/generated/packages/react/documents/overview.md b/docs/generated/packages/react/documents/overview.md index 7878bf2773..fa0e7372f6 100644 --- a/docs/generated/packages/react/documents/overview.md +++ b/docs/generated/packages/react/documents/overview.md @@ -19,7 +19,7 @@ It provides: To create a new workspace with React, run `npx create-nx-workspace@latest --preset=react-standalone`. {% callout type="note" title="React Tutorial" %} -For a full tutorial experience, follow the [React Monorepo Tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +For a full tutorial experience, follow the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) {% /callout %} ### Installation @@ -135,7 +135,7 @@ The library in `dist` is publishable to npm or a private registry. ## More Documentation -- [React Monorepo Tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +- [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) - [Using Cypress](/nx-api/cypress) - [Using Jest](/nx-api/jest) - [Using Storybook](/recipes/storybook/overview-react) diff --git a/docs/map.json b/docs/map.json index 58448dcf26..f5e51045c5 100644 --- a/docs/map.json +++ b/docs/map.json @@ -39,35 +39,26 @@ "name": "Tutorials", "id": "tutorials", "description": "Get started with basic information, concepts and tutorials.", - "path": "/tutorials", "itemList": [ { "name": "TypeScript Monorepo", "id": "typescript-packages-tutorial", - "file": "", - "path": "/tutorials/1-ts-packages/1t-introduction/1-welcome", - "isExternal": true + "file": "shared/tutorials/typescript-packages" }, { "name": "React Monorepo", "id": "react-monorepo-tutorial", - "file": "", - "path": "/tutorials/2-react-monorepo/1r-introduction/1-welcome", - "isExternal": true + "file": "shared/tutorials/react-monorepo" }, { "name": "Angular Monorepo", "id": "angular-monorepo-tutorial", - "file": "", - "path": "/tutorials/3-angular-monorepo/1a-introduction/1-welcome", - "isExternal": true + "file": "shared/tutorials/angular-monorepo" }, { "name": "Gradle Monorepo", "id": "gradle-tutorial", - "file": "", - "path": "/tutorials/4-gradle/1g-introduction/1-welcome", - "isExternal": true + "file": "shared/tutorials/gradle" } ] } diff --git a/docs/shared/deprecated/integrated-vs-package-based.md b/docs/shared/deprecated/integrated-vs-package-based.md index 4ec8423adf..1487585b34 100644 --- a/docs/shared/deprecated/integrated-vs-package-based.md +++ b/docs/shared/deprecated/integrated-vs-package-based.md @@ -36,7 +36,7 @@ Someone who appreciates the flexibility of a package-based repository will be mo - Easily create new projects or tools with [code generators](/features/generate-code) {% cards %} -{% card title="TypeScript Monorepo Tutorial" description="Add Nx to an existing TypeScript repo" type="documentation" url="/tutorials/1-ts-packages/1t-introduction/1-welcome" /%} +{% card title="TypeScript Monorepo Tutorial" description="Add Nx to an existing TypeScript repo" type="documentation" url="/getting-started/tutorials/typescript-packages-tutorial" /%} {% /cards %} ## Integrated Repos @@ -52,8 +52,8 @@ Someone who appreciates the structure and consistency of an integrated repositor - [Automate updating dependencies](/features/automate-updating-dependencies) of the entire toolchain {% cards %} -{% card title="Tutorial: React Monorepo" description="Create a React monorepo with Nx" type="documentation" url="/tutorials/2-react-monorepo/1r-introduction/1-welcome" /%} -{% card title="Tutorial: Angular Monorepo" description="Create an Angular monorepo with Nx" type="documentation" url="/tutorials/3-angular-monorepo/1a-introduction/1-welcome" /%} +{% card title="Tutorial: React Monorepo" description="Create a React monorepo with Nx" type="documentation" url="/getting-started/tutorials/react-monorepo-tutorial" /%} +{% card title="Tutorial: Angular Monorepo" description="Create an Angular monorepo with Nx" type="documentation" url="/getting-started/tutorials/angular-monorepo-tutorial" /%} {% /cards %} ## Standalone Applications diff --git a/docs/shared/getting-started/installation.md b/docs/shared/getting-started/installation.md index 641c0b84b7..f7e7c1b170 100644 --- a/docs/shared/getting-started/installation.md +++ b/docs/shared/getting-started/installation.md @@ -156,9 +156,9 @@ To avoid potential issues, it is [recommended to update one major version of Nx Try one of these tutorials for a full walkthrough of what to do after you install Nx -- [TypeScript Monorepo Tutorial](/tutorials/1-ts-packages/1t-introduction/1-welcome) -- [React Monorepo Tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) -- [Angular Monorepo Tutorial](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +- [TypeScript Monorepo Tutorial](/getting-started/tutorials/typescript-packages-tutorial) +- [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) +- [Angular Monorepo Tutorial](/getting-started/tutorials/angular-monorepo-tutorial) ## More Documentation diff --git a/docs/shared/getting-started/intro.md b/docs/shared/getting-started/intro.md index b12d22a228..6d646b41f5 100644 --- a/docs/shared/getting-started/intro.md +++ b/docs/shared/getting-started/intro.md @@ -66,13 +66,13 @@ Also, here are some recipes that give you more details based on the technology s {% cards cols="2" lgCols="4" mdCols="4" smCols="2" %} -{% link-card title="TypeScript Monorepo" type="tutorial" isExternal="true" url="/tutorials/1-ts-packages/1t-introduction/1-welcome" icon="jsMono" /%} +{% link-card title="TypeScript Monorepo" type="tutorial" url="/getting-started/tutorials/typescript-packages-tutorial" icon="jsMono" /%} -{% link-card title="React Monorepo" type="tutorial" isExternal="true" url="/tutorials/2-react-monorepo/1r-introduction/1-welcome" icon="reactMono" /%} +{% link-card title="React Monorepo" type="tutorial" url="/getting-started/tutorials/react-monorepo-tutorial" icon="reactMono" /%} -{% link-card title="Angular Monorepo" type="tutorial" isExternal="true" url="/tutorials/3-angular-monorepo/1a-introduction/1-welcome" icon="angularMono" /%} +{% link-card title="Angular Monorepo" type="tutorial" url="/getting-started/tutorials/angular-monorepo-tutorial" icon="angularMono" /%} -{% link-card title="Gradle Monorepo" type="tutorial" isExternal="true" url="/tutorials/4-gradle/1g-introduction/1-welcome" icon="gradle" /%} +{% link-card title="Gradle Monorepo" type="tutorial" url="/getting-started/tutorials/gradle-tutorial" icon="gradle" /%} {% /cards %} diff --git a/docs/shared/guides/nx-and-angular-cli.md b/docs/shared/guides/nx-and-angular-cli.md index 54800c37db..7cf032e569 100644 --- a/docs/shared/guides/nx-and-angular-cli.md +++ b/docs/shared/guides/nx-and-angular-cli.md @@ -41,7 +41,7 @@ Here's a quick side-by-side overview comparing the features between the Angular | Advanced Generators (e.g. Module Federation, Tailwind,...) | ❌ | ✅ | | Integrated Tooling (Jest, Cypress, Playwright etc.) | ❌ | ✅ | | Support for single-project Workspaces | ✅ | ✅ | -| First-Class [Monorepo Support](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) | ❌\* | ✅ | +| First-Class [Monorepo Support](/getting-started/tutorials/angular-monorepo-tutorial) | ❌\* | ✅ | | [Enforced Module Boundaries](/features/enforce-module-boundaries) | ❌ | ✅ | | Interactive [Project Graph](/features/explore-graph) | ❌ | ✅ | | Task Graph | ❌ | ✅ | @@ -411,4 +411,4 @@ There is also a guide describing how to [consolidate multiple Angular CLI projec You can learn more about Angular & Nx by following our dedicated tutorials: -- [Tutorial: Building Angular Apps in an Nx Monorepo](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +- [Tutorial: Building Angular Apps in an Nx Monorepo](/getting-started/tutorials/angular-monorepo-tutorial) diff --git a/docs/shared/migration/adding-to-monorepo.md b/docs/shared/migration/adding-to-monorepo.md index 817da7e3a9..a28bed1991 100644 --- a/docs/shared/migration/adding-to-monorepo.md +++ b/docs/shared/migration/adding-to-monorepo.md @@ -11,7 +11,7 @@ powering Nx underneath. As a result, Lerna gets all the modern features such as on [https://lerna.js.org/upgrade](https://lerna.js.org/upgrade). {% /callout %} -Nx has first-class support for [monorepos](/tutorials/1-ts-packages/1t-introduction/1-welcome). If you have +Nx has first-class support for [monorepos](/getting-started/tutorials/typescript-packages-tutorial). If you have an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get - fast [task scheduling](/features/run-tasks) diff --git a/docs/shared/packages/angular/angular-plugin.md b/docs/shared/packages/angular/angular-plugin.md index 368cbcbf98..579abcea17 100644 --- a/docs/shared/packages/angular/angular-plugin.md +++ b/docs/shared/packages/angular/angular-plugin.md @@ -46,7 +46,7 @@ nx add @nx/angular This will install the correct version of `@nx/angular`. {% callout type="note" title="Angular Tutorial" %} -For a full tutorial experience, follow the [Angular Monorepo Tutorial](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +For a full tutorial experience, follow the [Angular Monorepo Tutorial](/getting-started/tutorials/angular-monorepo-tutorial) {% /callout %} ## Using the Angular Plugin @@ -113,7 +113,7 @@ nx g @nx/angular:service apps/appName/src/lib/my-service/my-service ## More Documentation -- [Angular Monorepo Tutorial](/tutorials/3-angular-monorepo/1a-introduction/1-welcome) +- [Angular Monorepo Tutorial](/getting-started/tutorials/angular-monorepo-tutorial) - [Migrating from the Angular CLI](/recipes/angular/migration/angular) - [Setup Module Federation with Angular and Nx](/concepts/module-federation/faster-builds-with-module-federation) - [Using Tailwind CSS with Angular projects](/recipes/angular/using-tailwind-css-with-angular-projects) diff --git a/docs/shared/packages/react/react-plugin.md b/docs/shared/packages/react/react-plugin.md index 7878bf2773..fa0e7372f6 100644 --- a/docs/shared/packages/react/react-plugin.md +++ b/docs/shared/packages/react/react-plugin.md @@ -19,7 +19,7 @@ It provides: To create a new workspace with React, run `npx create-nx-workspace@latest --preset=react-standalone`. {% callout type="note" title="React Tutorial" %} -For a full tutorial experience, follow the [React Monorepo Tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +For a full tutorial experience, follow the [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) {% /callout %} ### Installation @@ -135,7 +135,7 @@ The library in `dist` is publishable to npm or a private registry. ## More Documentation -- [React Monorepo Tutorial](/tutorials/2-react-monorepo/1r-introduction/1-welcome) +- [React Monorepo Tutorial](/getting-started/tutorials/react-monorepo-tutorial) - [Using Cypress](/nx-api/cypress) - [Using Jest](/nx-api/jest) - [Using Storybook](/recipes/storybook/overview-react) diff --git a/docs/shared/reference/sitemap.md b/docs/shared/reference/sitemap.md index 270a12104b..73f1cb9b73 100644 --- a/docs/shared/reference/sitemap.md +++ b/docs/shared/reference/sitemap.md @@ -5,7 +5,11 @@ - [Installation](/getting-started/installation) - [Why Nx?](/getting-started/why-nx) - [Editor Setup](/getting-started/editor-setup) - - [Tutorials](/tutorials) + - [Tutorials](/getting-started/tutorials) + - [TypeScript Monorepo](/getting-started/tutorials/typescript-packages-tutorial) + - [React Monorepo](/getting-started/tutorials/react-monorepo-tutorial) + - [Angular Monorepo](/getting-started/tutorials/angular-monorepo-tutorial) + - [Gradle Monorepo](/getting-started/tutorials/gradle-tutorial) - [Features](/features) - [Run Tasks](/features/run-tasks) - [Cache Task Results](/features/cache-task-results) diff --git a/docs/shared/tutorials/angular-monorepo.md b/docs/shared/tutorials/angular-monorepo.md new file mode 100644 index 0000000000..f6b930f32f --- /dev/null +++ b/docs/shared/tutorials/angular-monorepo.md @@ -0,0 +1,1349 @@ +--- +title: 'Angular Monorepo Tutorial' +description: In this tutorial you'll create a frontend-focused workspace with Nx. +--- + +# Building Angular Apps in an Nx Monorepo + +In this tutorial you'll learn how to use Angular with Nx in a monorepo setup. + +What will you learn? + +- how to create a new Angular application +- how to run a single task (i.e. serve your app) or run multiple tasks in parallel +- how to leverage code generators to scaffold components +- how to modularize your codebase and impose architectural constraints for better maintainability +- [how to speed up CI with Nx Cloud ⚡](#fast-ci) + +## Nx CLI vs. Angular CLI + +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. + +Advantages of Nx over the Angular CLI: + +- [Cache any target](/features/cache-task-results) +- [Run only tasks affected by a code change](/ci/features/affected) +- [Split a large angular.json into multiple project.json files](/nx-api/angular/documents/nx-and-angular#projectjson-vs-angularjson) +- [Integrate with modern tools](/nx-api/angular/documents/nx-and-angular#integrating-with-modern-tools) +- [Controllable update process](/nx-api/angular/documents/nx-and-angular#ng-update-vs-nx-migrate) + +Visit our ["Nx and the Angular CLI" page](/nx-api/angular/documents/nx-and-angular) for more details. + +## Final Code + +Here's the source code of the final result for this tutorial. + +{% github-repository url="https://github.com/nrwl/nx-recipes/tree/main/angular-monorepo" /%} + + + +{% youtube +src="https://www.youtube.com/embed/ZzTP4bVJEnI" +title="Nx Angular Monorepo Tutorial Walkthrough" +/%} + +## Creating a new Angular Monorepo + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=90" /%} + +Create a new Angular monorepo with the following command: + +```{% command="npx create-nx-workspace@latest angular-monorepo --preset=angular-monorepo" path="~" %} + +NX Let's create a new workspace [https://nx.dev/getting-started/intro] + +✔ Application name · angular-store +✔ Which bundler would you like to use? · esbuild +✔ Default stylesheet format · css +✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? · No +✔ Test runner to use for end to end (E2E) tests · cypress +✔ Which CI provider would you like to use? · github +``` + +Let's name the initial application `angular-store`. In this tutorial we're going to use `cypress` for e2e tests and `css` for styling. We'll talk more about how Nx integrates with GitHub Actions later in the tutorial. The above command generates the following structure: + +``` +└─ angular-monorepo + ├─ ... + ├─ apps + │ ├─ angular-store + │ │ ├─ src + │ │ │ ├─ app + │ │ │ │ ├─ app.component.css + │ │ │ │ ├─ app.component.html + │ │ │ │ ├─ app.component.spec.ts + │ │ │ │ ├─ app.component.ts + │ │ │ │ ├─ app.config.ts + │ │ │ │ ├─ app.routes.ts + │ │ │ │ └─ nx-welcome.component.ts + │ │ │ ├─ assets + │ │ │ ├─ index.html + │ │ │ ├─ main.ts + │ │ │ ├─ styles.css + │ │ │ └─ test-setup.ts + │ │ ├─ eslintrc.json + │ │ ├─ jest.config.ts + │ │ ├─ project.json + │ │ ├─ tsconfig.app.json + │ │ ├─ tsconfig.editor.json + │ │ ├─ tsconfig.json + │ │ └─ tsconfig.spec.json + │ └─ angular-store-e2e + │ └─ ... + ├─ nx.json + ├─ tsconfig.base.json + └─ package.json +``` + +The setup includes: + +- a new Angular application (`apps/angular-store/`) +- a Cypress based set of e2e tests (`apps/angular-store-e2e/`) +- Prettier preconfigured +- ESLint preconfigured +- Jest preconfigured + +One way to structure an Nx monorepo is to place application projects in the `apps` folder and library projects in the `libs` folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. + +The [`nx.json` file](/reference/nx-json) contains configuration settings for Nx itself and global default settings that individual projects inherit. The `apps/angular-store/project.json` file contains [settings that are specific to the `angular-store` project](/reference/project-configuration). We'll examine that file more in the next section. + +## Serving the App + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=138" /%} + +To serve your new Angular application, just run: + +```shell +cd angular-monorepo +npx nx serve angular-store +``` + +Your application should be served at [http://localhost:4200](http://localhost:4200). + +Nx uses the following syntax to run tasks: + +![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) + +### Manually Defined Tasks + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=160" /%} + +The project tasks are defined in the `project.json` file. + +```json {% fileName="apps/angular-store/project.json" %} +{ + "name": "angular-store", + ... + "targets": { + "build": { ... }, + "serve": { ... }, + "extract-i18n": { ... }, + "lint": { ... }, + "test": { ... }, + "serve-static": { ... }, + }, +} +``` + +Each target contains a configuration object that tells Nx how to run that target. + +```json {% fileName="project.json" %} +{ + "name": "angular-store", + ... + "targets": { + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "angular-store:build" + }, + "configurations": { + "development": { + "buildTarget": "angular-store:build:development", + "hmr": true + }, + "production": { + "buildTarget": "angular-store:build:production", + "hmr": false + } + } + }, + ... + }, +} +``` + +The most critical parts are: + +- `executor` - this is of the syntax `:`, where the `plugin` is an NPM package containing an [Nx Plugin](/extending-nx/intro/getting-started) and `` points to a function that runs the task. +- `options` - these are additional properties and flags passed to the executor function to customize it + +Learn more about how to [run tasks with Nx](/features/run-tasks). We'll [revisit running tasks](#testing-and-linting) later in this tutorial. + +## Adding Another Application + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=182" /%} + +Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/angular` plugin provides, run the following command and inspect the output: + +```{% command="npx nx list @nx/angular" path="angular-monorepo" %} + +NX Capabilities in @nx/angular: + + GENERATORS + + add-linting : Adds linting configuration to an Angular project. + application : Creates an Angular application. + component : Generate an Angular Component. + component-story : Creates a stories.ts file for a component. + component-test : Creates a cypress component test file for a component. + convert-tslint-to-eslint : Converts a project from TSLint to ESLint. + init : Initializes the `@nx/angular` plugin. + library : Creates an Angular library. + library-secondary-entry-point : Creates a secondary entry point for an Angular publishable library. + remote : Generate a Remote Angular Module Federation Application. + move : Moves an Angular application or library to another folder within the workspace and updates the project configuration. + // etc... + + EXECUTORS/BUILDERS + + delegate-build : Delegates the build to a different target while supporting incremental builds. + ng-packagr-lite : Builds a library with support for incremental builds. +This executor is meant to be used with buildable libraries in an incremental build scenario. It is similar to the `@nx/angular:package` executor but with some key differences: +- It doesn't run `ngcc` automatically (`ngcc` needs to be run separately beforehand if needed, this can be done in a `postinstall` hook on `package.json`). +- It only produces ESM2020 bundles. +- It doesn't generate package exports in the `package.json`. + package : Builds and packages an Angular library producing an output following the Angular Package Format (APF) to be distributed as an NPM package. +This executor is similar to the `@angular-devkit/build-angular:ng-packagr` with additional support for incremental builds. + // etc... +``` + +{% callout type="info" title="Prefer a more visual UI?" %} + +If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. + +More info can be found in [the integrate with editors article](/getting-started/editor-setup). + +{% /callout %} + +Run the following command to generate a new `inventory` application. Note how we append `--dry-run` to first check the output. + +```{% command="npx nx g @nx/angular:app apps/inventory --dry-run" path="angular-monorepo" %} +NX Generating @nx/angular:application + +✔ Would you like to configure routing for this application? (y/N) · false +✔ Would you like to use Standalone Components? (y/N) · true +CREATE apps/inventory/project.json +CREATE apps/inventory/src/assets/.gitkeep +CREATE apps/inventory/src/favicon.ico +CREATE apps/inventory/src/index.html +CREATE apps/inventory/src/styles.css +CREATE apps/inventory/tsconfig.app.json +CREATE apps/inventory/tsconfig.editor.json +CREATE apps/inventory/tsconfig.json +CREATE apps/inventory/src/app/app.component.css +CREATE apps/inventory/src/app/app.component.html +CREATE apps/inventory/src/app/app.component.spec.ts +CREATE apps/inventory/src/app/app.component.ts +CREATE apps/inventory/src/app/app.config.ts +CREATE apps/inventory/src/app/nx-welcome.component.ts +CREATE apps/inventory/src/main.ts +CREATE apps/inventory/.eslintrc.json +CREATE apps/inventory/jest.config.ts +CREATE apps/inventory/src/test-setup.ts +CREATE apps/inventory/tsconfig.spec.json +CREATE apps/inventory-e2e/cypress.config.ts +CREATE apps/inventory-e2e/src/e2e/app.cy.ts +CREATE apps/inventory-e2e/src/fixtures/example.json +CREATE apps/inventory-e2e/src/support/app.po.ts +CREATE apps/inventory-e2e/src/support/commands.ts +CREATE apps/inventory-e2e/src/support/e2e.ts +CREATE apps/inventory-e2e/tsconfig.json +CREATE apps/inventory-e2e/project.json +CREATE apps/inventory-e2e/.eslintrc.json + +NOTE: The "dryRun" flag means no changes were made. +``` + +As you can see, it generates a new application in the `apps/inventory/` folder. Let's actually run the generator by removing the `--dry-run` flag. + +```shell +npx nx g @nx/angular:app apps/inventory +``` + +## Sharing Code with Local Libraries + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=232" /%} + +When you develop your Angular application, usually all your logic sits in the `app` folder. Ideally separated by various folder names which represent your "domains". As your app grows, however, the app becomes more and more monolithic and the code is unable to be shared with other applications. + +``` +└─ angular-monorepo + ├─ ... + ├─ apps + │ └─ angular-store + │ ├─ ... + │ ├─ src + │ │ ├─ app + │ │ │ ├─ products + │ │ │ ├─ cart + │ │ │ ├─ ui + │ │ │ ├─ ... + │ │ │ └─ app.tsx + │ │ ├─ ... + │ │ └─ main.tsx + │ ├─ ... + │ └─ project.json + ├─ nx.json + ├─ ... +``` + +Nx allows you to separate this logic into "local libraries". The main benefits include + +- better separation of concerns +- better reusability +- more explicit "APIs" between your "domain areas" +- better scalability in CI by enabling independent test/lint/build commands for each library +- better scalability in your teams by allowing different teams to work on separate libraries + +### Creating Local Libraries + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=254" /%} + +Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for each of these areas using the Angular library generator: + +``` +npx nx g @nx/angular:library libs/products --standalone +npx nx g @nx/angular:library libs/orders --standalone +npx nx g @nx/angular:library libs/shared/ui --standalone +``` + +Note how we type out the full path in the `directory` flag to place the libraries into a subfolder. You can choose whatever folder structure you like to organize your projects. If you change your mind later, you can run the [move generator](/nx-api/workspace/generators/move) to move a project to a different folder. + +Running the above commands should lead to the following directory structure: + +``` +└─ angular-monorepo + ├─ ... + ├─ apps + ├─ libs + │ ├─ products + │ │ ├─ ... + │ │ ├─ project.json + │ │ ├─ src + │ │ │ ├─ index.ts + │ │ │ ├─ test-setup.ts + │ │ │ └─ lib + │ │ │ └─ products + │ │ ├─ tsconfig.json + │ │ ├─ tsconfig.lib.json + │ │ └─ tsconfig.spec.json + │ ├─ orders + │ │ ├─ ... + │ │ ├─ project.json + │ │ ├─ src + │ │ │ ├─ index.ts + │ │ │ └─ ... + │ │ └─ ... + │ └─ shared + │ └─ ui + │ ├─ ... + │ ├─ project.json + │ ├─ src + │ │ ├─ index.ts + │ │ └─ ... + │ └─ ... + ├─ ... +``` + +Each of these libraries + +- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `npx nx test orders`) +- has the name you specified in the generate command; you can find the name in the corresponding `project.json` file +- has a dedicated `index.ts` file which is the "public API" of the library +- is mapped in the `tsconfig.base.json` at the root of the workspace + +### Importing Libraries into the Angular Applications + + + +All libraries that we generate automatically have aliases created in the root-level `tsconfig.base.json`. + +```json {% fileName="tsconfig.base.json" %} +{ + "compilerOptions": { + ... + "paths": { + "@angular-monorepo/orders": ["libs/orders/src/index.ts"], + "@angular-monorepo/products": ["libs/products/src/index.ts"], + "@angular-monorepo/shared-ui": ["libs/shared/ui/src/index.ts"] + }, + ... + }, +} +``` + +Hence we can easily import them into other libraries and our Angular application. As an example, let's use the pre-generated `ProductsComponent` component from our `libs/products` library. + +You can see that the `ProductsComponent` is exported via the `index.ts` file of our `products` library so that other projects in the repository can use it. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself. + +```ts {% fileName="libs/products/src/index.ts" %} +export * from './lib/products/products.component'; +``` + +We're ready to import it into our main application now. First (if you haven't already), let's set up the Angular router. Configure it in the `app.config.ts`. + +```ts {% fileName="apps/angular-store/src/app/app.config.ts" highlightLines=[2,3,4,5,6,9] %} +import { ApplicationConfig } from '@angular/core'; +import { + provideRouter, + withEnabledBlockingInitialNavigation, +} from '@angular/router'; +import { appRoutes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [provideRouter(appRoutes, withEnabledBlockingInitialNavigation())], +}; +``` + +And in `app.component.html`: + +```ts {% fileName="apps/angular-store/src/app/app.component.html" %} + +``` + +Then we can add the `ProductsComponent` component to our `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/products` route. + +```ts {% fileName="apps/angular-store/src/app/app.routes.ts" highlightLines=[10,11,12,13,14] %} +import { Route } from '@angular/router'; +import { NxWelcomeComponent } from './nx-welcome.component'; + +export const appRoutes: Route[] = [ + { + path: '', + component: NxWelcomeComponent, + pathMatch: 'full', + }, + { + path: 'products', + loadComponent: () => + import('@angular-monorepo/products').then((m) => m.ProductsComponent), + }, +]; +``` + +Serving your app (`npx nx serve angular-store`) and then navigating to `/products` should give you the following result: + +![products route](/shared/tutorials/app-products-route.png) + +Let's apply the same for our `orders` library. + +- import the `OrdersComponent` from `libs/orders` into the `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/orders` route + +In the end, your `app.routes.ts` should look similar to this: + +```ts {% fileName="apps/angular-store/src/app/app.routes.ts" highlightLines=[15,16,17,18,19] %} +import { Route } from '@angular/router'; +import { NxWelcomeComponent } from './nx-welcome.component'; + +export const appRoutes: Route[] = [ + { + path: '', + component: NxWelcomeComponent, + pathMatch: 'full', + }, + { + path: 'products', + loadComponent: () => + import('@angular-monorepo/products').then((m) => m.ProductsComponent), + }, + { + path: 'orders', + loadComponent: () => + import('@angular-monorepo/orders').then((m) => m.OrdersComponent), + }, +]; +``` + +Let's also show products in the `inventory` app. + +```ts {% fileName="apps/inventory/src/app/app.component.ts" highlightLines=[2,5] %} +import { Component } from '@angular/core'; +import { ProductsComponent } from '@angular-monorepo/products'; + +@Component({ + imports: [ProductsComponent], + selector: 'app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.css', +}) +export class AppComponent { + title = 'inventory'; +} +``` + +```ts {% fileName="apps/inventory/src/app/app.component.html" %} + +``` + +## Visualizing your Project Structure + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=364" /%} + +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `npx nx build`, identifying [affected projects](/features/run-tasks#run-tasks-on-projects-affected-by-a-pr) and more. Interestingly you can also visualize it. + +Just run: + +```shell +npx nx graph +``` + +You should be able to see something similar to the following in your browser. + +{% graph height="450px" %} + +```json +{ + "projects": [ + { + "name": "angular-store", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "angular-store-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "inventory", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "inventory-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "shared-ui", + "type": "lib", + "data": { + "tags": [] + } + }, + { + "name": "orders", + "type": "lib", + "data": { + "tags": [] + } + }, + + { + "name": "products", + "type": "lib", + "data": { + "tags": [] + } + } + ], + "dependencies": { + "angular-store": [ + { "source": "angular-store", "target": "orders", "type": "static" }, + { "source": "angular-store", "target": "products", "type": "static" } + ], + "angular-store-e2e": [ + { + "source": "angular-store-e2e", + "target": "angular-store", + "type": "implicit" + } + ], + "inventory": [ + { "source": "inventory", "target": "products", "type": "static" } + ], + "inventory-e2e": [ + { "source": "inventory-e2e", "target": "inventory", "type": "implicit" } + ], + "shared-ui": [], + "orders": [], + "products": [] + }, + "workspaceLayout": { "appsDir": "", "libsDir": "" }, + "affectedProjectIds": [], + "focus": null, + "groupByFolder": false +} +``` + +{% /graph %} + +Notice how `shared-ui` is not yet connected to anything because we didn't import it in any of our projects. + +Exercise for you: change the codebase such that `shared-ui` is used by `orders` and `products`. Note: you need to restart the `npx nx graph` command to update the graph visualization or run the CLI command with the `--watch` flag. + +## Testing and Linting + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=410" /%} + +Our current setup not only has targets for serving and building the Angular application, but also has targets for unit testing, e2e testing and linting. The `test` and `lint` targets are defined in the application `project.json` file, while the `e2e` target is [inferred from the `apps/angular-store-e2e/cypress.config.ts` file](#inferred-tasks). We can use the same syntax as before to run these tasks: + +```bash +npx nx test angular-store # runs the tests for angular-store +npx nx lint inventory # runs the linter on inventory +npx nx e2e angular-store-e2e # runs e2e tests for the angular-store +``` + +### Inferred Tasks + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=424" /%} + +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. All tasks from the `angular-store` project are defined in its `project.json` file, but the companion `angular-store-e2e` project has its tasks inferred from configuration files. To view the tasks that Nx has detected, look in the [Nx Console](/getting-started/editor-setup), [Project Details View](/recipes/nx-console/console-project-details) or run: + +```shell +npx nx show project angular-store-e2e --web +``` + +{% project-details title="Project Details View" %} + +```json +{ + "project": { + "name": "angular-store-e2e", + "type": "e2e", + "data": { + "metadata": { + "targetGroups": { + "E2E (CI)": ["e2e-ci--src/e2e/app.cy.ts", "e2e-ci"] + } + }, + "name": "angular-store-e2e", + "root": "apps/angular-store-e2e", + "sourceRoot": "apps/angular-store-e2e/src", + "projectType": "application", + "tags": [], + "implicitDependencies": ["angular-store"], + "targets": { + "e2e": { + "options": { + "cwd": "apps/angular-store-e2e", + "command": "cypress run" + }, + "cache": true, + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["cypress"] + } + ], + "outputs": [ + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/videos", + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/screenshots" + ], + "configurations": { + "production": { + "command": "cypress run --env webServerCommand=\"nx run angular-store:serve:production\"" + } + }, + "executor": "nx:run-commands", + "metadata": { + "technologies": ["cypress"] + } + }, + "e2e-ci--src/e2e/app.cy.ts": { + "outputs": [ + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/videos", + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/screenshots" + ], + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["cypress"] + } + ], + "cache": true, + "options": { + "cwd": "apps/angular-store-e2e", + "command": "cypress run --env webServerCommand=\"nx run angular-store:serve-static\" --spec src/e2e/app.cy.ts" + }, + "executor": "nx:run-commands", + "configurations": {}, + "metadata": { + "technologies": ["cypress"] + } + }, + "e2e-ci": { + "executor": "nx:noop", + "cache": true, + "inputs": [ + "default", + "^production", + { + "externalDependencies": ["cypress"] + } + ], + "outputs": [ + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/videos", + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/screenshots" + ], + "dependsOn": [ + { + "target": "e2e-ci--src/e2e/app.cy.ts", + "projects": "self", + "params": "forward" + } + ], + "options": {}, + "configurations": {}, + "metadata": { + "technologies": ["cypress"] + } + }, + "lint": { + "cache": true, + "options": { + "cwd": "apps/angular-store-e2e", + "command": "eslint ." + }, + "inputs": [ + "default", + "{workspaceRoot}/.eslintrc.json", + "{workspaceRoot}/apps/angular-store-e2e/.eslintrc.json", + "{workspaceRoot}/tools/eslint-rules/**/*", + { + "externalDependencies": ["eslint"] + } + ], + "executor": "nx:run-commands", + "configurations": {}, + "metadata": { + "technologies": ["eslint"] + } + } + } + } + }, + "sourceMap": { + "targets": ["apps/angular-store-e2e/project.json", "nx/core/project-json"], + "targets.e2e": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e.cache": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e.inputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e.outputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e.options": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e.configurations": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci--src/e2e/app.cy.ts": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci--src/e2e/app.cy.ts.cache": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci--src/e2e/app.cy.ts.inputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci--src/e2e/app.cy.ts.outputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci--src/e2e/app.cy.ts.options": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci.cache": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci.dependsOn": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci.inputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci.outputs": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.e2e-ci.executor": [ + "apps/angular-store-e2e/cypress.config.ts", + "@nx/cypress/plugin" + ], + "targets.lint": [ + "apps/angular-store-e2e/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.cache": [ + "apps/angular-store-e2e/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.inputs": [ + "apps/angular-store-e2e/project.json", + "@nx/eslint/plugin" + ], + "targets.lint.options": [ + "apps/angular-store-e2e/project.json", + "@nx/eslint/plugin" + ] + } +} +``` + +{% /project-details %} + +If you expand the `e2e` task, you can see that it was created by the `@nx/cypress` plugin by analyzing the `apps/angular-store-e2e/cypress.config.ts` file. Notice the outputs are defined as: + +```json +[ + [ + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/videos", + "{workspaceRoot}/dist/cypress/apps/angular-store-e2e/screenshots" + ] +] +``` + +This value is being read from the `videosFolder` and `screenshotsFolder` defined by the `nxE2EPreset` in your `apps/angular-store-e2e/cypress.config.ts` file. Let's change their value in your `apps/angular-store-e2e/cypress.config.ts` file: + +```ts {% fileName="apps/angular-store-e2e/cypress.config.ts" highlightLines=["8-10"] %} +// ... +export default defineConfig({ + e2e: { + ...nxE2EPreset(__filename, { + // ... + }), + baseUrl: 'http://localhost:4200', + videosFolder: '../dist/cypress/apps/angular-store-e2e/videos-changed', + screenshotsFolder: + '../dist/cypress/apps/angular-store-e2e/screenshots-changed', + }, +}); +``` + +Now if you look at the project details view again, the outputs for the `e2e` target will be: + +```json +[ + "{workspaceRoot}/apps/dist/cypress/apps/angular-store-e2e/videos-changed", + "{workspaceRoot}/apps/dist/cypress/apps/angular-store-e2e/screenshots-changed" +] +``` + +This feature ensures that Nx will always cache the correct files. + +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. + +### Running Multiple Tasks + +In addition to running individual tasks, you can also run multiple tasks in parallel using the following syntax: + +```shell +npx nx run-many -t test lint e2e +``` + +### Caching + +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). + +Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. + +```{% command="npx nx run-many -t test lint e2e" path="angular-monorepo" %} +✔ nx run e2e:lint [existing outputs match the cache, left as is] +✔ nx run angular-store:lint [existing outputs match the cache, left as is] +✔ nx run angular-store:test [existing outputs match the cache, left as is] +✔ nx run e2e:e2e [existing outputs match the cache, left as is] + +—————————————————————————————————————————————————————— + +NX Successfully ran targets test, lint, e2e for 5 projects (54ms) + +Nx read the output from the cache instead of running the command for 10 out of 10 tasks. +``` + +Not all tasks might be cacheable though. You can [configure which tasks are cacheable](/features/cache-task-results) in [the project configuration](/reference/project-configuration#cache) or in [the global Nx configuration](/reference/nx-json#cache). You can also [learn more about how caching works](/concepts/how-caching-works). + +### Testing Affected Projects + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=551" /%} + +Commit your changes to git. + +```shell +git commit -a -m "some commit message" +``` + +And then make a small change to the `products` library. + +```html {% fileName="libs/products/src/lib/product-list/product-list.component.html" %} +

product-list works!

+

This is a change. 👋

+``` + +One of the key features of Nx in a monorepo setting is that you're able to run tasks only for projects that are actually affected by the code changes that you've made. To run the tests for only the projects affected by this change, run: + +```shell +npx nx affected -t test +``` + +Note that the unit tests were run for `products`, `angular-store` and `inventory`, but not for `orders` because a change to `products` can not possibly break the tests for `orders`. In a small repo like this, there isn't a lot of time saved, but as there are more tests and more projects, this quickly becomes an essential command. + +You can also see what projects are affected in the graph visualizer with; + +```shell +npx nx graph --affected +``` + +{% graph height="450px" %} + +```json +{ + "projects": [ + { + "name": "angular-store", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "angular-store-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "inventory", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "inventory-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "shared-ui", + "type": "lib", + "data": { + "tags": [] + } + }, + { + "name": "orders", + "type": "lib", + "data": { + "tags": [] + } + }, + + { + "name": "products", + "type": "lib", + "data": { + "tags": [] + } + } + ], + "dependencies": { + "angular-store": [ + { "source": "angular-store", "target": "orders", "type": "static" }, + { "source": "angular-store", "target": "products", "type": "static" } + ], + "angular-store-e2e": [ + { + "source": "angular-store-e2e", + "target": "angular-store", + "type": "implicit" + } + ], + "inventory": [ + { "source": "inventory", "target": "products", "type": "static" } + ], + "inventory-e2e": [ + { "source": "inventory-e2e", "target": "inventory", "type": "implicit" } + ], + "shared-ui": [], + "orders": [], + "products": [] + }, + "workspaceLayout": { "appsDir": "", "libsDir": "" }, + "affectedProjectIds": [ + "products", + "inventory", + "inventory-e2e", + "angular-store", + "angular-store-e2e" + ], + "focus": null, + "groupByFolder": false +} +``` + +{% /graph %} + +## Building the Apps for Deployment + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=608" /%} + +If you're ready and want to ship your applications, you can build them using + +```{% command="npx nx run-many -t build" path="angular-monorepo" %} +NX Generating @nx/angular:component + +CREATE libs/orders/src/lib/order-list/order-list.component.css +CREATE libs/orders/src/lib/order-list/order-list.component.html +CREATE libs/orders/src/lib/order-list/order-list.component.spec.ts +CREATE libs/orders/src/lib/order-list/order-list.component.ts +UPDATE libs/orders/src/index.ts +❯ nx run-many -t build + +✔ nx run inventory:build:production (7s) +✔ nx run angular-store:build:production (7s) + +——————————————————————————————————————————————————————————————————————— + +NX Successfully ran target build for 2 projects (7s) +``` + +All the required files will be placed in `dist/apps/angular-store` and `dist/apps/inventory` and can be deployed to your favorite hosting provider. + +You can even create your own `deploy` task that sends the build output to your hosting provider. + +```json {% fileName="apps/angular-store/project.json" %} +{ + "targets": { + "deploy": { + "dependsOn": "build", + "command": "netlify deploy --dir=dist/angular-store" + } + } +} +``` + +Replace the `command` with whatever terminal command you use to deploy your site. + +The `"dependsOn": "build"` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. + +With the `deploy` tasks defined, you can deploy a single application with `npx nx deploy angular-store` or deploy any applications affected by the current changes with: + +```shell +npx nx affected -t deploy +``` + +## Imposing Constraints with Module Boundary Rules + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=663" /%} + +Once you modularize your codebase you want to make sure that the libs are not coupled to each other in an uncontrolled way. Here are some examples of how we might want to guard our small demo workspace: + +- we might want to allow `orders` to import from `shared-ui` but not the other way around +- we might want to allow `orders` to import from `products` but not the other way around +- we might want to allow all libraries to import the `shared-ui` components, but not the other way around + +When building these kinds of constraints you usually have two dimensions: + +- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library +- **scope (domain) of the project:** what domain area is covered by the project. Example: "orders", "products", "shared" ... this really depends on the type of product you're developing + +Nx comes with a generic mechanism that allows you to assign "tags" to projects. "tags" are arbitrary strings you can assign to a project that can be used later when defining boundaries between projects. For example, go to the `project.json` of your `orders` library and assign the tags `type:feature` and `scope:orders` to it. + +```json {% fileName="libs/orders/project.json" %} +{ + ... + "tags": ["type:feature", "scope:orders"], +} +``` + +Then go to the `project.json` of your `products` library and assign the tags `type:feature` and `scope:products` to it. + +```json {% fileName="libs/products/project.json" %} +{ + ... + "tags": ["type:feature", "scope:products"], +} +``` + +Finally, go to the `project.json` of the `shared-ui` library and assign the tags `type:ui` and `scope:shared` to it. + +```json {% fileName="libs/shared/ui/project.json" %} +{ + ... + "tags": ["type:ui", "scope:shared"], +} +``` + +Notice how we assign `scope:shared` to our UI library because it is intended to be used throughout the workspace. + +Next, let's come up with a set of rules based on these tags: + +- `type:feature` should be able to import from `type:feature` and `type:ui` +- `type:ui` should only be able to import from `type:ui` +- `scope:orders` should be able to import from `scope:orders`, `scope:shared` and `scope:products` +- `scope:products` should be able to import from `scope:products` and `scope:shared` + +To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.base.json` at the root of the workspace and add the following `depConstraints` in the `@nx/enforce-module-boundaries` rule configuration: + +```json {% fileName=".eslintrc.base.json" %} +{ + ... + "overrides": [ + { + ... + "rules": { + "@nx/enforce-module-boundaries": [ + "error", + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { + "sourceTag": "*", + "onlyDependOnLibsWithTags": ["*"] + }, + { + "sourceTag": "type:feature", + "onlyDependOnLibsWithTags": ["type:feature", "type:ui"] + }, + { + "sourceTag": "type:ui", + "onlyDependOnLibsWithTags": ["type:ui"] + }, + { + "sourceTag": "scope:orders", + "onlyDependOnLibsWithTags": [ + "scope:orders", + "scope:products", + "scope:shared" + ] + }, + { + "sourceTag": "scope:products", + "onlyDependOnLibsWithTags": ["scope:products", "scope:shared"] + }, + { + "sourceTag": "scope:shared", + "onlyDependOnLibsWithTags": ["scope:shared"] + } + ] + } + ] + } + }, + ... + ] +} +``` + +To test it, go to your `libs/products/src/lib/product-list/product-list.component.ts` file and import the `OrdersComponent` from the `orders` project: + +```ts {% fileName="libs/products/src/lib/product-list/product-list.component.ts" highlightLines=[4,5] %} +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +// This import is not allowed 👇 +import { OrdersComponent } from '@angular-monorepo/orders'; + +@Component({ + selector: 'angular-monorepo-product-list', + standalone: true, + imports: [CommonModule], + templateUrl: './product-list.component.html', + styleUrls: ['./product-list.component.css'], +}) +export class ProductsComponent {} +``` + +If you lint your workspace you'll get an error now: + +```{% command="npx nx run-many -t lint" %} +NX Running target lint for 7 projects +✖ nx run products:lint + Linting "products"... + + /Users/isaac/Documents/code/nx-recipes/angular-monorepo/libs/products/src/lib/product-list/product-list.component.ts + 5:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries + 5:10 warning 'OrdersComponent' is defined but never used @typescript-eslint/no-unused-vars + + ✖ 2 problems (1 error, 1 warning) + + Lint warnings found in the listed files. + + Lint errors found in the listed files. + + +✔ nx run orders:lint (1s) +✔ nx run angular-store:lint (1s) +✔ nx run angular-store-e2e:lint (689ms) +✔ nx run inventory-e2e:lint (690ms) +✔ nx run inventory:lint (858ms) +✔ nx run shared-ui:lint (769ms) + +——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + +NX Ran target lint for 7 projects (3s) + +✔ 6/7 succeeded [0 read from cache] + +✖ 1/7 targets failed, including the following: + - nx run products:lint +``` + +If you have the ESLint plugin installed in your IDE you should immediately see an error: + +![ESLint module boundary error](/shared/tutorials/module-boundary-lint-rule.png) + +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). + +## Fast CI ⚡ {% highlightColor="green" %} + +{% callout type="check" title="Repository with Nx" %} +Make sure you have completed the previous sections of this tutorial before starting this one. If you want a clean starting point, you can check out the [reference code](https://github.com/nrwl/nx-recipes/tree/main/angular-monorepo) as a starting point. +{% /callout %} + +{% video-link link="https://youtu.be/ZzTP4bVJEnI?t=791" /%} + +This tutorial walked you through how Nx can improve the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. + +- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). +- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. +- Nx Agents [efficiently distribute tasks across machines](/ci/concepts/parallelization-distribution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. +- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). + +### Connect to Nx Cloud {% highlightColor="green" %} + +Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. + +Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository. + +1. Commit your existing changes with `git add . && git commit -am "updates"` +2. [Create a new GitHub repository](https://github.com/new) +3. Follow GitHub's instructions to push your existing code to the repository + +When we set up the repository at the beginning of this tutorial, we chose to use GitHub Actions as a CI provider. This created a basic CI pipeline and configured Nx Cloud in the repository. It also printed a URL in the terminal to register your repository in your [Nx Cloud](https://cloud.nx.app) account. If you didn't click on the link when first creating your repository, you can show it again by running: + +```shell +npx nx connect +``` + +Once you click the link, follow the steps provided and make sure Nx Cloud is enabled on the main branch of your repository. + +### Configure Your CI Workflow {% highlightColor="green" %} + +When you chose GitHub Actions as your CI provider at the beginning of the tutorial, `create-nx-workspace` created a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. + +If you need to generate a new workflow file for GitHub Actions or other providers, you can do so with this command: + +```shell +npx nx generate ci-workflow +``` + +The key lines in the CI pipeline are: + +```yml {% fileName=".github/workflows/ci.yml" highlightLines=["10-14", "21-23"] %} +name: CI +# ... +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + filter: tree:0 + + # This enables task distribution via Nx Cloud + # Run this command as early as possible, before dependencies are installed + # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun + # Uncomment this line to enable task distribution + # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: 'npm' + - run: npm ci --legacy-peer-deps + - uses: nrwl/nx-set-shas@v4 + # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected + # When you enable task distribution, run the e2e-ci task instead of e2e + - run: npx nx affected -t lint test build e2e +``` + +### Open a Pull Request {% highlightColor="green" %} + +Commit the changes and open a new PR on GitHub. + +```shell +git add . +git commit -m 'add CI workflow file' +git push origin add-workflow +``` + +When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run. + +![Nx Cloud report](/shared/tutorials/github-pr-cloud-report.avif) + +The `See all runs` link goes to a page with the progress and results of tasks that were run in the CI pipeline. + +![Run details](/shared/tutorials/nx-cloud-run-details.avif) + +For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: + +- [Circle CI with Nx](/ci/intro/tutorials/circle) +- [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) + +## Next Steps + +Here's some things you can dive into next: + +- Read more about [how Nx compares to the Angular CLI](/nx-api/angular/documents/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) +- [Setup Storybook for our shared UI library](/recipes/storybook/overview-angular) + +Also, make sure you + +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! +- [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](/blog) +- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights diff --git a/docs/shared/tutorials/gradle.md b/docs/shared/tutorials/gradle.md new file mode 100644 index 0000000000..a94e0619f8 --- /dev/null +++ b/docs/shared/tutorials/gradle.md @@ -0,0 +1,437 @@ +--- +title: 'Gradle Tutorial' +description: In this tutorial you'll add Nx to an existing Gradle repo +--- + +# Gradle Tutorial + +In this tutorial, you'll learn how to add Nx to a repository with an existing Gradle setup. + +What will you learn? + +- how to add Nx to a Gradle project +- how to run a single task (i.e. serve your app) or run multiple tasks in parallel +- how to leverage code generators to scaffold components +- how to modularize your codebase and impose architectural constraints for better maintainability +- [how to speed up CI with Nx Cloud ⚡](#fast-ci) + +## Prerequisites + +Make sure that you have [Gradle](https://gradle.org/) installed on your system. +Consult [Gradle's installation guide](https://docs.gradle.org/current/userguide/installation.html) for instruction that +are specific to your operating system. + +To verify that Gradle was installed correctly, run this command: + +```shell +gradle --version +``` + +To streamline this tutorial, we'll install Nx globally on your system. You can use Homebrew (Mac only) or a manually installed Node version (any OS). + +{% tabs %} +{% tab label="Homebrew" %} + +Make sure [Homebrew is installed](https://brew.sh/), then install Nx globally with these commands: + +```shell +brew tap nrwl/nx +brew install nx +``` + +{% /tab %} +{% tab label="Node" %} + +Install node from the [NodeJS website](https://nodejs.org/en/download), then install Nx globally with this command: + +```shell +npm install --global nx +``` + +{% /tab %} +{% /tabs %} + +## Getting Started + +This tutorial picks up where [Spring framework](https://spring.io/)'s guide for [Multi-Module Projects](https://spring.io/guides/gs/multi-module) leaves off. + +Fork [the sample repository](https://github.com/nrwl/gradle-tutorial/fork), and then clone it on your local machine: + +```shell +git clone https://github.com//gradle-tutorial.git +``` + +The Multi-Module Spring Tutorial left us with 2 projects: + +- The main `application` project which contains the Spring `DemoApplication` +- A `library` project which contains a Service used in the `DemoApplication` + +You can see the above 2 projects by running `./gradlew projects` + +```text {% command="./gradlew projects" %} +> Task :projects + +------------------------------------------------------------ +Root project 'gradle-tutorial' +------------------------------------------------------------ + +Root project 'gradle-tutorial' ++--- Project ':application' +\--- Project ':library' + +``` + +## Add Nx + +Nx is a build system with built in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, +both locally and on CI. We will explore the features of Nx in this tutorial by adding it to the Gradle workspace above. + +To add Nx, run + +```shell {% path="~/gradle-tutorial" %} +npx nx@latest init +``` + +This command will download the latest version of Nx and help set up your repository to take advantage of it. Nx will +also detect Gradle is used in the repo so it will propose adding the `@nx/gradle` plugin to integrate Gradle with Nx. +Select the plugin and continue with the setup. + +Similar to Gradle, Nx can be run with the `nx` or `nx.bat` executables. We will learn about some of the Nx commands in +the following sections. + +## Explore Your Workspace + +Like Gradle, Nx understands your workspace as a graph of projects. Nx uses this graph for many things which we will +learn about in following sections. To visualize this graph in your browser, Run the following command and click the +"Show all projects" button in the left sidebar. + +You will recognize that the projects which are shown, are the same projects which Gradle shows. +The `@nx/gradle` plugin reflects the graph of projects in Gradle into the Nx Project Graph. As projects +are created, deleted, and change their dependencies, Nx will automatically recalculate the graph. Exploring this graph +visually is vital to understanding how your code is structured and how Nx and Gradle behaves. + +{% tabs %} +{% tab label="Mac/Linux" %} + +```shell +./nx graph +``` + +{% /tab %} +{% tab label="Windows" %} + +```shell +./nx.bat graph +``` + +{% /tab %} +{% /tabs %} + +{% graph title="Gradle Projects" height="200px" jsonFile="shared/tutorials/gradle-project-graph.json" %} +{% /graph %} + +## Running Tasks + +Nx is a task runner built for monorepos. It can run a single task for a single project, a task for all projects, and +even intelligently run a subset of tasks based on the changes you've made in your repository. Nx also has sophisticated +computation caching to reuse the results of tasks. We will explore how Nx adds to the task running Gradle provides. + +Before we start running tasks, let's explore the tasks available for the `application` project. The `@nx/gradle` plugin +that we've installed reflects Gradle's tasks to Nx, which allows it to run any of the Gradle tasks defined for that project. You can view the available tasks either through [Nx Console](/getting-started/editor-setup) or from the terminal: + +```shell {% path="~/gradle-tutorial" %} +./nx show project application --web +``` + +{% project-details title="Project Details View" jsonFile="shared/tutorials/gradle-pdv.json" expandedTargets=["build"] height="520px" %} +{% /project-details %} + +The Nx command to run the `build` task for the `application` project is: + +```shell +./nx run application:build +``` + +When Nx runs a Gradle task, it hands off the execution of that task to Gradle, so all task dependencies and +configuration settings in the Gradle configuration are still respected. + +By running the task via Nx, however, the task computation was cached for reuse. Now, running `./nx run application:build` +again, will complete almost instantly as the result from the previous execution will be used. + +```{% command="./nx run application:build" %} + + ✔ 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 application:classes [existing outputs match the cache, left as is] + +> ./gradlew :application:classes + +> Task :library:compileJava UP-TO-DATE +> Task :library:processResources NO-SOURCE +> Task :library:classes UP-TO-DATE +> Task :library:jar UP-TO-DATE +> Task :application:compileJava UP-TO-DATE +> Task :application:processResources UP-TO-DATE +> Task :application:classes UP-TO-DATE + +BUILD SUCCESSFUL in 647ms +4 actionable tasks: 4 up-to-date + +> nx run application:build [existing outputs match the cache, left as is] + +> ./gradlew :application:build + + +Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. + +You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. + +For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. + +BUILD SUCCESSFUL in 768ms +9 actionable tasks: 1 executed, 8 up-to-date + +————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + NX Successfully ran target build for project application and 3 tasks it depends on (30ms) + +Nx read the output from the cache instead of running the command for 4 out of 4 tasks. +``` + +Now that we've run one task, let's run all the `build` tasks in the repository with the Nx `run-many` command. This is similar to Gradle's `./gradlew build` command. + +```{% command="./nx run-many -t build" %} + + ✔ nx run library:classes [existing outputs match the cache, left as is] + ✔ nx run library:build [existing outputs match the cache, left as is] + ✔ nx run application:classes [existing outputs match the cache, left as is] + ✔ nx run application:build [existing outputs match the cache, left as is] + ✔ nx run gradle-tutorial:classes (1s) + ✔ nx run gradle-tutorial:build (1s) + +————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + NX Successfully ran target build for 3 projects and 3 tasks they depend on (2s) + +Nx read the output from the cache instead of running the command for 4 out of 6 tasks. +``` + +Again, because Nx cached the tasks when the application was built, most of the tasks here were near instant. The only +ones which needed to be done is the root project's build. Running the command one more time, will be near instant as +then all the tasks will be restored from the cache. + +## Run Tasks for Affected Projects + +Nx doesn't just cache your task results, it can also [eliminate the need to run unnecessary tasks](/ci/features/affected). + +First, commit any outstanding changes to the `main` branch locally: + +```shell +git commit -am "changes" +``` + +Next make a small change to the `application` code: + +```java {% fileName="application/src/main/java/com/example/multimodule/application/DemoApplication.java" highlightLines=[21] %} +package com.example.multimodule.application; + +import com.example.multimodule.service.MyService; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication(scanBasePackages = "com.example.multimodule") +@RestController +public class DemoApplication { + + private final MyService myService; + + public DemoApplication(MyService myService) { + this.myService = myService; + } + + @GetMapping("/") + public String home() { + return myService.message() + " changed!"; + } + + public static void main(String[] args) { + SpringApplication.run(DemoApplication.class, args); + } +} +``` + +As a developer, we know that this change only affects the `application` project, not the `library` project. We would +run `./nx run application:test` to verify our changes. In CI, teams often run all test tasks rerunning +the `library:test` task unnecessarily. + +For a repository with only a few projects, you can manually calculate which projects are affected. As the repository grows, it becomes critical to have a tool like Nx that understands the project dependency graph and eliminates wasted time in CI. + +The `./nx affected` command solves this problem. Nx uses its project graph in conjunction with git history to only run +tasks for projects that may have been affected by the changes that you made. + +To run the `test` tasks for projects affected by this change, run: + +```shell +./nx affected -t test +``` + +Notice that this command does not run the `test` task for the `library` project, since it could not have been affected by the code change. + +## Fast CI ⚡ {% highlightColor="green" %} + +{% callout type="check" title="Repository with Nx" %} +Make sure you have completed the previous sections of this tutorial before starting this one. If you want a clean starting point, you can check out the [reference code](https://github.com/nrwl/nx-recipes/tree/main/gradle) as a starting point. +{% /callout %} + +This tutorial walked you through how Nx can improve the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. + +- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). +- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. +- Nx Agents [efficiently distribute tasks across machines](/ci/concepts/parallelization-distribution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. +- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). + +### Connect to Nx Cloud {% highlightColor="green" %} + +Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. + +Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository. + +1. Commit your existing changes with `git add . && git commit -am "updates"` +2. [Create a new GitHub repository](https://github.com/new) +3. Follow GitHub's instructions to push your existing code to the repository + +Now connect your repository to Nx Cloud with the following command: + +```shell +./nx connect +``` + +A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. + +![](/shared/tutorials/nx-cloud-github-connect.avif) + +Once the PR is created, merge it into your main branch. + +![](/shared/tutorials/github-cloud-pr-merged.avif) + +And make sure you pull the latest changes locally: + +```shell +git pull +``` + +You should now have an `nxCloudId` property specified in the `nx.json` file. + +### Create a CI Workflow {% highlightColor="green" %} + +Let's create a branch to add a CI workflow. + +```shell +git checkout -b add-workflow +``` + +And use the following command to generate a CI workflow file. + +```shell +./nx generate ci-workflow --ci=github +``` + +This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line. + +The key lines in the CI pipeline are: + +```yml {% fileName=".github/workflows/ci.yml" highlightLines=["21-24", "38-39"] %} +name: CI + +on: + push: + branches: + - main + pull_request: + +permissions: + actions: read + contents: read + +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + filter: tree:0 + + # This enables task distribution via Nx Cloud + # Run this command as early as possible, before dependencies are installed + # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun + # Uncomment this line to enable task distribution + # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" + + - name: Set up JDK 21 for x64 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + architecture: x64 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2 + + - uses: nrwl/nx-set-shas@v4 + + # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected + - run: ./nx affected -t test build +``` + +### Open a Pull Request {% highlightColor="green" %} + +Commit the changes and open a new PR on GitHub. + +```shell +git add . +git commit -m 'add CI workflow file' +git push origin add-workflow +``` + +When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run. + +![Nx Cloud report](/shared/tutorials/gradle-github-pr-cloud-report.avif) + +The `See all runs` link goes to a page with the progress and results of tasks that were run in the CI pipeline. + +![Gradle run details](/shared/tutorials/gradle-run-details.webp) + +For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: + +- [Circle CI with Nx](/ci/intro/tutorials/circle) +- [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) + +## Summary + +Now that you have added Nx to this sample Gradle repository, you have learned several ways that Nx can help your +organization: + +- Nx reflects the Gradle graph into the Nx graph +- Nx's dependency graph visualisation helps you understand your codebase +- Nx caches task results and reuses them when the same task is rerun later +- Nx intelligently determines which tasks are `affected` by code changes to reduce waste in CI +- Nx Cloud provides remote caching and distributed task execution to speed up CI + +## Next Steps + +Connect with the rest of the Nx community with these resources: + +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! +- [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](/blog) +- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights diff --git a/docs/shared/tutorials/react-monorepo.md b/docs/shared/tutorials/react-monorepo.md new file mode 100644 index 0000000000..443196ba2d --- /dev/null +++ b/docs/shared/tutorials/react-monorepo.md @@ -0,0 +1,1190 @@ +--- +title: 'React Monorepo Tutorial' +description: In this tutorial you'll create a frontend-focused workspace with Nx. +--- + +# Building React Apps in an Nx Monorepo + +In this tutorial you'll learn how to use React with Nx in a monorepo setup. + +What will you learn? + +- how to create a new React application +- how to run a single task (i.e. serve your app) or run multiple tasks in parallel +- how to leverage code generators to scaffold components +- how to modularize your codebase and impose architectural constraints for better maintainability +- [how to speed up CI with Nx Cloud ⚡](#fast-ci) + +## Why Use an Nx Monorepo? + +Nx works along side your existing tooling to improve your experience developing in a monorepo. You can also use code generators that Nx provides to quickly spin up a new project that is pre-configured with industry standard tooling. In this tutorial, we'll set up a monorepo that leverages the same tooling you would typically use without Nx, but Nx will enable you to focus your time on the features of your application rather than the tooling that surrounds it. + +We'll use npm/yarn/pnpm workspaces to link projects and TypeScript project references to incrementally typecheck the repository. Nx works well whether you have a [single version policy](/concepts/decisions/dependency-management#single-version-policy) or have each project [separately define their dependencies](/concepts/decisions/dependency-management#independently-maintained-dependencies), but in this tutorial we'll define all dependencies in a single `package.json` at the root of the repository. + +Nx generators will automatically configure new projects with useful tools like Prettier, ESLint and Jest. Those generators will also make sure that each project is referenced correctly in the root `workspaces` property and the `tsconfig` references properties accurately reflect the dependencies of each project. + +Nx Plugins are optional packages that extend the capabilities of Nx, catering to various specific technologies. For instance, we have plugins tailored to React (e.g., `@nx/react`), 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. + +Features we'll use in this monorepo: + +- [Install dependencies at the root by default](/concepts/decisions/dependency-management#single-version-policy) +- [Scaffold new code with generators](/features/generate-code) +- [Updates dependencies with automated migrations](/features/automate-updating-dependencies) + +Visit our ["Why Nx" page](/getting-started/why-nx) for more details. + +## Final Code + +Here's the source code of the final result for this tutorial. + +{% github-repository url="https://github.com/nrwl/nx-recipes/tree/main/react-monorepo" /%} + + + +{% youtube +src="https://www.youtube.com/embed/gc4N7kxiA50" +title="Nx React Monorepo Tutorial Walkthrough" +/%} + +## Creating a new React Monorepo + +Create a new React monorepo with the following command: + +```{% command="npx create-nx-workspace@latest react-monorepo --preset=react-monorepo" path="~" %} + +NX Let's create a new workspace [https://nx.dev/getting-started/intro] + +✔ Application name · react-store +✔ Which bundler would you like to use? · vite +✔ Which unit test runner would you like to use? · vitest +✔ Test runner to use for end to end (E2E) tests · playwright +✔ Default stylesheet format · css +✔ Would you like to use ESLint? · Yes +✔ Would you like to use Prettier for code formatting? · Yes +✔ Which CI provider would you like to use? · github +``` + +Let's name the initial application `react-store`. In this tutorial we're going to use `vite` as a bundler, `vitest` for unit testing, `cypress` for e2e tests, `css` for styling and also include ESLint and Prettier. We'll talk more about how Nx integrates with GitHub Actions later in the tutorial. The above command generates the following structure: + +``` +└─ react-monorepo + ├─ apps + │ ├─ react-store + │ │ ├─ public + │ │ │ └─ ... + │ │ ├─ src + │ │ │ ├─ app + │ │ │ │ ├─ app.module.css + │ │ │ │ ├─ app.spec.tsx + │ │ │ │ ├─ app.tsx + │ │ │ │ └─ nx-welcome.tsx + │ │ │ ├─ assets + │ │ │ ├─ main.tsx + │ │ │ └─ styles.css + │ │ ├─ index.html + │ │ ├─ package.json + │ │ ├─ tsconfig.app.json + │ │ ├─ tsconfig.json + │ │ ├─ tsconfig.spec.json + │ │ └─ vite.config.ts + │ └─ react-store-e2e + │ └─ ... + ├─ ... + ├─ package.json + ├─ nx.json + ├─ tsconfig.base.json + ├─ tsconfig.json + └─ vitest.workspace.ts +``` + +The setup includes: + +- a new React application (`apps/react-store/`) +- a Playwright based set of e2e tests (`apps/react-store-e2e/`) +- Prettier preconfigured +- ESLint preconfigured +- Vitest preconfigured + +One way to structure an Nx monorepo is to place application projects in the `apps` folder and library projects in the `libs` folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. + +The [`nx.json` file](/reference/nx-json) contains configuration settings for Nx itself and global default settings that individual projects inherit. + +## Serving the App + +To serve your new React application, just run: + +```shell +npx nx serve react-store +``` + +Your application should be served at [http://localhost:4200](http://localhost:4200). + +Nx uses the following syntax to run tasks: + +![Syntax for Running Tasks in Nx](/shared/images/run-target-syntax.svg) + +### Inferred Tasks + +Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/getting-started/editor-setup) project detail view or run: + +```shell +npx nx show project react-store +``` + +{% project-details title="Project Details View (Simplified)" %} + +```json +{ + "project": { + "name": "react-store", + "type": "app", + "data": { + "root": "apps/react-store", + "targets": { + "build": { + "options": { + "cwd": "apps/react-store", + "command": "vite build" + }, + "cache": true, + "dependsOn": ["^build"], + "inputs": [ + "production", + "^production", + { + "externalDependencies": ["vite"] + } + ], + "outputs": ["{workspaceRoot}/dist/apps/react-store"], + "executor": "nx:run-commands", + "configurations": {} + } + }, + "name": "react-store", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/react-store/src", + "projectType": "application", + "tags": [], + "implicitDependencies": [] + } + }, + "sourceMap": { + "root": ["apps/react-store/project.json", "nx/core/project-json"], + "targets": ["apps/react-store/project.json", "nx/core/project-json"], + "targets.build": ["apps/react-store/vite.config.ts", "@nx/vite/plugin"], + "targets.build.command": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.cache": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.dependsOn": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.inputs": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.outputs": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "targets.build.options.cwd": [ + "apps/react-store/vite.config.ts", + "@nx/vite/plugin" + ], + "name": ["apps/react-store/project.json", "nx/core/project-json"], + "$schema": ["apps/react-store/project.json", "nx/core/project-json"], + "sourceRoot": ["apps/react-store/project.json", "nx/core/project-json"], + "projectType": ["apps/react-store/project.json", "nx/core/project-json"], + "tags": ["apps/react-store/project.json", "nx/core/project-json"] + } +} +``` + +{% /project-details %} + +If you expand the `build` task, you can see that it was created by the `@nx/vite` plugin by analyzing your `vite.config.ts` file. Notice the outputs are defined as `{projectRoot}/dist`. This value is being read from the `build.outDir` defined in your `vite.config.ts` file. Let's change that value in your `vite.config.ts` file: + +```ts {% fileName="apps/react-store/vite.config.ts" %} +export default defineConfig({ + // ... + build: { + outDir: './build', + // ... + }, +}); +``` + +Now if you look at the project details view, the outputs for the build target will say `{projectRoot}/build`. This feature ensures that Nx will always cache the correct files. + +You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`package.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. + +Set the `outDir` back to `./dist` so that we don't have to modify all the other tools to account for a different build output folder. + +```ts {% fileName="apps/react-store/vite.config.ts" %} +export default defineConfig({ + // ... + build: { + outDir: './dist', + // ... + }, +}); +``` + +## Add Another Application + +Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin provides, run the following command and inspect the output: + +```{% command="npx nx list @nx/react" path="react-monorepo" %} + +NX Capabilities in @nx/react: + +GENERATORS + +init : Initialize the `@nx/react` plugin. +application : Create a React application. +library : Create a React library. +component : Create a React component. +redux : Create a Redux slice for a project. +storybook-configuration : Set up storybook for a React app or library. +component-story : Generate storybook story for a React component +stories : Create stories/specs for all components declared in an app or library. +hook : Create a hook. +host : Generate a host react application +remote : Generate a remote react application +cypress-component-configuration : Setup Cypress component testing for a React project +component-test : Generate a Cypress component test for a React component +setup-tailwind : Set up Tailwind configuration for a project. +setup-ssr : Set up SSR configuration for a project. +federate-module : Federate a module. + +EXECUTORS/BUILDERS + +module-federation-dev-server : Serve a host or remote application. +module-federation-ssr-dev-server : Serve a host application along with it's known remotes. +module-federation-static-server : Serve a host and its remotes statically. +``` + +{% callout type="info" title="Prefer a more visual UI?" %} + +If you prefer a more integrated experience, you can install the "Nx Console" extension for your code editor. It has support for VSCode, IntelliJ and ships a LSP for Vim. Nx Console provides autocompletion support in Nx configuration files and has UIs for browsing and running generators. + +More info can be found in [the integrate with editors article](/getting-started/editor-setup). + +{% /callout %} + +Run the following command to generate a new `inventory` application. Note how we append `--dry-run` to first check the output. + +```{% command="npx nx g @nx/react:app apps/inventory" path="react-monorepo" %} + NX Generating @nx/react:application + +✔ Would you like to add routing to this application? (y/N) · false +✔ What unit test runner should be used? · vitest +✔ Which E2E test runner would you like to use? · playwright +CREATE apps/inventory/index.html +CREATE apps/inventory/public/favicon.ico +CREATE apps/inventory/src/app/app.spec.tsx +CREATE apps/inventory/src/assets/.gitkeep +CREATE apps/inventory/src/main.tsx +CREATE apps/inventory/tsconfig.app.json +CREATE apps/inventory/src/app/nx-welcome.tsx +CREATE apps/inventory/src/app/app.module.css +CREATE apps/inventory/src/app/app.tsx +CREATE apps/inventory/src/styles.css +CREATE apps/inventory/tsconfig.json +CREATE apps/inventory/package.json +CREATE apps/inventory/eslint.config.mjs +UPDATE nx.json +CREATE apps/inventory/tsconfig.spec.json +CREATE apps/inventory/vite.config.ts +CREATE apps/inventory-e2e/package.json +CREATE apps/inventory-e2e/src/example.spec.ts +CREATE apps/inventory-e2e/playwright.config.ts +UPDATE tsconfig.json +CREATE apps/inventory-e2e/tsconfig.json +CREATE apps/inventory-e2e/eslint.config.mjs + +NOTE: The "dryRun" flag means no changes were made. +``` + +As you can see, it generates a new application in the `apps/inventory/` folder. Let's actually run the generator by removing the `--dry-run` flag. + +```shell +npx nx g @nx/react:app apps/inventory +``` + +## Share Code with Local Libraries + +When you develop your React application, usually all your logic sits in the `app` folder. Ideally separated by various folder names which represent your "domains". As your app grows, however, the app becomes more and more monolithic and the code is unable to be shared with other applications. + +``` +└─ react-monorepo + ├─ ... + ├─ apps + │ └─ react-store + │ ├─ ... + │ ├─ src + │ │ ├─ app + │ │ │ ├─ products + │ │ │ ├─ cart + │ │ │ ├─ ui + │ │ │ ├─ ... + │ │ │ └─ app.tsx + │ │ ├─ ... + │ │ └─ main.tsx + │ ├─ ... + │ └─ package.json + ├─ nx.json + ├─ ... +``` + +Nx allows you to separate this logic into "local libraries". The main benefits include + +- better separation of concerns +- better reusability +- more explicit "APIs" between your "domain areas" +- better scalability in CI by enabling independent test/lint/build commands for each library +- better scalability in your teams by allowing different teams to work on separate libraries + +### Create Local Libraries + +Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for each of these areas using the React library generator: + +``` +npx nx g @nx/react:library libs/products --unitTestRunner=vitest --bundler=none +npx nx g @nx/react:library libs/orders --unitTestRunner=vitest --bundler=none +npx nx g @nx/react:library libs/shared/ui --unitTestRunner=vitest --bundler=none +``` + +Note how we type out the full path in the `directory` flag to place the libraries into a subfolder. You can choose whatever folder structure you like to organize your projects. If you change your mind later, you can run the [move generator](/nx-api/workspace/generators/move) to move a project to a different folder. + +Running the above commands should lead to the following directory structure: + +``` +└─ react-monorepo + ├─ ... + ├─ apps + ├─ libs + │ ├─ products + │ │ ├─ ... + │ │ ├─ package.json + │ │ ├─ src + │ │ │ ├─ index.ts + │ │ │ └─ lib + │ │ │ ├─ products.spec.ts + │ │ │ └─ products.ts + │ │ ├─ tsconfig.json + │ │ ├─ tsconfig.lib.json + │ │ ├─ tsconfig.spec.json + │ │ └─ vite.config.ts + │ ├─ orders + │ │ ├─ ... + │ │ ├─ package.json + │ │ ├─ src + │ │ │ ├─ index.ts + │ │ │ └─ ... + │ │ └─ ... + │ └─ shared + │ └─ ui + │ ├─ ... + │ ├─ package.json + │ ├─ src + │ │ ├─ index.ts + │ │ └─ ... + │ └─ ... + ├─ ... +``` + +Each of these libraries + +- has a project details view where you can see the available tasks (e.g. running tests for just orders: `npx nx test orders`) +- has its own `package.json` file where you can customize targets +- has the name you specified in the generate command; you can find the name in the corresponding `package.json` file +- has a dedicated `index.ts` file which is the "public API" of the library +- is included in the `workspaces` property of the `package.json` file at the root of the workspace + +### Import Libraries into the React Applications + +All libraries that we generate are automatically included in the `workspaces` defined in the root-level `package.json`. + +```json {% fileName="package.json" %} +{ + "workspaces": ["apps/*", "libs/*", "libs/shared/*"] +} +``` + +Hence we can easily import them into other libraries and our React application. As an example, let's use the pre-generated `ProductsComponent` component from our `libs/products` library. + +You can see that the `Products` component is exported via the `index.ts` file of our `products` library so that other projects in the repository can use it. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself. + +```ts {% fileName="libs/products/src/index.ts" %} +export * from './lib/products'; +``` + +We're ready to import it into our main application now. First (if you haven't already), let's set up React Router. + +{% tabs %} +{% tab label="npm" %} + +```shell +npm add react-router-dom +``` + +{% /tab %} +{% tab label="yarn" %} + +```shell +yarn add react-router-dom +``` + +{% /tab %} +{% tab label="pnpm" %} + +```shell +pnpm add react-router-dom +``` + +{% /tab %} + +{% tab label="bun" %} + +```shell +bun add react-router-dom +``` + +{% /tab %} +{% /tabs %} + +Configure it in the `main.tsx`. + +```tsx {% fileName="apps/react-store/src/main.tsx" %} +import { StrictMode } from 'react'; +import { BrowserRouter } from 'react-router-dom'; +import ReactDOM from 'react-dom/client'; + +import App from './app/app'; + +const root = ReactDOM.createRoot( + document.getElementById('root') as HTMLElement +); + +root.render( + + + + + +); +``` + +Then we can import the `Products` component into our `app.tsx` and render it via the routing mechanism whenever a user hits the `/products` route. + +```tsx {% fileName="apps/react-store/src/app/app.tsx" %} +import { Route, Routes } from 'react-router-dom'; + +// importing the component from the library +import { Products } from '@react-monorepo/products'; + +function Home() { + return

Welcome react-store

; +} + +export function App() { + return ( + + }> + }> + + ); +} + +export default App; +``` + +Serving your app (`npx nx serve react-store`) and then navigating to `/products` should give you the following result: + +![products route](/shared/tutorials/react-tutorial-products-route.png) + +Let's apply the same for our `orders` library. + +- import the `Orders` component from `libs/orders` into the `app.tsx` and render it via the routing mechanism whenever a user hits the `/orders` route + +In the end, your `app.tsx` should look similar to this: + +```tsx {% fileName="apps/react-store/src/app/app.tsx" %} +import { Route, Routes } from 'react-router-dom'; +import { Products } from '@react-monorepo/products'; +import { Orders } from '@react-monorepo/orders'; + +function Home() { + return

Home

; +} + +export function App() { + return ( + + }> + }> + }> + + ); +} + +export default App; +``` + +Let's also show products in the `inventory` app. + +```tsx {% fileName="apps/inventory/src/app/app.tsx" %} +import { Products } from '@react-monorepo/products'; + +export function App() { + return ; +} + +export default App; +``` + +## Visualize your Project Structure + +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `npx nx build`, identifying [affected projects](/features/run-tasks#run-tasks-on-projects-affected-by-a-pr) and more. Interestingly you can also visualize it. + +Just run: + +```shell +npx nx graph +``` + +You should be able to see something similar to the following in your browser. + +{% graph height="450px" %} + +```json +{ + "projects": [ + { + "name": "react-store", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "react-store-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "inventory", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "inventory-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "shared-ui", + "type": "lib", + "data": { + "tags": [] + } + }, + { + "name": "orders", + "type": "lib", + "data": { + "tags": [] + } + }, + + { + "name": "products", + "type": "lib", + "data": { + "tags": [] + } + } + ], + "dependencies": { + "react-store": [ + { "source": "react-store", "target": "orders", "type": "static" }, + { "source": "react-store", "target": "products", "type": "static" } + ], + "react-store-e2e": [ + { + "source": "react-store-e2e", + "target": "react-store", + "type": "implicit" + } + ], + "inventory": [ + { "source": "inventory", "target": "products", "type": "static" } + ], + "inventory-e2e": [ + { "source": "inventory-e2e", "target": "inventory", "type": "implicit" } + ], + "shared-ui": [], + "orders": [], + "products": [] + }, + "workspaceLayout": { "appsDir": "", "libsDir": "" }, + "affectedProjectIds": [], + "focus": null, + "groupByFolder": false +} +``` + +{% /graph %} + +Notice how `ui` is not yet connected to anything because we didn't import it in any of our projects. + +Exercise for you: change the codebase such that `ui` is used by `orders` and `products`. Note: you need to restart the `npx nx graph` command to update the graph visualization or run the CLI command with the `--watch` flag. + +## Testing and Linting - Running Multiple Tasks + +Our current setup doesn't just come with targets for serving and building the React application, but also has targets for unit testing, e2e testing and linting. We can use the same syntax as before to run these tasks: + +```bash +npx nx test react-store # runs the tests for react-store +npx nx lint inventory # runs the linter on inventory +npx nx e2e react-store-e2e # runs e2e tests for the react-store +``` + +More conveniently, we can also run tasks in parallel using the following syntax: + +```shell +npx nx run-many -t test +``` + +These tasks are automatically configured by through [Nx plugins](/concepts/inferred-tasks). You can view available tasks for a project by using the `nx show project` command. + +```shell +npx nx show project react-store +npx nx show project react-store-e2e +npx nx show project inventory + +# To list all projects +npx nx show projects +``` + +### Cache Tasks + +One thing to highlight is that Nx is able to [cache the tasks you run](/features/cache-task-results). + +Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. + +```{% command="npx nx run-many -t test lint e2e" path="react-monorepo" %} +✔ nx run @react-monorepo/ui:lint [existing outputs match the cache, left as is] +✔ nx run inventory-e2e:lint [existing outputs match the cache, left as is] +✔ nx run react-store-e2e:lint [existing outputs match the cache, left as is] +✔ nx run @react-monorepo/ui:test [existing outputs match the cache, left as is] + +—————————————————————————————————————————————————————— + +NX Successfully ran targets test, lint, e2e for 7 projects (54ms) + +Nx read the output from the cache instead of running the command for 10 out of 10 tasks. +``` + +Not all tasks might be cacheable though. You can configure the `cache` settings in the `targetDefaults` property of the `nx.json` file. You can also [learn more about how caching works](/features/cache-task-results). + +### Test Affected Projects + +Commit your changes to git. + +```shell +git commit -a -m "some commit message" +``` + +And then make a small change to the `products` library. + +```tsx {% fileName="libs/products/src/lib/products.tsx" %} +import styles from './products.module.css'; + +export function Products() { + return ( +
+

Welcome to Products!

+

This is a change. 👋

+
+ ); +} + +export default Products; +``` + +One of the key features of Nx in a monorepo setting is that you're able to run tasks only for projects that are actually affected by the code changes that you've made. To run the tests for only the projects affected by this change, run: + +```shell +npx nx affected -t test +``` + +Note that the unit tests were run for `products`, `react-store` and `inventory`, but not for `orders` because a change to `products` can not possibly break the tests for `orders`. In a small repo like this, there isn't a lot of time saved, but as there are more tests and more projects, this quickly becomes an essential command. + +You can also see what projects are affected in the graph visualizer with; + +```shell +npx nx graph --affected +``` + +{% graph height="450px" %} + +```json +{ + "projects": [ + { + "name": "react-store", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "react-store-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "inventory", + "type": "app", + "data": { + "tags": [] + } + }, + { + "name": "inventory-e2e", + "type": "e2e", + "data": { + "tags": [] + } + }, + { + "name": "shared-ui", + "type": "lib", + "data": { + "tags": [] + } + }, + { + "name": "orders", + "type": "lib", + "data": { + "tags": [] + } + }, + + { + "name": "products", + "type": "lib", + "data": { + "tags": [] + } + } + ], + "dependencies": { + "react-store": [ + { "source": "react-store", "target": "orders", "type": "static" }, + { "source": "react-store", "target": "products", "type": "static" } + ], + "react-store-e2e": [ + { + "source": "react-store-e2e", + "target": "react-store", + "type": "implicit" + } + ], + "inventory": [ + { "source": "inventory", "target": "products", "type": "static" } + ], + "inventory-e2e": [ + { "source": "inventory-e2e", "target": "inventory", "type": "implicit" } + ], + "shared-ui": [], + "orders": [], + "products": [] + }, + "workspaceLayout": { "appsDir": "", "libsDir": "" }, + "affectedProjectIds": [ + "products", + "inventory", + "inventory-e2e", + "react-store", + "react-store-e2e" + ], + "focus": null, + "groupByFolder": false +} +``` + +{% /graph %} + +## Build the Apps for Deployment + +If you're ready and want to ship your applications, you can build them using + +```{% command="npx nx run-many -t build" path="react-monorepo" %} + ✔ nx run @react-monorepo/inventory:build (841ms) + ✔ nx run @react-monorepo/react-store:build (968ms) + +————————————————————————————————————————————————————————————— + + NX Successfully ran target build for 2 projects (1s) +``` + +All the required files will be placed in `apps/react-store/dist` and `apps/inventory/dist` and can be deployed to your favorite hosting provider. + +Nx will run any script defined in `package.json`, so you can create a `deploy` task that sends the build output to your hosting provider. + +```json {% fileName="apps/react-store/package.json" %} +{ + "scripts": { + "deploy": "netlify deploy --dir=dist" +} +``` + +We want to let Nx know that the `build` task needs to be run before the `deploy` task, so we add a `dependsOn` property for that target. + +```json {% fileName="apps/react-store/package.json" %} +{ + "scripts": { + "deploy": "netlify deploy --dir=dist" + }, + "nx": { + "targets": { + "deploy": { + "dependsOn": ["build"] + } + } + } +} +``` + +If you want to keep the script next to its Nx configuration, you can rewrite the above configuration like this: + +```json {% fileName="apps/react-store/package.json" %} +{ + "scripts": {}, + "nx": { + "targets": { + "deploy": { + "command": "netlify deploy --dir=dist", + "dependsOn": ["build"] + } + } + } +} +``` + +Replace the `deploy` script with whatever terminal command you use to deploy your site. + +The `"dependsOn": ["build"]` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. + +With the `deploy` tasks defined, you can deploy a single application with `npx nx deploy react-store` or deploy any applications affected by the current changes with: + +```shell +npx nx affected -t deploy +``` + +## Imposing Constraints with Module Boundary Rules + +Once you modularize your codebase you want to make sure that the libs are not coupled to each other in an uncontrolled way. Here are some examples of how we might want to guard our small demo workspace: + +- we might want to allow `orders` to import from `shared-ui` but not the other way around +- we might want to allow `orders` to import from `products` but not the other way around +- we might want to allow all libraries to import the `shared-ui` components, but not the other way around + +When building these kinds of constraints you usually have two dimensions: + +- **type of project:** what is the type of your library. Example: "feature" library, "utility" library, "data-access" library, "ui" library +- **scope (domain) of the project:** what domain area is covered by the project. Example: "orders", "products", "shared" ... this really depends on the type of product you're developing + +Nx comes with a generic mechanism that allows you to assign "tags" to projects. "tags" are arbitrary strings you can assign to a project that can be used later when defining boundaries between projects. For example, go to the `package.json` of your `orders` library and assign the tags `type:feature` and `scope:orders` to it. + +```json {% fileName="libs/orders/package.json" %} +{ + ... + "nx": { + "tags": ["type:feature", "scope:orders"] + } +} +``` + +Then go to the `package.json` of your `products` library and assign the tags `type:feature` and `scope:products` to it. + +```json {% fileName="libs/products/package.json" %} +{ + ... + "nx": { + "tags": ["type:feature", "scope:products"] + } +} +``` + +Finally, go to the `package.json` of the `shared-ui` library and assign the tags `type:ui` and `scope:shared` to it. + +```json {% fileName="libs/shared/ui/package.json" %} +{ + ... + "nx": { + "tags": ["type:ui", "scope:shared"] + } +} +``` + +Notice how we assign `scope:shared` to our UI library because it is intended to be used throughout the workspace. + +Next, let's come up with a set of rules based on these tags: + +- `type:feature` should be able to import from `type:feature` and `type:ui` +- `type:ui` should only be able to import from `type:ui` +- `scope:orders` should be able to import from `scope:orders`, `scope:shared` and `scope:products` +- `scope:products` should be able to import from `scope:products` and `scope:shared` + +To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.base.json` at the root of the workspace and add the following `depConstraints` in the `@nx/enforce-module-boundaries` rule configuration: + +```js {% fileName="eslint.config.mjs" %} +import nx from '@nx/eslint-plugin'; + +export default [ + // ... + { + files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'], + rules: { + '@nx/enforce-module-boundaries': [ + 'error', + { + enforceBuildableLibDependency: true, + allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?js$'], + depConstraints: [ + { + sourceTag: 'type:feature', + onlyDependOnLibsWithTags: ['type:feature', 'type:ui'], + }, + { + sourceTag: 'type:ui', + onlyDependOnLibsWithTags: ['type:ui'], + }, + { + sourceTag: 'scope:orders', + onlyDependOnLibsWithTags: [ + 'scope:orders', + 'scope:products', + 'scope:shared', + ], + }, + { + sourceTag: 'scope:products', + onlyDependOnLibsWithTags: ['scope:products', 'scope:shared'], + }, + { + sourceTag: 'scope:shared', + onlyDependOnLibsWithTags: ['scope:shared'], + }, + { + sourceTag: '*', + onlyDependOnLibsWithTags: ['*'], + }, + ], + }, + ], + }, + }, + // ... +]; +``` + +To test it, go to your `libs/products/src/lib/products.tsx` file and import the `Orders` component from the `orders` project: + +```tsx {% fileName="libs/products/src/lib/products.tsx" %} +import styles from './products.module.css'; + +// This import is not allowed 👇 +import { Orders } from '@react-monorepo/orders'; + +export function Products() { + return ( +
+

Welcome to Products!

+

This is a change. 👋

+
+ ); +} + +export default Products; +``` + +If you lint your workspace you'll get an error now: + +```{% command="npx nx run-many -t lint" %} + + ✔ nx run @react-monorepo/orders:lint [existing outputs match the cache, left as is] + ✔ nx run @react-monorepo/react-store:lint [existing outputs match the cache, left as is] + ✔ nx run @react-monorepo/inventory:lint [existing outputs match the cache, left as is] + ✔ nx run @react-monorepo/ui:lint [existing outputs match the cache, left as is] + ✔ nx run inventory-e2e:lint [existing outputs match the cache, left as is] + ✔ nx run react-store-e2e:lint (877ms) + +———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + ✖ nx run @react-monorepo/products:lint + > eslint . + + + /Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/products.tsx + 3:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries + 3:10 warning 'Orders' is defined but never used @typescript-eslint/no-unused-vars + + ✖ 2 problems (1 error, 1 warning) + + + + +———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— + + NX Ran target lint for 7 projects (1s) + + ✔ 6/7 succeeded [5 read from cache] + + ✖ 1/7 targets failed, including the following: + + - nx run @react-monorepo/products:lint +``` + +If you have the ESLint plugin installed in your IDE you should also immediately see an error. + +Learn more about how to [enforce module boundaries](/features/enforce-module-boundaries). + +## Fast CI ⚡ {% highlightColor="green" %} + +{% callout type="check" title="Repository with Nx" %} +Make sure you have completed the previous sections of this tutorial before starting this one. If you want a clean starting point, you can check out the [reference code](https://github.com/nrwl/nx-recipes/tree/main/react-monorepo) as a starting point. +{% /callout %} + +This tutorial walked you through how Nx can improve the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. + +- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). +- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. +- Nx Agents [efficiently distribute tasks across machines](/ci/concepts/parallelization-distribution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. +- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). + +### Connect to Nx Cloud {% highlightColor="green" %} + +Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. + +Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository. + +1. Commit your existing changes with `git add . && git commit -am "updates"` +2. [Create a new GitHub repository](https://github.com/new) +3. Follow GitHub's instructions to push your existing code to the repository + +When we set up the repository at the beginning of this tutorial, we chose to use GitHub Actions as a CI provider. This created a basic CI pipeline and configured Nx Cloud in the repository. It also printed a URL in the terminal to register your repository in your [Nx Cloud](https://cloud.nx.app) account. If you didn't click on the link when first creating your repository, you can show it again by running: + +```shell +npx nx connect +``` + +Once you click the link, follow the steps provided and make sure Nx Cloud is enabled on the main branch of your repository. + +### Configure Your CI Workflow {% highlightColor="green" %} + +When you chose GitHub Actions as your CI provider at the beginning of the tutorial, `create-nx-workspace` created a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. + +If you need to generate a new workflow file for GitHub Actions or other providers, you can do so with this command: + +```shell +npx nx generate ci-workflow +``` + +The key lines in the CI pipeline are: + +```yml {% fileName=".github/workflows/ci.yml" highlightLines=["11-15", "27-31"] %} +name: CI +# ... +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + filter: tree:0 + + # This enables task distribution via Nx Cloud + # Run this command as early as possible, before dependencies are installed + # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun + # Uncomment this line to enable task distribution + # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" + + # Cache node_modules + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + + - run: npm ci --legacy-peer-deps + - run: npx playwright install --with-deps + - uses: nrwl/nx-set-shas@v4 + + # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud + # - run: npx nx-cloud record -- echo Hello World + # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected + # When you enable task distribution, run the e2e-ci task instead of e2e + - run: npx nx affected -t lint test build e2e +``` + +### Open a Pull Request {% highlightColor="green" %} + +Commit the changes and open a new PR on GitHub. + +```shell +git add . +git commit -m 'add CI workflow file' +git push origin add-workflow +``` + +When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run. + +![Nx Cloud report](/shared/tutorials/github-pr-cloud-report.avif) + +The `See all runs` link goes to a page with the progress and results of tasks that were run in the CI pipeline. + +![Run details](/shared/tutorials/nx-cloud-run-details.avif) + +For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: + +- [Circle CI with Nx](/ci/intro/tutorials/circle) +- [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) + +## Next Steps + +Here's some things you can dive into next: + +- Learn more about the [underlying mental model of Nx](/concepts/mental-model) +- Learn how to [migrate your React app to Nx](/recipes/adopting-nx/adding-to-existing-project) +- [Learn how to setup Tailwind](/recipes/react/using-tailwind-css-in-react) +- [Setup Storybook for our shared UI library](/recipes/storybook/overview-react) + +Also, make sure you + +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! +- [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](/blog) +- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights diff --git a/docs/shared/tutorials/typescript-packages.md b/docs/shared/tutorials/typescript-packages.md new file mode 100644 index 0000000000..9ac8507e95 --- /dev/null +++ b/docs/shared/tutorials/typescript-packages.md @@ -0,0 +1,505 @@ +--- +title: 'TypeScript Monorepo Tutorial' +description: In this tutorial you'll add Nx to an existing TypeScript repo +--- + +# TypeScript Monorepo Tutorial + +In this tutorial, you'll learn how to add Nx to a repository with an existing TypeScript project. The starting repository uses [NPM workspaces](https://docs.npmjs.com/cli/using-npm/workspaces) for project linking and is configured to build with [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html). + +What will you learn? + +- how to add Nx to the repository with a single command +- how to configure caching for your tasks +- how to configure a task pipeline +- how to configure projects automatically with Nx Plugins +- how to manage your releases with `nx release` +- [how to speed up CI with Nx Cloud ⚡](#fast-ci) + + + + + +## Starting Repository + + + +To get started, fork [the sample repository](https://github.com/nrwl/tuskydesign/fork) and clone it on your local machine: + +```shell +git clone https://github.com//tuskydesign.git +``` + +The repository has three TypeScript packages under `packages/animals`, `packages/names` and `packages/zoo`. The `zoo` package uses `animals` and `names` to generate a random message. The root `package.json` has a `workspaces` property that tells NPM how to find the projects in the repository. + +```json {% fileName="package.json" %} +{ + "workspaces": ["packages/*"] +} +``` + +Because of this setting, when the install command is run at the root, the correct packages are installed for each project. NPM will create dedicated `node_modules` folders inside of each project folder where necessary. + +```shell +npm install +``` + +Now let's try running some tasks. To build the `animals` package, use the `build` npm script: + +```text {% command="npm run build -w @tuskdesign/animals" path="~/tuskydesigns" %} +> @tuskdesign/animals@1.2.0 build +> tsc --build tsconfig.lib.json +``` + +The repository is set up using [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html) so building the `zoo` package will automatically build all its dependencies. + +```text {% command="npm run build -w @tuskdesign/zoo" path="~/tuskydesigns" %} +> @tuskdesign/zoo@1.2.0 build +> tsc --build tsconfig.lib.json +``` + +To run the `zoo` package use the `serve` script: + +```text {% command="npm run serve -w @tuskdesign/zoo" path="~/tuskydesigns" %} +> @tuskdesign/zoo@1.2.0 serve +> node dist/index.js + +Bo the pig says oink! +``` + +Now that you have a basic understanding of the repository we're working with, let's see how Nx can help us. + +## Smart Monorepo + + + +Nx offers many features, but at its core, it is a task runner. Out of the box, it can cache your tasks and ensure those tasks are run in the correct order. After the initial set up, you can incrementally add on other features that would be helpful in your organization. + +### Add Nx + +To enable Nx in your repository, run a single command: + +```shell {% path="~/tuskydesigns" %} +npx nx@latest init +``` + +This command will download the latest version of Nx and help set up your repository to take advantage of it. + +First, the script will propose installing some plugins based on the packages that are being used in your repository. + +- Deselect both proposed plugins so that we can explore what Nx provides without any plugins. + +Second, the script asks a series of questions to help set up caching for you. + +- `Which scripts need to be run in order?` - Choose `build` +- `Which scripts are cacheable?` - Choose `build` and `typecheck` +- `Does the "build" script create any outputs?` - Enter `dist` +- `Does the "typecheck" script create any outputs?` - Enter nothing +- `Would you like remote caching to make your build faster?` - Choose `Skip for now` + +### Explore Your Workspace + + + +If you run `nx graph` as instructed, you'll see the dependencies between your projects. + +```shell {% path="~/tuskydesigns" %} +npx nx graph --focus=@tuskdesign/zoo +``` + +{% graph title="Tusk Design" height="200px" jsonFile="shared/tutorials/typescript-packages-project-graph.json" %} +{% /graph %} + +Nx uses this graph to determine the order tasks are run and enforce module boundaries. You can also leverage this graph to gain an accurate understanding of the architecture of your codebase. Part of what makes this graph invaluable is that it is derived directly from your codebase, so it will never become out of date. + +### Caching Pre-configured + + + +Nx has been configured to run your `build`, `typecheck` and `lint` tasks. You can run a single task like this: + +```shell {% path="~/tuskydesigns" %} +npx nx build @tuskdesign/zoo +``` + +Or all tasks with a certain name like this: + +```shell {% path="~/tuskydesigns" %} +npx nx run-many -t typecheck +``` + +During the `init` script, Nx also configured caching for these tasks. You can see in the `nx.json` file that the `build`, `typecheck` and `lint` targets have the `cache` property set to `true` and the `build` target specifies that its output goes to the project's `dist` folder. + +```json {% fileName="nx.json" %} +{ + "$schema": "./node_modules/nx/schemas/nx-schema.json", + "targetDefaults": { + "build": { + "dependsOn": ["^build"], + "outputs": ["{projectRoot}/dist"], + "cache": true + }, + "typecheck": { + "cache": true + }, + "lint": { + "cache": true + } + }, + "defaultBase": "main" +} +``` + +Try running `build` for the `zoo` app a second time: + +```shell {% path="~/tuskydesigns" %} +npx nx build @tuskdesign/zoo +``` + +The first time `nx build` was run, it took about 1 second - just like running `npm run build`. But the second time you run `nx build`, it completes instantly and displays this message: + +```text +Nx read the output from the cache instead of running the command for 3 out of 3 tasks. +``` + +You can see the same caching behavior working when you run `npx nx typecheck`. + +### Use Task Pipelines + + + +You may be wondering why the caching message in the previous section mentioned 3 tasks when you only ran the `build` task from the terminal. When we said that `build` tasks must be run in order during the setup script, Nx created a simple task pipeline. You can see the configuration for it in the `nx.json` file: + +```json {% fileName="nx.json" %} +{ + "targetDefaults": { + "build": { + "dependsOn": ["^build"] + } + } +} +``` + +This configuration means that if you run `build` on any project, Nx will first run `build` for the dependencies of that project and then run `build` on the project itself. The `^build` text means "the `build` tasks of the project's dependencies." You can visualize this in the Nx graph by selecting the `Tasks` dropdown in the top left and clicking `Show all tasks`: + +```shell {% path="~/tuskydesigns" %} +npx nx graph +``` + +Alternatively, you can pass the `--graph` option to the run command to inspect the task graph. + +```shell {% path="~/tuskydesigns" %} +npx nx run @tuskdesign/zoo:build --graph +``` + +{% graph height="200px" title="Build Task Pipeline" type="task" jsonFile="shared/tutorials/typescript-packages-build-tasks1.json" %} +{% /graph %} + +### Create a Task Pipeline + + + +You may have noticed in the `packages/zoo/package.json` file, there is a `serve` script that expects the `build` task to already have created the `dist` folder. Let's set up a task pipeline that will guarantee that the project's `build` task has been run. + +```json {% fileName="nx.json" highlightLines=[5] %} +{ + "$schema": "./node_modules/nx/schemas/nx-schema.json", + "targetDefaults": { + "serve": { + "dependsOn": ["build"] + }, + "build": { + "dependsOn": ["^build"], + "outputs": ["{projectRoot}/dist"], + "cache": true + }, + "typecheck": { + "cache": true + } + }, + "defaultBase": "main" +} +``` + +The `serve` target's `dependsOn` line makes Nx run the `build` task for the current project before running the current project's `build` task. Now `nx serve` will run the `build` task before running the `serve` task. + +### Use Nx Plugins to Enhance Your Workspace + + + +We mentioned earlier that this repository is using TypeScript project references defined in the `tsconfig.json` files to incrementally build each project so that the output is available for other projects in the repository. In order for this feature to work, the `references` section in the `tsconfig.json` files for each project need to accurately reflect the actual dependencies of that project. This can be difficult to maintain, but Nx already knows the dependencies of every project and you can use the `@nx/js` plugin to automatically keep the TypeScript project references in sync with the code base. + +Nx plugins can: + +- automatically configure caching for you, including inputs and outputs based on the underlying tooling configuration +- infer tasks that can be run on a project because of the tooling present +- keep tooling configuration in sync with the structure of your codebase +- provide code generators to help scaffold out projects +- automatically keep the tooling versions and configuration files up to date + +For this tutorial, we'll focus on inferring tasks and keeping tooling configuration in sync. + +First, let's remove the existing `build` and `typecheck` scripts from each project's `package.json` files to allow the `@nx/js` plugin to infer those tasks for us. + +```json {% fileName="packages/animals/package.json" %} +{ + "scripts": {} +} +``` + +```json {% fileName="packages/names/package.json" %} +{ + "scripts": {} +} +``` + +```json {% fileName="packages/zoo/package.json" %} +{ + "scripts": { + "serve": "node dist/index.js" + } +} +``` + +Now let's add the `@nx/js` plugin: + +```{% command="npx nx add @nx/js" path="~/tuskydesign" %} +✔ Installing @nx/js... +✔ Initializing @nx/js... + NX Generating @nx/js:init + +UPDATE nx.json +UPDATE package.json + + NX Package @nx/js added successfully. +``` + +The `nx add` command installs the version of the plugin that matches your repo's Nx version and runs that plugin's initialization script. For `@nx/js`, the initialization script registers the plugin in the `plugins` array of `nx.json`. The registered plugin automatically infers `build` and `typecheck` tasks for any project with a `tsconfig.json` file. Open the project details view for the `zoo` package and look at the `build` task. + +```shell {% path="~/tuskydesigns" %} +npx nx show project @tuskdesign/zoo +``` + +{% project-details title="Project Details View" jsonFile="shared/tutorials/typescript-packages-pdv.json" %} +{% /project-details %} + +Notice that the `inputs` that are inferred for the `build` task match the `include` and `exclude` settings in the `tsconfig.lib.json` file. As those settings are changed, the cache `inputs` will automatically update to the correct values. + +The `build` task also has a [sync generator](/concepts/sync-generators) defined. The `@nx/js:typescript-sync` generator will automatically update the `references` property in the `tsconfig.json` files across the repository to match the actual dependencies in your code. + +Let's see this behavior in action by extracting some common code into a new `util` library. + +First, create a library with `@nx/js:lib` generator: + +```shell +nx g @nx/js:lib packages/util +``` + +Set the bundler to `tsc`, the linter to `none` and the unit test runner to `none`. + +Now we can move the `getRandomItem` function from `packages/names/names.ts` and `packages/animals/animals.ts` into the `packages/util/src/lib/util.ts` file. + +```ts {% fileName="packages/util/src/lib/util.ts" %} +export function getRandomItem(arr: T[]): T { + return arr[Math.floor(Math.random() * arr.length)]; +} +``` + +```ts {% fileName="packages/animals/animals.ts" %} +import { getRandomItem } from '@tuskdesign/util'; + +// ... +``` + +```ts {% fileName="packages/names/names.ts" %} +import { getRandomItem } from '@tuskdesign/util'; + +// ... +``` + +Now if you run the build, Nx will notice that the TypeScript project references need to be updated and ask your permission to update them. + +```text {% command="nx build @tuskdesign/zoo" path="~/tuskydesigns" %} + NX The workspace is out of sync + +[@nx/js:typescript-sync]: Some TypeScript configuration files are missing project references to the projects they depend on or contain outdated project references. + +This will result in an error in CI. + +? Would you like to sync the identified changes to get your workspace up to date? … +❯ Yes, sync the changes and run the tasks + No, run the tasks without syncing the changes +``` + +Allow the sync to happen and you'll see that the `tsconfig.json` and `tsconfig.lib.json` files have been updated to include references to the new `util` library. With this system in place, no matter how your codebase changes, the TypeScript project references will always be correct. + +### Checkpoint + +At this point, the repository is still using all the same tools to run tasks, but now Nx runs those tasks in a smarter way. The tasks are efficiently cached so that there is no repeated work and the cache configuration settings are automatically synced with your tooling configuration files by Nx plugins. Also, any task dependencies are automatically executed whenever needed because we configured task pipelines for the projects. + +Open up the task graph for `zoo` app's `serve` task again to see the changes. + +```shell {% path="~/tuskydesigns" %} +npx nx run @tuskdesign/zoo:serve --graph +``` + +{% graph height="200px" title="Build Task Pipeline" type="task" jsonFile="shared/tutorials/typescript-packages-build-tasks2.json" %} +{% /graph %} + +## Manage Releases + + + +If you decide to publish the `animals` or `names` packages on NPM, Nx can also help you [manage the release process](/features/manage-releases). Release management involves updating the version of your package, populating a changelog, and publishing the new version to the NPM registry. + +First you'll need to define which projects Nx should manage releases for by setting the `release.projects` property in `nx.json`: + +```json {% fileName="nx.json" %} +{ + "release": { + "projects": ["packages/*"] + } +} +``` + +Now you're ready to use the `nx release` command to publish the `animals` and `names` packages. The first time you run `nx release`, you need to add the `--first-release` flag so that Nx doesn't try to find the previous version to compare against. It's also recommended to use the `--dry-run` flag until you're sure about the results of the `nx release` command, then you can run it a final time without the `--dry-run` flag. + +To preview your first release, run: + +```shell +npx nx release --first-release --dry-run +``` + +The command will ask you a series of questions and then show you what the results would be. Once you are happy with the results, run it again without the `--dry-run` flag: + +```shell +npx nx release --first-release +``` + +After this first release, you can remove the `--first-release` flag and just run `nx release --dry-run`. There is also a [dedicated feature page](/features/manage-releases) that goes into more detail about how to use the `nx release` command. + +## Fast CI ⚡ {% highlightColor="green" %} + + + +{% callout type="check" title="Forked repository with Nx" %} +Make sure you have completed the previous sections of this tutorial before starting this one. If you want a clean starting point, you can fork the [sample repository with Nx already added](https://github.com/nrwl/nx-recipes/tree/main/typescript-packages). +{% /callout %} + +So far in this tutorial you've seen how Nx improves the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. + +- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). +- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. +- Nx Agents [efficiently distribute tasks across machines](/ci/features/distribute-task-execution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. +- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). + +### Connect to Nx Cloud {% highlightColor="green" %} + +Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. + +Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository. + +1. Commit your existing changes with `git add . && git commit -am "updates"` +2. Push your changes to your forked GitHub repository with `git push` + +Now connect your repository to Nx Cloud with the following command: + +```shell +npx nx connect +``` + +A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. + +![](/shared/tutorials/nx-cloud-github-connect.avif) + +Once the PR is created, merge it into your main branch. + +![](/shared/tutorials/github-cloud-pr-merged.avif) + +And make sure you pull the latest changes locally: + +```shell +git pull +``` + +You should now have an `nxCloudId` property specified in the `nx.json` file. + +### Create a CI Workflow {% highlightColor="green" %} + +Use the following command to generate a CI workflow file. + +```shell +npx nx generate ci-workflow --ci=github +``` + +This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. + +The key lines in the CI pipeline are: + +```yml {% fileName=".github/workflows/ci.yml" highlightLines=["10-14", "21-23"] %} +name: CI +# ... +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + filter: tree:0 + + # This enables task distribution via Nx Cloud + # Run this command as early as possible, before dependencies are installed + # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun + # Uncomment this line to enable task distribution + # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci" + - uses: actions/setup-node@v3 + with: + node-version: 20 + cache: 'npm' + - run: npm ci --legacy-peer-deps + - uses: nrwl/nx-set-shas@v4 + # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected + # When you enable task distribution, run the e2e-ci task instead of e2e + - run: npx nx affected -t lint test build e2e +``` + +### Open a Pull Request {% highlightColor="green" %} + +Commit the changes and open a new PR on GitHub. + +```shell +git add . +git commit -m 'add CI workflow file' +git push origin add-workflow +``` + +When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run. + +![Nx Cloud report](/shared/tutorials/github-pr-cloud-report.avif) + +The `See all runs` link goes to a page with the progress and results of tasks that were run in the CI pipeline. + +![Run details](/shared/tutorials/nx-cloud-run-details.avif) + +For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: + +- [Circle CI with Nx](/ci/intro/tutorials/circle) +- [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) + +## Next Steps + +Connect with the rest of the Nx community with these resources: + +- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! +- [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](/blog) +- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights diff --git a/nx-dev/nx-dev/pages/[...segments].tsx b/nx-dev/nx-dev/pages/[...segments].tsx index 52f6e4b782..12bd270974 100644 --- a/nx-dev/nx-dev/pages/[...segments].tsx +++ b/nx-dev/nx-dev/pages/[...segments].tsx @@ -56,7 +56,7 @@ export default function NxDocumentation({ } export const getStaticPaths: GetStaticPaths = () => { - const reservedPaths = ['/ci', '/nx-api', '/changelog', '/tutorials']; + const reservedPaths = ['/ci', '/nx-api', '/changelog']; return { paths: nxDocumentationApi .getSlugsStaticDocumentPaths() diff --git a/nx-dev/nx-dev/pages/tutorials.tsx b/nx-dev/nx-dev/pages/tutorials.tsx index ef91bb0a76..4f014e7fa3 100644 --- a/nx-dev/nx-dev/pages/tutorials.tsx +++ b/nx-dev/nx-dev/pages/tutorials.tsx @@ -62,7 +62,7 @@ export default function Tutorials(): JSX.Element { diff --git a/nx-dev/nx-dev/redirect-rules.js b/nx-dev/nx-dev/redirect-rules.js index 9d566cda6e..440f4da811 100644 --- a/nx-dev/nx-dev/redirect-rules.js +++ b/nx-dev/nx-dev/redirect-rules.js @@ -600,42 +600,42 @@ for (const path of oldAngularTutorialPaths) { */ const standaloneTutorialRedirects = { '/showcase/example-repos/react-nx': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', - '/react-tutorial': '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', + '/react-tutorial': '/getting-started/tutorials/react-monorepo-tutorial', '/react-tutorial/1-code-generation': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-tutorial/2-project-graph': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-tutorial/3-task-running': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-tutorial/4-task-pipelines': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-tutorial/5-summary': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial/1-code-generation': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial/2-project-graph': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial/3-task-running': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial/4-task-pipelines': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/react-standalone-tutorial/5-summary': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/angular-standalone-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-standalone-tutorial/1-code-generation': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-standalone-tutorial/2-project-graph': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-standalone-tutorial/3-task-running': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-standalone-tutorial/4-task-pipelines': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-standalone-tutorial/5-summary': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', }; const packagesIndexes = { @@ -773,17 +773,17 @@ const conceptUrls = { '/concepts/more-concepts/global-nx': '/getting-started/installation#installing-nx-globally', '/getting-started/package-based-repo-tutorial': - '/tutorials/1-ts-packages/1t-introduction/1-welcome', + '/getting-started/tutorials/typescript-packages-tutorial', '/getting-started/tutorials/package-based-repo-tutorial': - '/tutorials/1-ts-packages/1t-introduction/1-welcome', + '/getting-started/tutorials/typescript-packages-tutorial', '/getting-started/integrated-repo-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/getting-started/tutorials/integrated-repo-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/getting-started/react-standalone-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/getting-started/angular-standalone-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/concepts/more-concepts/micro-frontend-architecture': '/concepts/module-federation/micro-frontend-architecture', '/concepts/more-concepts/faster-builds-with-module-federation': @@ -799,45 +799,35 @@ const conceptUrls = { const nested5minuteTutorialUrls = { '/tutorials/package-based-repo-tutorial': - '/tutorials/1-ts-packages/1t-introduction/1-welcome', + '/getting-started/tutorials/typescript-packages-tutorial', '/getting-started/tutorials/npm-workspaces-tutorial': - '/tutorials/1-ts-packages/1t-introduction/1-welcome', + '/getting-started/tutorials/typescript-packages-tutorial', '/tutorials/integrated-repo-tutorial': '/getting-started/tutorials/integrated-repo-tutorial', '/tutorials/react-standalone-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/getting-started/tutorials/react-standalone-tutorial': - '/tutorials/2-react-monorepo/1r-introduction/1-welcome', + '/getting-started/tutorials/react-monorepo-tutorial', '/tutorials/angular-standalone-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/getting-started/tutorials/angular-standalone-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/getting-started/tutorials/vue-standalone-tutorial': '/getting-started/tutorials', '/tutorials/node-server-tutorial': '/getting-started/tutorials', - '/angular-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/angular-tutorial': '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-tutorial/1-code-generation': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/getting-started/angular-monorepo-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-tutorial/2-project-graph': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-tutorial/3-task-running': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-tutorial/4-workspace-optimization': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', '/angular-tutorial/5-summary': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', - '/getting-started/tutorials': '/tutorials', - '/getting-started/tutorials/typescript-packages-tutorial': - '/tutorials/1-ts-packages/1t-introduction/1-welcome', - '/getting-started/tutorials/react-monorepo-tutorial': - '/tutorials/2-react-monorepo/1a-introduction/1-welcome', - '/getting-started/tutorials/angular-monorepo-tutorial': - '/tutorials/3-angular-monorepo/1a-introduction/1-welcome', - '/getting-started/tutorials/gradle-tutorial': - '/tutorials/4-gradle/1a-introduction/1-welcome', + '/getting-started/tutorials/angular-monorepo-tutorial', }; const pluginUrls = { diff --git a/nx-dev/tutorial/src/bust-cache.js b/nx-dev/tutorial/src/bust-cache.js deleted file mode 100644 index 7cf7a25c8e..0000000000 --- a/nx-dev/tutorial/src/bust-cache.js +++ /dev/null @@ -1,2 +0,0 @@ -// TODO(isaac): nx build tutorial is caching when there are template changes -// Bust: 3 diff --git a/nx-dev/tutorial/src/code-block-button/apply-file-changes-plugin.ts b/nx-dev/tutorial/src/code-block-button/apply-file-changes-plugin.ts index b8f42b982d..6ec76bdf4e 100644 --- a/nx-dev/tutorial/src/code-block-button/apply-file-changes-plugin.ts +++ b/nx-dev/tutorial/src/code-block-button/apply-file-changes-plugin.ts @@ -15,10 +15,8 @@ export function applyFileChangesPlugin(): ExpressiveCodePlugin { applyFileChangesTexts, (codeBlock, isTerminal) => !isTerminal && - ['solution:', 'file:'].some( - (prefix) => - codeBlock.metaOptions.getString('path')?.startsWith(prefix) && - !codeBlock.metaOptions.getBoolean('no-apply') + ['solution:', 'file:'].some((prefix) => + codeBlock.metaOptions.getString('path')?.startsWith(prefix) ), (codeBlock, _) => { return { diff --git a/nx-dev/tutorial/src/code-block-button/run-in-terminal-plugin.ts b/nx-dev/tutorial/src/code-block-button/run-in-terminal-plugin.ts index c11c737f10..88fa96b383 100644 --- a/nx-dev/tutorial/src/code-block-button/run-in-terminal-plugin.ts +++ b/nx-dev/tutorial/src/code-block-button/run-in-terminal-plugin.ts @@ -17,8 +17,7 @@ export function runInTerminalPlugin(): ExpressiveCodePlugin { 'runInTerminal', svg, runInTerminalTexts, - (codeBlock, isTerminal) => - isTerminal && !codeBlock.metaOptions.getBoolean('no-run'), + (_, isTerminal) => isTerminal, (codeBlock, _) => { // remove comment lines starting with `#` from terminal frames let code = codeBlock.code.replace(/(?<=^|\n)\s*#.*($|\n+)/g, '').trim(); diff --git a/nx-dev/tutorial/src/components/GlobalCustomizations.tsx b/nx-dev/tutorial/src/components/GlobalCustomizations.tsx index bec6ff760a..59e2142483 100644 --- a/nx-dev/tutorial/src/components/GlobalCustomizations.tsx +++ b/nx-dev/tutorial/src/components/GlobalCustomizations.tsx @@ -78,7 +78,7 @@ export function GlobalCustomizations() { // Apply file changes async function applyFileChanges(e: any) { const { filepath } = e.detail; - if (!filepath || !(tutorialStore as any)._lessonSolution[filepath]) { + if (!filepath) { return; } tutorialStore.updateFile( diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/1-welcome/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/1-welcome/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/1-welcome/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/1-welcome/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/1-welcome/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/1-welcome/content.mdx similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/1-welcome/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/1-welcome/content.mdx diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/meta.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/meta.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/1t-introduction/meta.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/1-introduction/meta.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/nx.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/nx.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/nx.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/package-lock.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/package-lock.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/package-lock.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/package-lock.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/_solution/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/_solution/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/content.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/2-nx-init/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/2-nx-init/content.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/3-explore-workspace/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/3-explore-workspace/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/3-explore-workspace/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/3-explore-workspace/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/3-explore-workspace/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/3-explore-workspace/content.md similarity index 95% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/3-explore-workspace/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/3-explore-workspace/content.md index 0c6cfa18b7..7484c4cf57 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/3-explore-workspace/content.md +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/3-explore-workspace/content.md @@ -13,7 +13,7 @@ previews: If you run `nx graph` as instructed, you'll see the dependencies between your projects. ```shell {% path="~/tuskydesigns" %} -nx graph --focus=@tuskdesign/zoo +npx nx graph --focus=@tuskdesign/zoo ``` Nx uses this graph to determine the order tasks are run and enforce module boundaries. You can also leverage this graph to gain an accurate understanding of the architecture of your codebase. Part of what makes this graph invaluable is that it is derived directly from your codebase, so it will never become out of date. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/_solution/nx.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/_solution/nx.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/_solution/nx.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/content.md similarity index 97% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/content.md index fcbd939886..6d43c748e3 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/4-task-pipelines/content.md +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/4-task-pipelines/content.md @@ -19,5 +19,5 @@ The `serve` target's `dependsOn` line makes Nx run the `build` task for the curr Now `nx serve` will run the `build` task before running the `serve` task. ```shell -nx serve zoo +npx nx serve zoo ``` diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/animals/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/animals/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/animals/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/animals/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/names/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/names/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/names/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/names/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/zoo/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/zoo/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_files/packages/zoo/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_files/packages/zoo/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/nx.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/nx.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/nx.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/package-lock.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/package-lock.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/package-lock.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/package-lock.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/animals/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/animals/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/animals/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/animals/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/names/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/names/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/names/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/names/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/zoo/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/zoo/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/_solution/packages/zoo/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/_solution/packages/zoo/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/content.mdx similarity index 98% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/content.mdx index 90ea16b03e..8ca034f661 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/5-add-plugin/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/5-add-plugin/content.mdx @@ -41,7 +41,7 @@ First, let's remove the existing `build` and `typecheck` scripts from each proje Now let's add the `@nx/js` plugin: ```shell -nx add @nx/js +npx nx add @nx/js ``` Your output should look like this: @@ -62,7 +62,7 @@ The `nx add` command installs the version of the plugin that matches your repo's Open the project details view for the `zoo` package and look at the `build` task. ```shell -nx show project @tuskdesign/zoo +npx nx show project @tuskdesign/zoo ``` Notice that the `inputs` that are inferred for the `build` task match the `include` and `exclude` settings in the `tsconfig.lib.json` file. As those settings are changed, the cache `inputs` will automatically update to the correct values. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/nx.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/nx.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/nx.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/package-lock.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/package-lock.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/package-lock.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/package-lock.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/animals.ts b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/animals.ts similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/animals.ts rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/animals.ts diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.lib.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.lib.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.lib.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/animals/tsconfig.lib.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/names.ts b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/names.ts similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/names.ts rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/names.ts diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.lib.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.lib.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.lib.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/names/tsconfig.lib.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/README.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/README.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/README.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/README.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/package.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/package.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/package.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/package.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/index.ts b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/index.ts similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/index.ts rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/index.ts diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/lib/util.ts b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/lib/util.ts similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/lib/util.ts rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/src/lib/util.ts diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.lib.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.lib.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.lib.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/util/tsconfig.lib.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/zoo/tsconfig.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/zoo/tsconfig.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/packages/zoo/tsconfig.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/packages/zoo/tsconfig.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/tsconfig.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/tsconfig.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/_solution/tsconfig.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/_solution/tsconfig.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/content.mdx similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/6-sync-ts-references/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/6-sync-ts-references/content.mdx diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/7-checkpoint/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/7-checkpoint/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/7-checkpoint/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/7-checkpoint/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/7-checkpoint/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/7-checkpoint/content.mdx similarity index 96% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/7-checkpoint/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/7-checkpoint/content.mdx index a499111e71..5da82ff7d5 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/7-checkpoint/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/7-checkpoint/content.mdx @@ -16,7 +16,7 @@ At this point, the repository is still using all the same tools to run tasks, bu Open up the task graph for `zoo` app's `serve` task again to see the changes. ```shell {% path="~/tuskydesigns" %} -nx run @tuskdesign/zoo:serve --graph +npx nx run @tuskdesign/zoo:serve --graph ``` The rest of this tutorial covers managing releases and setting up CI, which both require you to have a local copy of the repository. Click the "Download Repository" button and extract the zip file on your local machine before moving to the next section. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/meta.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/meta.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/2t-smart-monorepo/meta.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/2-smart-monorepo/meta.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/1-manage-releases/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/1-manage-releases/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/1-manage-releases/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/1-manage-releases/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/1-manage-releases/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/1-manage-releases/content.mdx similarity index 96% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/1-manage-releases/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/1-manage-releases/content.mdx index 0efebe6fec..0e71304b4e 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/1-manage-releases/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/1-manage-releases/content.mdx @@ -32,13 +32,13 @@ Now you're ready to use the `nx release` command to publish the `animals` and `n To preview your first release, run: ```shell -nx release --first-release --dry-run +npx nx release --first-release --dry-run ``` The command will ask you a series of questions and then show you what the results would be. Once you are happy with the results, run it again without the `--dry-run` flag: ```shell -nx release --first-release +npx nx release --first-release ``` After this first release, you can remove the `--first-release` flag and just run `nx release --dry-run`. There is also a [dedicated feature page](/features/manage-releases) that goes into more detail about how to use the `nx release` command. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/meta.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/meta.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/3t-manage-releases/meta.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/3-manage-releases/meta.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/1-welcome/_files/.tk-config.json b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/1-welcome/_files/.tk-config.json similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/1-welcome/_files/.tk-config.json rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/1-welcome/_files/.tk-config.json diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/1-welcome/content.mdx b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/1-welcome/content.mdx similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/1-welcome/content.mdx rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/1-welcome/content.mdx diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/2-connect-to-nx-cloud/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/2-connect-to-nx-cloud/content.md similarity index 99% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/2-connect-to-nx-cloud/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/2-connect-to-nx-cloud/content.md index 1ece56bf62..f1628f1458 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/2-connect-to-nx-cloud/content.md +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/2-connect-to-nx-cloud/content.md @@ -18,7 +18,7 @@ Now that we're working on the CI pipeline, it is important for your changes to b Now connect your repository to Nx Cloud with the following command: ```shell -nx connect +npx nx connect ``` A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/3-create-ci-workflow/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/3-create-ci-workflow/content.md similarity index 97% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/3-create-ci-workflow/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/3-create-ci-workflow/content.md index 313e53cb3d..93e6bcd90f 100644 --- a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/3-create-ci-workflow/content.md +++ b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/3-create-ci-workflow/content.md @@ -8,7 +8,7 @@ title: Create a CI Workflow Use the following command to generate a CI workflow file. ```shell -nx generate ci-workflow --ci=github +npx nx generate ci-workflow --ci=github ``` This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/4-open-pr/content.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/4-open-pr/content.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/4-open-pr/content.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/4-open-pr/content.md diff --git a/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/meta.md b/nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/meta.md similarity index 100% rename from nx-dev/tutorial/src/content/tutorial/1-ts-packages/4t-fast-ci/meta.md rename to nx-dev/tutorial/src/content/tutorial/1-ts-packages/4-fast-ci/meta.md diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/10-affected/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/10-affected/content.mdx index 2dfbf10b62..2dc30ecf13 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/10-affected/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/10-affected/content.mdx @@ -38,7 +38,7 @@ Then the following command would run the tests for only the projects affected by ```shell # This does not work in the browser webcontainer -nx affected -t test +npx nx affected -t test ``` :::info @@ -48,7 +48,7 @@ This webcontainer does not have `git` enabled, so we have to manually tell Nx wh Use this command in the webcontainer terminal to manually specify which files have been touched. ```shell -nx affected -t test --files=libs/products/src/lib/products.tsx +npx nx affected -t test --files=libs/products/src/lib/products.tsx ``` Note that the unit tests were run for `products`, `react-store` and `inventory`, but not for `orders` because a change to `products` can not possibly break the tests for `orders`. In a small repo like this, there isn't a lot of time saved, but as there are more tests and more projects, this quickly becomes an essential command. @@ -56,7 +56,7 @@ Note that the unit tests were run for `products`, `react-store` and `inventory`, You can also see what projects are affected in the graph visualizer with; ```shell -nx graph --affected --files=libs/products/src/lib/products.tsx +npx nx graph --affected --files=libs/products/src/lib/products.tsx ``` ## Build the Apps for Deployment @@ -66,7 +66,7 @@ nx graph --affected --files=libs/products/src/lib/products.tsx If you're ready and want to ship your applications, you can build them using ```shell -nx run-many -t build +npx nx run-many -t build ``` All the required files will be placed in `/apps/react-store/dist` and `/apps/inventory/dist` and can be deployed to your favorite hosting provider. @@ -117,8 +117,8 @@ Replace the `deploy` script with whatever terminal command you use to deploy you The `"dependsOn": ["build"]` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. -With the `deploy` tasks defined, you can deploy a single application with `nx deploy react-store` or deploy any applications affected by the current changes with: +With the `deploy` tasks defined, you can deploy a single application with `npx nx deploy react-store` or deploy any applications affected by the current changes with: ```shell -nx affected -t deploy +npx nx affected -t deploy ``` diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/11-module-boundaries/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/11-module-boundaries/content.mdx index 0ebb016b5d..eb2d5b1b4f 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/11-module-boundaries/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/11-module-boundaries/content.mdx @@ -77,7 +77,7 @@ To test it, go to your `libs/products/src/lib/products.tsx` file and import the If you lint your workspace you'll get an error now: ```shell -nx run-many -t lint +npx nx run-many -t lint ``` ``` @@ -92,7 +92,7 @@ nx run-many -t lint > eslint . - /home/tutorial/libs/products/src/lib/products.tsx + /Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/products.tsx 3:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries 3:10 warning 'Orders' is defined but never used @typescript-eslint/no-unused-vars diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/_solution/react-monorepo/nx.json b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/_solution/react-monorepo/nx.json index b02af17dbd..57277a6751 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/_solution/react-monorepo/nx.json +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/_solution/react-monorepo/nx.json @@ -15,6 +15,7 @@ ], "sharedGlobals": [] }, + "nxCloudId": "68101bb54a6391016e75634c", "plugins": [ { "plugin": "@nx/js/typescript", diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/content.mdx index 93ac215588..e9bbcc6fc0 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/2-use-preset/content.mdx @@ -28,7 +28,7 @@ If you experience technical issues with the in-browser tutorial, try refreshing Create a new React monorepo with the following command: ```shell -npx create-nx-workspace@latest react-monorepo --preset=react-monorepo --nx-cloud=skip +npx create-nx-workspace@latest react-monorepo --preset=react-monorepo ``` ``` @@ -41,6 +41,7 @@ NX Let's create a new workspace [https://nx.dev/getting-started/intro] ✔ Default stylesheet format · css ✔ Would you like to use ESLint? · Yes ✔ Would you like to use Prettier for code formatting? · Yes +✔ Which CI provider would you like to use? · github ``` Let's name the initial application `react-store`. In this tutorial we're going to use `vite` as a bundler, `cypress` for e2e tests and `css` for styling. We'll talk more about how Nx integrates with GitHub Actions later in the tutorial. The above command generates the following structure: @@ -77,7 +78,7 @@ Let's name the initial application `react-store`. In this tutorial we're going t The setup includes.. - a new React application (`apps/react-store/`) -- a Cypress based set of e2e tests (`apps/react-store-e2e/`) +- a Playwright based set of e2e tests (`apps/react-store-e2e/`) - Prettier preconfigured - ESLint preconfigured - Jest preconfigured diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/3-run-tasks/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/3-run-tasks/content.mdx index f95903d3e8..fcde327b64 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/3-run-tasks/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/3-run-tasks/content.mdx @@ -14,7 +14,7 @@ previews: To serve your new React application, just run: ```shell -nx serve react-store +npx nx serve react-store ``` Your application should be served at [http://localhost:4200](http://localhost:4200). diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/_solution/apps/react-store/vite.config.ts b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/_solution/apps/react-store/vite.config.ts index 139f61e644..0947c31bd1 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/_solution/apps/react-store/vite.config.ts +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/_solution/apps/react-store/vite.config.ts @@ -22,7 +22,7 @@ export default defineConfig({ // plugins: [ nxViteTsPaths() ], // }, build: { - outDir: './build', + outDir: './build/react-store', emptyOutDir: true, reportCompressedSize: true, commonjsOptions: { diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/content.mdx index cad359c22d..4be8f3a5ab 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/4-inferred-tasks/content.mdx @@ -5,7 +5,7 @@ previews: - { port: 4211, title: 'Project Details View', - pathname: '/project-details/react-store', + pathname: '/project-details/%40react-monorepo%2Freact-store', } --- @@ -18,7 +18,7 @@ previews: Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. To view the tasks that Nx has detected, look in the [Nx Console](/getting-started/editor-setup) project detail view or run: ```shell -nx show project react-store +npx nx show project @react-monorepo/react-store ``` If you expand the `build` task, you can see that it was created by the `@nx/vite` plugin by analyzing your `vite.config.ts` file. Notice the outputs are defined as `{projectRoot}/dist`. This value is being read from the `build.outDir` defined in your `vite.config.ts` file. Let's change that value in your `vite.config.ts` file: diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/5-add-application/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/5-add-application/content.mdx index acddf94f1d..3b8a63563d 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/5-add-application/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/5-add-application/content.mdx @@ -12,7 +12,7 @@ title: Add an Application Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/react` plugin provides, run the following command and inspect the output: ```shell -nx list @nx/react +npx nx list @nx/react ``` :::info @@ -27,7 +27,7 @@ More info can be found in [the integrate with editors article](/getting-started/ Run the following command to generate a new `inventory` application. Note how we append `--dry-run` to first check the output. ```shell -nx g @nx/react:app apps/inventory --dry-run +npx nx g @nx/react:app apps/inventory --dry-run ``` ``` @@ -35,11 +35,11 @@ NX Generating @nx/react:application ✔ Would you like to add React Router to this application? (y/N) · false ✔ What unit test runner should be used? · vitest -✔ Which E2E test runner would you like to use? · none +✔ Which E2E test runner would you like to use? · cypress ``` As you can see, it generates a new application in the `apps/inventory/` folder. Let's actually run the generator by removing the `--dry-run` flag. ```shell -nx g @nx/react:app apps/inventory +npx nx g @nx/react:app apps/inventory ``` diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/_solution/nx.json index 8489532cda..3e16b79395 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/_solution/nx.json +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/_solution/nx.json @@ -15,6 +15,7 @@ ], "sharedGlobals": [] }, + "nxCloudId": "68101bb54a6391016e75634c", "plugins": [ { "plugin": "@nx/js/typescript", diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/content.mdx index 66d2508715..8836ee3839 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/6-create-local-library/content.mdx @@ -53,15 +53,9 @@ Nx allows you to separate this logic into "local libraries". The main benefits i Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for each of these areas using the React library generator: ```shell -nx g @nx/react:library libs/products --unitTestRunner=vitest --bundler=none -``` - -```shell -nx g @nx/react:library libs/orders --unitTestRunner=vitest --bundler=none -``` - -```shell -nx g @nx/react:library libs/shared/ui --unitTestRunner=vitest --bundler=none +npx nx g @nx/react:library libs/products --unitTestRunner=vitest --bundler=none +npx nx g @nx/react:library libs/orders --unitTestRunner=vitest --bundler=none +npx nx g @nx/react:library libs/shared/ui --unitTestRunner=vitest --bundler=none ``` Note how we type out the full path in the `directory` flag to place the libraries into a subfolder. You can choose whatever folder structure you like to organize your projects. If you change your mind later, you can run the [move generator](/nx-api/workspace/generators/move) to move a project to a different folder. @@ -105,7 +99,7 @@ Running the above commands should lead to the following directory structure: Each of these libraries -- has a project details view where you can see the available tasks (e.g. running tests for just orders: `nx test orders`) +- has a project details view where you can see the available tasks (e.g. running tests for just orders: `npx nx test orders`) - has its own `package.json` file where you can customize targets - has the name you specified in the generate command; you can find the name in the corresponding `package.json` file - has a dedicated `index.ts` file which is the "public API" of the library diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/inventory/src/app/app.spec.tsx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/inventory/src/app/app.spec.tsx deleted file mode 100644 index 3a848a2292..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/inventory/src/app/app.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from '@testing-library/react'; - -import App from './app'; - -describe('App', () => { - it('should render successfully', () => { - const { baseElement } = render(); - expect(baseElement).toBeTruthy(); - }); - - it('should have a greeting as the title', () => { - const { getByText } = render(); - expect( - getByText(new RegExp('Products', 'gi')) - ).toBeTruthy(); - }); -}); diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/react-store/src/app/app.spec.tsx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/react-store/src/app/app.spec.tsx deleted file mode 100644 index 80546f6cd5..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/_solution/apps/react-store/src/app/app.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from '@testing-library/react'; - -import App from './app'; - -describe('App', () => { - it('should render successfully', () => { - const { baseElement } = render(); - expect(baseElement).toBeTruthy(); - }); - - it('should have a greeting as the title', () => { - const { getByText } = render(); - expect( - getByText(new RegExp('Home', 'gi')) - ).toBeTruthy(); - }); -}); diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/content.mdx index 767701a419..901570cf63 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/7-share-code/content.mdx @@ -2,7 +2,7 @@ type: lesson title: Share Code previews: - - { port: 4200, title: 'ReactStore', pathname: '/products' } + - { port: 4211, title: 'Project Graph', pathname: '/projects' } --- ### Import Libraries into the React Applications @@ -13,7 +13,7 @@ previews: All libraries that we generate are automatically included in the `workspaces` defined in the root-level `package.json`. -```file:/package.json title="/package.json" collapse={3-53} no-apply +```file:/package.json title="/package.json" collapse={3-51} ``` @@ -61,11 +61,7 @@ export function App() { export default App; ``` -Serving your app (`nx serve react-store`) and then navigating to `/products` should give you the following result: - -```shell -nx serve react-store -``` +Serving your app (`npx nx serve react-store`) and then navigating to `/products` should give you the following result: ![products route](/documentation/shared/tutorials/react-tutorial-products-route.png) diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/8-visualize-project-structure/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/8-visualize-project-structure/content.mdx index 4d272163c5..a392a421c2 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/8-visualize-project-structure/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/8-visualize-project-structure/content.mdx @@ -11,14 +11,14 @@ previews: {/* */} -Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `nx build`, identifying [affected projects](/features/run-tasks#run-tasks-on-projects-affected-by-a-pr) and more. Interestingly you can also visualize it. +Nx automatically detects the dependencies between the various parts of your workspace and builds a [project graph](/features/explore-graph). This graph is used by Nx to perform various optimizations such as determining the correct order of execution when running tasks like `npx nx build`, identifying [affected projects](/features/run-tasks#run-tasks-on-projects-affected-by-a-pr) and more. Interestingly you can also visualize it. Just run: ```shell -nx graph +npx nx graph ``` Notice how `ui` is not yet connected to anything because we didn't import it in any of our projects. -Exercise for you: change the codebase such that `ui` is used by `orders` and `products`. Note: you need to restart the `nx graph` command to update the graph visualization. +Exercise for you: change the codebase such that `ui` is used by `orders` and `products`. Note: you need to restart the `npx nx graph` command to update the graph visualization. diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/9-run-many/content.mdx b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/9-run-many/content.mdx index 91b9cd8088..c5aa6e9435 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/9-run-many/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/2r-smart-monorepo/9-run-many/content.mdx @@ -12,14 +12,15 @@ title: Run Multiple Tasks Our current setup doesn't just come with targets for serving and building the React application, but also has targets for unit testing, e2e testing and linting. Again, these are defined in the `project.json` file. We can use the same syntax as before to run these tasks: ```bash -nx test react-store # runs the tests for react-store -nx lint inventory # runs the linter on inventory +npx nx test react-store # runs the tests for react-store +npx nx lint inventory # runs the linter on inventory +npx nx e2e react-store-e2e # runs e2e tests for the react-store ``` More conveniently, we can also run tasks in parallel using the following syntax: ```shell -nx run-many -t test +npx nx run-many -t test ``` ### Cache Tasks @@ -29,7 +30,7 @@ One thing to highlight is that Nx is able to [cache the tasks you run](/features Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. ```shell -nx run-many -t test lint +npx nx run-many -t test lint e2e ``` ``` @@ -40,7 +41,7 @@ nx run-many -t test lint —————————————————————————————————————————————————————— -NX Successfully ran targets test, lint for 7 projects (54ms) +NX Successfully ran targets test, lint, e2e for 7 projects (54ms) Nx read the output from the cache instead of running the command for 10 out of 10 tasks. ``` diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/2-connect-to-nx-cloud/content.md b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/2-connect-to-nx-cloud/content.md index 1ece56bf62..f1628f1458 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/2-connect-to-nx-cloud/content.md +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/2-connect-to-nx-cloud/content.md @@ -18,7 +18,7 @@ Now that we're working on the CI pipeline, it is important for your changes to b Now connect your repository to Nx Cloud with the following command: ```shell -nx connect +npx nx connect ``` A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. diff --git a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/3-create-ci-workflow/content.md b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/3-create-ci-workflow/content.md index 313e53cb3d..93e6bcd90f 100644 --- a/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/3-create-ci-workflow/content.md +++ b/nx-dev/tutorial/src/content/tutorial/2-react-monorepo/3r-fast-ci/3-create-ci-workflow/content.md @@ -8,7 +8,7 @@ title: Create a CI Workflow Use the following command to generate a CI workflow file. ```shell -nx generate ci-workflow --ci=github +npx nx generate ci-workflow --ci=github ``` This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/10-affected/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/10-affected/content.mdx index ae5c99eae0..fc6b108a47 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/10-affected/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/10-affected/content.mdx @@ -28,7 +28,7 @@ Then the following command would run the tests for only the projects affected by ```shell # This does not work in the browser webcontainer -nx affected -t test +npx nx affected -t test ``` :::info @@ -38,7 +38,7 @@ This webcontainer does not have `git` enabled, so we have to manually tell Nx wh Use this command in the webcontainer terminal to manually specify which files have been touched. ```shell -nx affected -t test --files=libs/products/src/lib/products.tsx +npx nx affected -t test --files=libs/products/src/lib/products.tsx ``` Note that the unit tests were run for `products`, `angular-store` and `inventory`, but not for `orders` because a change to `products` can not possibly break the tests for `orders`. In a small repo like this, there isn't a lot of time saved, but as there are more tests and more projects, this quickly becomes an essential command. @@ -46,7 +46,7 @@ Note that the unit tests were run for `products`, `angular-store` and `inventory You can also see what projects are affected in the graph visualizer with: ```shell -nx graph --affected --files=libs/products/src/lib/products.tsx +npx nx graph --affected --files=libs/products/src/lib/products.tsx ``` ## Build the Apps for Deployment @@ -56,7 +56,7 @@ nx graph --affected --files=libs/products/src/lib/products.tsx If you're ready and want to ship your applications, you can build them using ```shell -nx run-many -t build +npx nx run-many -t build ``` All the required files will be placed in `dist/apps/angular-store` and `dist/apps/inventory` and can be deployed to your favorite hosting provider. @@ -78,8 +78,8 @@ Replace the `command` with whatever terminal command you use to deploy your site The `"dependsOn": "build"` setting tells Nx to make sure that the project's `build` task has been run successfully before the `deploy` task. -With the `deploy` tasks defined, you can deploy a single application with `nx deploy angular-store` or deploy any applications affected by the current changes with: +With the `deploy` tasks defined, you can deploy a single application with `npx nx deploy angular-store` or deploy any applications affected by the current changes with: ```shell -nx affected -t deploy +npx nx affected -t deploy ``` diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.component.ts b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.component.ts deleted file mode 100644 index 28b00e87fe..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.component.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component } from '@angular/core'; -import { CommonModule } from '@angular/common'; - -// This import is not allowed 👇 -import { OrdersComponent } from '@angular-monorepo/orders'; - -@Component({ - selector: 'lib-products', - imports: [CommonModule], - templateUrl: './products.component.html', - styleUrl: './products.component.css', -}) -export class ProductsComponent {} diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.tsx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.tsx new file mode 100644 index 0000000000..fab987cd54 --- /dev/null +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/_solution/libs/products/src/lib/products.tsx @@ -0,0 +1,15 @@ +import styles from './products.module.css'; + +// This import is not allowed 👇 +import { Orders } from '@angular-monorepo/orders'; + +export function Products() { + return ( +
+

Welcome to Products!

+

This is a change. 👋

+
+ ); +} + +export default Products; diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/content.mdx index a4e3027015..fa8e807c28 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/11-module-boundaries/content.mdx @@ -53,16 +53,16 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `eslint.confi ``` -To test it, go to your `/libs/products/src/lib/products/products.component.ts` file and import the `Orders` component from the `orders` project: +To test it, go to your `libs/products/src/lib/products.tsx` file and import the `Orders` component from the `orders` project: -```solution:/libs/products/src/lib/products/products.component.ts title="/libs/products/src/lib/products/products.component.ts" {3-4} +```solution:/libs/products/src/lib/products.tsx title="/libs/products/src/lib/products.tsx" {3-4} ``` If you lint your workspace you'll get an error now: ```shell -nx run-many -t lint +npx nx run-many -t lint ``` ``` @@ -70,9 +70,9 @@ nx run-many -t lint ✖ nx run products:lint Linting "products"... - /home/tutorial/libs/products/src/lib/products/products.component.ts - 5:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries - 5:10 warning 'OrdersComponent' is defined but never used @typescript-eslint/no-unused-vars + /Users/isaac/Documents/code/nx-recipes/angular-monorepo/libs/products/src/lib/products.tsx + 4:1 error A project tagged with "scope:products" can only depend on libs tagged with "scope:products", "scope:shared" @nx/enforce-module-boundaries + 4:10 warning 'Orders' is defined but never used @typescript-eslint/no-unused-vars ✖ 2 problems (1 error, 1 warning) diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/_solution/angular-monorepo/nx.json b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/_solution/angular-monorepo/nx.json index f7c1387995..7571fd9111 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/_solution/angular-monorepo/nx.json +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/_solution/angular-monorepo/nx.json @@ -17,6 +17,7 @@ ], "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"] }, + "nxCloudId": "6810b7447beee15fcea96208", "targetDefaults": { "@angular-devkit/build-angular:application": { "cache": true, diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/content.mdx index 1e2837cc97..7bb7373017 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/2-use-preset/content.mdx @@ -28,7 +28,7 @@ If you experience technical issues with the in-browser tutorial, try refreshing ::: ```shell -npx create-nx-workspace@latest angular-monorepo --preset=angular-monorepo --nx-cloud=skip +npx create-nx-workspace@latest angular-monorepo --preset=angular-monorepo ``` ``` @@ -40,6 +40,7 @@ NX Let's create a new workspace [https://nx.dev/getting-started/intro] ✔ Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? · No ✔ Which unit test runner would you like to use? · jest ✔ Test runner to use for end to end (E2E) tests · cypress +✔ Which CI provider would you like to use? · github ``` Let's name the initial application `angular-store`. In this tutorial we're going to use `cypress` for e2e tests and `css` for styling. We'll talk more about how Nx integrates with GitHub Actions later in the tutorial. The above command generates the following structure: @@ -85,12 +86,6 @@ The setup includes: - ESLint preconfigured - Jest preconfigured -:::info - -The Cypress e2e task does not run in a web container. To see the e2e tests in action, download the repo and run `nx e2e angular-store-e2e` on your local machine. - -::: - One way to structure an Nx monorepo is to place application projects in the `apps` folder and library projects in the `libs` folder. Applications are encouraged to be as light-weight as possible so that more code is pushed into libraries and can be reused in other projects. This folder structure is just a suggestion and can be modified to suit your organization's needs. The [`nx.json` file](/reference/nx-json) contains configuration settings for Nx itself and global default settings that individual projects inherit. The `apps/angular-store/project.json` file contains [settings that are specific to the `angular-store` project](/reference/project-configuration). We'll examine that file more in the next section. diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/3-run-tasks/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/3-run-tasks/content.mdx index ab8dbc45f0..dca869bee1 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/3-run-tasks/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/3-run-tasks/content.mdx @@ -14,7 +14,7 @@ previews: To serve your new Angular application, just run: ```shell -nx serve angular-store +npx nx serve angular-store ``` Your application should be served at [http://localhost:4200](http://localhost:4200). diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/5-add-application/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/5-add-application/content.mdx index caa696ae24..686538952c 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/5-add-application/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/5-add-application/content.mdx @@ -12,7 +12,7 @@ title: Add an Application Nx plugins usually provide [generators](/features/generate-code) that allow you to easily scaffold code, configuration or entire projects. To see what capabilities the `@nx/angular` plugin provides, run the following command and inspect the output: ```shell -nx list @nx/angular +npx nx list @nx/angular ``` :::info @@ -27,7 +27,7 @@ More info can be found in [the integrate with editors article](/getting-started/ Run the following command to generate a new `inventory` application. Note how we append `--dry-run` to first check the output. ```shell -nx g @nx/angular:app apps/inventory --dry-run +npx nx g @nx/angular:app apps/inventory --dry-run ``` ``` @@ -40,5 +40,5 @@ NX Generating @nx/angular:application As you can see, it generates a new application in the `apps/inventory/` folder. Let's actually run the generator by removing the `--dry-run` flag. ```shell -nx g @nx/angular:app apps/inventory +npx nx g @nx/angular:app apps/inventory ``` diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/_solution/nx.json b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/_solution/nx.json index 1e617e8f53..40f3290647 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/_solution/nx.json +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/_solution/nx.json @@ -17,6 +17,7 @@ ], "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"] }, + "nxCloudId": "67b34f1b5f0dc34dcae257e2", "targetDefaults": { "@angular-devkit/build-angular:application": { "cache": true, diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/content.mdx index b64d598814..21b7603019 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/6-create-local-library/content.mdx @@ -53,15 +53,9 @@ Nx allows you to separate this logic into "local libraries". The main benefits i Let's assume our domain areas include `products`, `orders` and some more generic design system components, called `ui`. We can generate a new library for each of these areas using the Angular library generator: ```shell -nx g @nx/angular:library libs/products --unitTestRunner=jest -``` - -```shell -nx g @nx/angular:library libs/orders --unitTestRunner=jest -``` - -```shell -nx g @nx/angular:library libs/shared/ui --unitTestRunner=jest +npx nx g @nx/angular:library libs/products --unitTestRunner=jest +npx nx g @nx/angular:library libs/orders --unitTestRunner=jest +npx nx g @nx/angular:library libs/shared/ui --unitTestRunner=jest ``` Note how we type out the full path in the `directory` flag to place the libraries into a subfolder. You can choose whatever folder structure you like to organize your projects. If you change your mind later, you can run the [move generator](/nx-api/workspace/generators/move) to move a project to a different folder. @@ -104,7 +98,7 @@ Running the above commands should lead to the following directory structure: Each of these libraries -- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `nx test orders`) +- has its own `project.json` file with corresponding targets you can run (e.g. running tests for just orders: `npx nx test orders`) - has the name you specified in the generate command; you can find the name in the corresponding `project.json` file - has a dedicated `index.ts` file which is the "public API" of the library - is mapped in the `tsconfig.base.json` at the root of the workspace diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/7-share-code/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/7-share-code/content.mdx index fd8ba06eae..518aedea2c 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/7-share-code/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/7-share-code/content.mdx @@ -41,7 +41,7 @@ Then we can add the `ProductsComponent` component to our `app.routes.ts` and ren ``` -Serving your app (`nx serve angular-store`) and then navigating to `/products` should give you the following result: +Serving your app (`npx nx serve angular-store`) and then navigating to `/products` should give you the following result: ![products route](/documentation/shared/tutorials/app-products-route.png) @@ -72,6 +72,6 @@ Let's also show products in the `inventory` app. Our current setup not only has targets for serving and building the Angular application, but also has targets for unit testing and linting. The `test` and `lint` targets are defined in the application `project.json` file. We can use the same syntax as before to run these tasks: ```shell -nx test angular-store # runs the tests for angular-store -nx lint inventory # runs the linter on inventory +npx nx test angular-store # runs the tests for angular-store +npx nx lint inventory # runs the linter on inventory ``` diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/8-inferred-tasks/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/8-inferred-tasks/content.mdx index 6e365eba73..e3ba8d6ba2 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/8-inferred-tasks/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/8-inferred-tasks/content.mdx @@ -18,7 +18,7 @@ previews: Nx identifies available tasks for your project from [tooling configuration files](/concepts/inferred-tasks), `package.json` scripts and the targets defined in `project.json`. All tasks from the `angular-store` project are defined in its `project.json` file, but the companion `angular-store-e2e` project has its tasks inferred from configuration files. To view the tasks that Nx has detected, look in the [Nx Console](/getting-started/editor-setup), [Project Details View](/recipes/nx-console/console-project-details) or run: ```shell -nx show project angular-store-e2e +npx nx show project angular-store-e2e ``` If you expand the `e2e` task, you can see that it was created by the `@nx/cypress` plugin by analyzing the `apps/angular-store-e2e/cypress.config.ts` file. Notice the outputs are defined as: @@ -32,8 +32,19 @@ If you expand the `e2e` task, you can see that it was created by the `@nx/cypres This value is being read from the `videosFolder` and `screenshotsFolder` defined by the `nxE2EPreset` in your `apps/angular-store-e2e/cypress.config.ts` file. Let's change their value in your `apps/angular-store-e2e/cypress.config.ts` file: -```solution:/apps/angular-store-e2e/cypress.config.ts title="/apps/angular-store-e2e/cypress.config.ts" collapse={1-3,7-13} {16-18} - +```ts title="apps/angular-store-e2e/cypress.config.ts" {8-10} +// ... +export default defineConfig({ + e2e: { + ...nxE2EPreset(__filename, { + // ... + }), + baseUrl: 'http://localhost:4200', + videosFolder: '../dist/cypress/apps/angular-store-e2e/videos-changed', + screenshotsFolder: + '../dist/cypress/apps/angular-store-e2e/screenshots-changed', + }, +}); ``` Now if you close the project details view (Ctrl-C in the terminal) and open it again, the outputs for the `e2e` target will be: @@ -48,9 +59,3 @@ Now if you close the project details view (Ctrl-C in the terminal) and open it a This feature ensures that Nx will always cache the correct files. You can also override the settings for inferred tasks by modifying the [`targetDefaults` in `nx.json`](/reference/nx-json#target-defaults) or setting a value in your [`project.json` file](/reference/project-configuration). Nx will merge the values from the inferred tasks with the values you define in `targetDefaults` and in your specific project's configuration. - -:::info - -The e2e task does not run in a web container. To see the e2e tests in action, download the repo and run `nx e2e angular-store-e2e` on your local machine. - -::: diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/9-run-many/content.mdx b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/9-run-many/content.mdx index e0b1cda6e2..255b20f36c 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/9-run-many/content.mdx +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/2a-smart-monorepo/9-run-many/content.mdx @@ -8,7 +8,7 @@ title: Run Multiple Tasks In addition to running individual tasks, you can also run multiple tasks in parallel using the following syntax: ```shell -nx run-many -t test lint build +npx nx run-many -t test lint build ``` ### Caching @@ -18,7 +18,7 @@ One thing to highlight is that Nx is able to [cache the tasks you run](/features Note that all of these targets are automatically cached by Nx. If you re-run a single one or all of them again, you'll see that the task completes immediately. In addition, (as can be seen in the output example below) there will be a note that a matching cache result was found and therefore the task was not run again. ```shell -nx run-many -t test lint build +npx nx run-many -t test lint build ``` ``` diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/2-connect-to-nx-cloud/content.md b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/2-connect-to-nx-cloud/content.md index 1ece56bf62..f1628f1458 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/2-connect-to-nx-cloud/content.md +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/2-connect-to-nx-cloud/content.md @@ -18,7 +18,7 @@ Now that we're working on the CI pipeline, it is important for your changes to b Now connect your repository to Nx Cloud with the following command: ```shell -nx connect +npx nx connect ``` A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/3-create-ci-workflow/content.md b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/3-create-ci-workflow/content.md index 313e53cb3d..93e6bcd90f 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/3-create-ci-workflow/content.md +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/3a-fast-ci/3-create-ci-workflow/content.md @@ -8,7 +8,7 @@ title: Create a CI Workflow Use the following command to generate a CI workflow file. ```shell -nx generate ci-workflow --ci=github +npx nx generate ci-workflow --ci=github ``` This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. diff --git a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/meta.md b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/meta.md index 6a30a41678..41cf2646c9 100644 --- a/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/meta.md +++ b/nx-dev/tutorial/src/content/tutorial/3-angular-monorepo/meta.md @@ -5,7 +5,7 @@ meta: title: 'Nx Tutorial: Angular Monorepo' image: /images/nx-media.png filesystem: - watch: ['/*.json', '/libs', '/(apps|libs)/**'] + watch: true terminal: panels: 'terminal' open: true diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/1-welcome/content.mdx b/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/1-welcome/content.mdx deleted file mode 100644 index ebd3116b3f..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/1-welcome/content.mdx +++ /dev/null @@ -1,87 +0,0 @@ ---- -type: lesson -title: Starting Repository -custom: - first: true ---- - -# Gradle Tutorial - -In this tutorial, you'll learn how to add Nx to a repository with an existing Gradle setup. - -What will you learn? - -- how to add Nx to a Gradle project -- how to run a single task (i.e. serve your app) or run multiple tasks in parallel -- how to leverage code generators to scaffold components -- how to modularize your codebase and impose architectural constraints for better maintainability -- [how to speed up CI with Nx Cloud ⚡](/tutorials/4-gradle/3g-fast-ci/1-welcome) - -## Prerequisites - -Make sure that you have [Gradle](https://gradle.org/) installed on your system. -Consult [Gradle's installation guide](https://docs.gradle.org/current/userguide/installation.html) for instruction that -are specific to your operating system. - -To verify that Gradle was installed correctly, run this command: - -```shell no-run -gradle --version -``` - -To streamline this tutorial, we'll install Nx globally on your system. You can use Homebrew (Mac only) or a manually installed Node version (any OS). - -##### Homebrew - -If installing Nx with Homebrew, make sure [Homebrew is installed](https://brew.sh/), then install Nx globally with these commands: - -```shell no-run -brew tap nrwl/nx -brew install nx -``` - -##### Node - -If installing Nx with Node, install node from the [NodeJS website](https://nodejs.org/en/download), then install Nx globally with this command: - -```shell no-run -npm install --global nx -``` - -## Getting Started - -This tutorial picks up where [Spring framework](https://spring.io/)'s guide for [Multi-Module Projects](https://spring.io/guides/gs/multi-module) leaves off. - -Fork [the sample repository](https://github.com/nrwl/gradle-tutorial/fork), and then clone it on your local machine: - -import { GithubRepository } from '@nx/nx-dev/ui-markdoc'; - - - -```shell no-run -git clone https://github.com//gradle-tutorial.git -``` - -The Multi-Module Spring Tutorial left us with 2 projects: - -- The main `application` project which contains the Spring `DemoApplication` -- A `library` project which contains a Service used in the `DemoApplication` - -You can see the above 2 projects by running `./gradlew projects` - -```shell no-run -./gradlew projects -``` - -``` -> Task :projects - ------------------------------------------------------------- -Root project 'gradle-tutorial' ------------------------------------------------------------- - -Root project 'gradle-tutorial' -+--- Project ':application' -\--- Project ':library' - -``` diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/meta.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/meta.md deleted file mode 100644 index 47f5fcd7eb..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/1g-introduction/meta.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: chapter -title: Intro ---- diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/2-nx-init/content.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/2-nx-init/content.md deleted file mode 100644 index 9ad6f6d855..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/2-nx-init/content.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -type: lesson -title: Add Nx ---- - -## Smart Monorepo - -Nx offers many features, but at its core, it is a task runner. Out of the box, it can cache your tasks and ensure those tasks are run in the correct order. After the initial set up, you can incrementally add on other features that would be helpful in your organization. - -### Add Nx - -Nx is a build system with built in tooling and advanced CI capabilities. It helps you maintain and scale monorepos, -both locally and on CI. We will explore the features of Nx in this tutorial by adding it to the Gradle workspace above. - -To add Nx, run - -```shell no-run -npx nx@latest init -``` - -This command will download the latest version of Nx and help set up your repository to take advantage of it. Nx will -also detect Gradle is used in the repo so it will propose adding the `@nx/gradle` plugin to integrate Gradle with Nx. -Select the plugin and continue with the setup. - -Similar to Gradle, Nx can be run with the `nx` or `nx.bat` executables. We will learn about some of the Nx commands in -the following sections. diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/3-explore-workspace/content.mdx b/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/3-explore-workspace/content.mdx deleted file mode 100644 index 38cc76ed4c..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/3-explore-workspace/content.mdx +++ /dev/null @@ -1,41 +0,0 @@ ---- -type: lesson -title: Explore Your Workspace ---- - -## Explore Your Workspace - -Like Gradle, Nx understands your workspace as a graph of projects. Nx uses this graph for many things which we will -learn about in following sections. To visualize this graph in your browser, Run the following command and click the -"Show all projects" button in the left sidebar. - -You will recognize that the projects which are shown, are the same projects which Gradle shows. -The `@nx/gradle` plugin reflects the graph of projects in Gradle into the Nx Project Graph. As projects -are created, deleted, and change their dependencies, Nx will automatically recalculate the graph. Exploring this graph -visually is vital to understanding how your code is structured and how Nx and Gradle behaves. - -##### Mac/Linux - -```shell no-run -./nx graph -``` - -##### Windows - -```shell no-run -./nx.bat graph -``` - -##### Graph Result - -import { Graph } from '@nx/nx-dev/ui-markdoc'; - -
- -
diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/4-run-tasks/content.mdx b/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/4-run-tasks/content.mdx deleted file mode 100644 index 4808bd87d8..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/4-run-tasks/content.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -type: lesson -title: Run Tasks ---- - -## Run Tasks - -Nx is a task runner built for monorepos. It can run a single task for a single project, a task for all projects, and -even intelligently run a subset of tasks based on the changes you've made in your repository. Nx also has sophisticated -computation caching to reuse the results of tasks. We will explore how Nx adds to the task running Gradle provides. - -Before we start running tasks, let's explore the tasks available for the `application` project. The `@nx/gradle` plugin -that we've installed reflects Gradle's tasks to Nx, which allows it to run any of the Gradle tasks defined for that project. You can view the available tasks either through [Nx Console](/getting-started/editor-setup) or from the terminal: - -```shell no-run -./nx show project application --web -``` - -import { ProjectDetails } from '@nx/nx-dev/ui-markdoc'; - -
- -
- -The Nx command to run the `build` task for the `application` project is: - -```shell no-run -./nx run application:build -``` - -When Nx runs a Gradle task, it hands off the execution of that task to Gradle, so all task dependencies and -configuration settings in the Gradle configuration are still respected. - -By running the task via Nx, however, the task computation was cached for reuse. Now, running `./nx run application:build` -again, will complete almost instantly as the result from the previous execution will be used. - -```shell no-run -./nx run application:build -``` - -``` - - ✔ 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 application:classes [existing outputs match the cache, left as is] - -> ./gradlew :application:classes - -> Task :library:compileJava UP-TO-DATE -> Task :library:processResources NO-SOURCE -> Task :library:classes UP-TO-DATE -> Task :library:jar UP-TO-DATE -> Task :application:compileJava UP-TO-DATE -> Task :application:processResources UP-TO-DATE -> Task :application:classes UP-TO-DATE - -BUILD SUCCESSFUL in 647ms -4 actionable tasks: 4 up-to-date - -> nx run application:build [existing outputs match the cache, left as is] - -> ./gradlew :application:build - - -Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. - -You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. - -For more on this, please refer to https://docs.gradle.org/8.5/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. - -BUILD SUCCESSFUL in 768ms -9 actionable tasks: 1 executed, 8 up-to-date - -————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - NX Successfully ran target build for project application and 3 tasks it depends on (30ms) - -Nx read the output from the cache instead of running the command for 4 out of 4 tasks. -``` - -Now that we've run one task, let's run all the `build` tasks in the repository with the Nx `run-many` command. This is similar to Gradle's `./gradlew build` command. - -```shell no-run -./nx run-many -t build -``` - -``` - - ✔ nx run library:classes [existing outputs match the cache, left as is] - ✔ nx run library:build [existing outputs match the cache, left as is] - ✔ nx run application:classes [existing outputs match the cache, left as is] - ✔ nx run application:build [existing outputs match the cache, left as is] - ✔ nx run gradle-tutorial:classes (1s) - ✔ nx run gradle-tutorial:build (1s) - -————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————— - - NX Successfully ran target build for 3 projects and 3 tasks they depend on (2s) - -Nx read the output from the cache instead of running the command for 4 out of 6 tasks. -``` - -Again, because Nx cached the tasks when the application was built, most of the tasks here were near instant. The only -ones which needed to be done is the root project's build. Running the command one more time, will be near instant as -then all the tasks will be restored from the cache. diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/5-affected/content.mdx b/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/5-affected/content.mdx deleted file mode 100644 index 6da2358593..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/5-affected/content.mdx +++ /dev/null @@ -1,63 +0,0 @@ ---- -type: lesson -title: Affected ---- - -## Run Tasks for Affected Projects - -Nx doesn't just cache your task results, it can also [eliminate the need to run unnecessary tasks](/ci/features/affected). - -First, commit any outstanding changes to the `main` branch locally: - -```shell no-run -git commit -am "changes" -``` - -Next make a small change to the `application` code: - -```java title="application/src/main/java/com/example/multimodule/application/DemoApplication.java" {21} -package com.example.multimodule.application; - -import com.example.multimodule.service.MyService; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -@SpringBootApplication(scanBasePackages = "com.example.multimodule") -@RestController -public class DemoApplication { - - private final MyService myService; - - public DemoApplication(MyService myService) { - this.myService = myService; - } - - @GetMapping("/") - public String home() { - return myService.message() + " changed!"; - } - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } -} -``` - -As a developer, we know that this change only affects the `application` project, not the `library` project. We would -run `./nx run application:test` to verify our changes. In CI, teams often run all test tasks rerunning -the `library:test` task unnecessarily. - -For a repository with only a few projects, you can manually calculate which projects are affected. As the repository grows, it becomes critical to have a tool like Nx that understands the project dependency graph and eliminates wasted time in CI. - -The `./nx affected` command solves this problem. Nx uses its project graph in conjunction with git history to only run -tasks for projects that may have been affected by the changes that you made. - -To run the `test` tasks for projects affected by this change, run: - -```shell no-run -./nx affected -t test -``` - -Notice that this command does not run the `test` task for the `library` project, since it could not have been affected by the code change. diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/meta.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/meta.md deleted file mode 100644 index 42a2cf19bd..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/2g-smart-monorepo/meta.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: chapter -title: Smart Monorepo ---- diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/1-welcome/content.mdx b/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/1-welcome/content.mdx deleted file mode 100644 index 88892b21b0..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/1-welcome/content.mdx +++ /dev/null @@ -1,23 +0,0 @@ ---- -type: lesson -title: About Nx Cloud ---- - -## Fast CI ⚡ - -import { GithubRepository } from '@nx/nx-dev/ui-markdoc'; - -:::info -Make sure you have completed the previous sections of this tutorial before starting this one. If you want a clean starting point, you can check out the [reference code](https://github.com/nrwl/nx-recipes/tree/main/gradle) as a starting point. - -
- -
-::: - -So far in this tutorial you've seen how Nx improves the local development experience, but the biggest difference Nx makes is in CI. As repositories get bigger, making sure that the CI is fast, reliable and maintainable can get very challenging. Nx provides a solution. - -- Nx reduces wasted time in CI with the [`affected` command](/ci/features/affected). -- Nx Replay's [remote caching](/ci/features/remote-cache) will reuse task artifacts from different CI executions making sure you will never run the same computation twice. -- Nx Agents [efficiently distribute tasks across machines](/ci/features/distribute-task-execution) ensuring constant CI time regardless of the repository size. The right number of machines is allocated for each PR to ensure good performance without wasting compute. -- Nx Atomizer [automatically splits](/ci/features/split-e2e-tasks) large e2e tests to distribute them across machines. Nx can also automatically [identify and rerun flaky e2e tests](/ci/features/flaky-tasks). diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/2-connect-to-nx-cloud/content.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/2-connect-to-nx-cloud/content.md deleted file mode 100644 index c4c43135a6..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/2-connect-to-nx-cloud/content.md +++ /dev/null @@ -1,38 +0,0 @@ ---- -type: lesson -title: Connect to Nx Cloud ---- - -## Connect to Nx Cloud - -Nx Cloud is a companion app for your CI system that provides remote caching, task distribution, e2e tests deflaking, better DX and more. - -Now that we're working on the CI pipeline, it is important for your changes to be pushed to a GitHub repository. - -1. Create a [new GitHub repository](https://github.com/new) if you don't already have one. -2. Copy the path to your repository (i.e. https://github.com/[your-user-name]/[your-repo-name].git) -3. In the terminal, add the GitHub repository as a remote with `git remote add origin https://github.com/[your-user-name]/[your-repo-name].git` -4. Commit your existing changes with `git add . && git commit -am "updates"` -5. Push your changes to your forked GitHub repository with `git push -u origin HEAD` - -Now connect your repository to Nx Cloud with the following command: - -```shell no-run -npx nx connect -``` - -A browser window will open to register your repository in your [Nx Cloud](https://cloud.nx.app) account. The link is also printed to the terminal if the windows does not open, or you closed it before finishing the steps. The app will guide you to create a PR to enable Nx Cloud on your repository. - -![](/tutorials/images/nx-cloud-github-connect.avif) - -Once the PR is created, merge it into your main branch. - -![](/tutorials/images/github-cloud-pr-merged.avif) - -And make sure you pull the latest changes locally: - -```shell no-run -git pull -``` - -You should now have an `nxCloudId` property specified in the `nx.json` file. diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/3-create-ci-workflow/content.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/3-create-ci-workflow/content.md deleted file mode 100644 index f11bbe2881..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/3-create-ci-workflow/content.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -type: lesson -title: Create a CI Workflow ---- - -## Create a CI Workflow - -Use the following command to generate a CI workflow file. - -```shell no-run -npx nx generate ci-workflow --ci=github -``` - -This generator creates a `.github/workflows/ci.yml` file that contains a CI pipeline that will run the `lint`, `test`, `build` and `e2e` tasks for projects that are affected by any given PR. If you would like to also distribute tasks across multiple machines to ensure fast and reliable CI runs, uncomment the `nx-cloud start-ci-run` line and have the `nx affected` line run the `e2e-ci` task instead of `e2e`. - -The key lines in the CI pipeline are: - -```yml title=".github/workflows/ci.yml" {21-24,38-39} -name: CI - -on: - push: - branches: - - main - pull_request: - -permissions: - actions: read - contents: read - -jobs: - main: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - filter: tree:0 - - # This enables task distribution via Nx Cloud - # Run this command as early as possible, before dependencies are installed - # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun - # Uncomment this line to enable task distribution - # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" - - - name: Set up JDK 21 for x64 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - architecture: x64 - - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - - - uses: nrwl/nx-set-shas@v4 - - # Nx Affected runs only tasks affected by the changes in this PR/commit. Learn more: https://nx.dev/ci/features/affected - - run: ./nx affected -t test build -``` diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/4-open-pr/content.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/4-open-pr/content.md deleted file mode 100644 index 3a037ae9de..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/4-open-pr/content.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -type: lesson -title: Open a Pull Request -custom: - last: true ---- - -## Open a Pull Request - -Commit the changes and open a new PR on GitHub. - -```shell no-run -git add . -git commit -m 'add CI workflow file' -git push origin add-workflow -``` - -When you view the PR on GitHub, you will see a comment from Nx Cloud that reports on the status of the CI run. - -![Nx Cloud report](/tutorials/images/github-pr-cloud-report.avif) - -The `See all runs` link goes to a page with the progress and results of tasks that were run in the CI pipeline. - -![Run details](/tutorials/images/nx-cloud-run-details.avif) - -For more information about how Nx can improve your CI pipeline, check out one of these detailed tutorials: - -- [Circle CI with Nx](/ci/intro/tutorials/circle) -- [GitHub Actions with Nx](/ci/intro/tutorials/github-actions) - -## Next Steps - -Connect with the rest of the Nx community with these resources: - -- ⭐️ [Star us on GitHub](https://github.com/nrwl/nx) to show your support and stay updated on new releases! -- [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](/blog) -- [Subscribe to our Youtube channel](https://www.youtube.com/@nxdevtools) for demos and Nx insights diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/meta.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/meta.md deleted file mode 100644 index faeb358452..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/3g-fast-ci/meta.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: chapter -title: Fast CI -editor: false -previews: false -terminal: false ---- diff --git a/nx-dev/tutorial/src/content/tutorial/4-gradle/meta.md b/nx-dev/tutorial/src/content/tutorial/4-gradle/meta.md deleted file mode 100644 index c6a15fb2e2..0000000000 --- a/nx-dev/tutorial/src/content/tutorial/4-gradle/meta.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -type: part -title: Gradle -meta: - title: 'Nx Tutorial: Gradle' - image: /images/nx-media.png -downloadAsZip: true -editor: false -previews: false -terminal: false ---- diff --git a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-6/nx.json b/nx-dev/tutorial/src/templates/angular-monorepo/lesson-6/nx.json index 1e617e8f53..40f3290647 100644 --- a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-6/nx.json +++ b/nx-dev/tutorial/src/templates/angular-monorepo/lesson-6/nx.json @@ -17,6 +17,7 @@ ], "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"] }, + "nxCloudId": "67b34f1b5f0dc34dcae257e2", "targetDefaults": { "@angular-devkit/build-angular:application": { "cache": true, diff --git a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/angular-store/src/app/app.component.spec.ts b/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/angular-store/src/app/app.component.spec.ts deleted file mode 100644 index fb0d46a148..0000000000 --- a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/angular-store/src/app/app.component.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -import { NxWelcomeComponent } from './nx-welcome.component'; -import { RouterModule } from '@angular/router'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent, NxWelcomeComponent, RouterModule.forRoot([])], - }).compileComponents(); - }); - - it(`should have as title 'angular-store'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('angular-store'); - }); -}); diff --git a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/inventory/src/app/app.component.spec.ts b/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/inventory/src/app/app.component.spec.ts deleted file mode 100644 index d54dca213c..0000000000 --- a/nx-dev/tutorial/src/templates/angular-monorepo/lesson-7/apps/inventory/src/app/app.component.spec.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AppComponent } from './app.component'; -import { NxWelcomeComponent } from './nx-welcome.component'; -import { RouterModule } from '@angular/router'; - -describe('AppComponent', () => { - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [AppComponent, NxWelcomeComponent, RouterModule.forRoot([])], - }).compileComponents(); - }); - - it('should render title', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.nativeElement as HTMLElement; - expect(compiled.querySelector('p')?.textContent).toContain( - 'Products' - ); - }); - - it(`should have as title 'inventory'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.componentInstance; - expect(app.title).toEqual('inventory'); - }); -}); diff --git a/nx-dev/tutorial/src/templates/default/.env b/nx-dev/tutorial/src/templates/default/.env index 301d29f58e..d8bf6191d6 100644 --- a/nx-dev/tutorial/src/templates/default/.env +++ b/nx-dev/tutorial/src/templates/default/.env @@ -1,3 +1,2 @@ NX_DAEMON=false NX_PREFER_TS_NODE=true -NODE_NO_WARNINGS=1 diff --git a/nx-dev/tutorial/src/templates/react-monorepo/lesson-2/nx.json b/nx-dev/tutorial/src/templates/react-monorepo/lesson-2/nx.json index b02af17dbd..57277a6751 100644 --- a/nx-dev/tutorial/src/templates/react-monorepo/lesson-2/nx.json +++ b/nx-dev/tutorial/src/templates/react-monorepo/lesson-2/nx.json @@ -15,6 +15,7 @@ ], "sharedGlobals": [] }, + "nxCloudId": "68101bb54a6391016e75634c", "plugins": [ { "plugin": "@nx/js/typescript", diff --git a/nx-dev/tutorial/src/templates/react-monorepo/lesson-6/nx.json b/nx-dev/tutorial/src/templates/react-monorepo/lesson-6/nx.json index 8489532cda..3e16b79395 100644 --- a/nx-dev/tutorial/src/templates/react-monorepo/lesson-6/nx.json +++ b/nx-dev/tutorial/src/templates/react-monorepo/lesson-6/nx.json @@ -15,6 +15,7 @@ ], "sharedGlobals": [] }, + "nxCloudId": "68101bb54a6391016e75634c", "plugins": [ { "plugin": "@nx/js/typescript", diff --git a/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/inventory/src/app/app.spec.tsx b/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/inventory/src/app/app.spec.tsx deleted file mode 100644 index 3a848a2292..0000000000 --- a/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/inventory/src/app/app.spec.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { render } from '@testing-library/react'; - -import App from './app'; - -describe('App', () => { - it('should render successfully', () => { - const { baseElement } = render(); - expect(baseElement).toBeTruthy(); - }); - - it('should have a greeting as the title', () => { - const { getByText } = render(); - expect( - getByText(new RegExp('Products', 'gi')) - ).toBeTruthy(); - }); -}); diff --git a/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/react-store/src/app/app.spec.tsx b/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/react-store/src/app/app.spec.tsx deleted file mode 100644 index 52164569b8..0000000000 --- a/nx-dev/tutorial/src/templates/react-monorepo/lesson-7/apps/react-store/src/app/app.spec.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { render } from '@testing-library/react'; -import { BrowserRouter } from 'react-router-dom'; -import App from './app'; - -describe('App', () => { - it('should render successfully', () => { - const { baseElement } = render( - - - - ); - expect(baseElement).toBeTruthy(); - }); - - it('should have a greeting as the title', () => { - const { getByText } = render( - - - - ); - expect( - getByText(new RegExp('Home', 'gi')) - ).toBeTruthy(); - }); -}); diff --git a/nx-dev/tutorial/theme.css b/nx-dev/tutorial/theme.css index d89bc6f06c..62218b9101 100644 --- a/nx-dev/tutorial/theme.css +++ b/nx-dev/tutorial/theme.css @@ -13,9 +13,3 @@ max-width: 56rem; margin: 0 auto; } - -.markdown-content :is(h1, h2, h3, h4, h5, h6) { - font-size: revert; - line-height: revert; - margin: revert; -} diff --git a/nx-dev/ui-common/src/lib/sidebar.tsx b/nx-dev/ui-common/src/lib/sidebar.tsx index dd19adde38..d8a78cffcc 100644 --- a/nx-dev/ui-common/src/lib/sidebar.tsx +++ b/nx-dev/ui-common/src/lib/sidebar.tsx @@ -137,22 +137,6 @@ function SidebarSectionItems({ item }: { item: MenuItem }): JSX.Element { > {subItem.children.length ? ( - ) : subItem.isExternal ? ( - - - {subItem.name} - - ) : ( - {icon && ( -
- {icon.startsWith('/') ? ( - {title} - ) : ( - frameworkIcons[icon as Framework]?.image || - callIfFunction(nxDevIcons[icon as keyof typeof nxDevIcons]) || - callIfFunction( - (heroIcons[icon as keyof typeof heroIcons] as any)?.render, - { className: 'w-full h-full' } - ) - )} -
- )} -
- {appearance === 'small' && type ? null : ( -
- {type} -
- )} -

- {title} -

-
- - ); - } - return isExternal ? ( - - {linkContents()} - - ) : ( + return ( - {linkContents()} + {icon && ( +
+ {icon.startsWith('/') ? ( + {title} + ) : ( + frameworkIcons[icon as Framework]?.image || + callIfFunction(nxDevIcons[icon as keyof typeof nxDevIcons]) || + callIfFunction( + (heroIcons[icon as keyof typeof heroIcons] as any)?.render, + { className: 'w-full h-full' } + ) + )} +
+ )} +
+ {appearance === 'small' && type ? null : ( +
+ {type} +
+ )} +

+ {title} +

+
); } @@ -200,13 +182,11 @@ export function Card({ title, type = 'documentation', url, - isExternal = false, }: { title: string; description: string; type: 'documentation' | 'external' | 'video'; url: string; - isExternal?: boolean; }): JSX.Element { const iconMap = { documentation: , @@ -219,47 +199,7 @@ export function Card({ ); const hasYoutubeId = !!youtubeRegex ? youtubeRegex[1] : ''; - function linkContents() { - return ( - <> - {!!hasYoutubeId && ( -
- Youtube Link -
- )} -
- - - {!hasYoutubeId ? iconMap[type] : null} - {title} - - {description ? ( -

{description}

- ) : null} - - {/*HOVER ICON*/} - - - -
- - ); - } - - return isExternal ? ( - - {linkContents()} - - ) : ( + return ( - {linkContents()} + {!!hasYoutubeId && ( +
+ Youtube Link +
+ )} +
+ + + {!hasYoutubeId ? iconMap[type] : null} + {title} + + {description ? ( +

{description}

+ ) : null} + + {/*HOVER ICON*/} + + + +
); } diff --git a/nx-dev/ui-markdoc/src/lib/tags/cards.schema.ts b/nx-dev/ui-markdoc/src/lib/tags/cards.schema.ts index eae9c0ca31..65d3a94a9a 100644 --- a/nx-dev/ui-markdoc/src/lib/tags/cards.schema.ts +++ b/nx-dev/ui-markdoc/src/lib/tags/cards.schema.ts @@ -45,10 +45,6 @@ export const linkCard: Schema = { type: 'String', default: '', }, - isExternal: { - type: 'Boolean', - default: false, - }, appearance: { type: 'String', default: 'default', @@ -75,9 +71,5 @@ export const card: Schema = { type: 'String', default: '', }, - isExternal: { - type: 'Boolean', - default: false, - }, }, }; diff --git a/nx-dev/ui-react/src/lib/hero.tsx b/nx-dev/ui-react/src/lib/hero.tsx index ede2f81f0a..5b85f2a58e 100644 --- a/nx-dev/ui-react/src/lib/hero.tsx +++ b/nx-dev/ui-react/src/lib/hero.tsx @@ -39,7 +39,7 @@ export function Hero(): ReactElement {