docs(core): small tutorial updates (#26559)
Update the npm workspaces, react monorepo and angular monorepo tutorials
This commit is contained in:
parent
5b44085c81
commit
1d1c699c81
@ -385,24 +385,12 @@ All libraries that we generate automatically have aliases created in the root-le
|
||||
}
|
||||
```
|
||||
|
||||
Hence we can easily import them into other libraries and our Angular application. As an example, let's create and expose a `ProductListComponent` component from our `libs/products` library. Either create it by hand or run
|
||||
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.
|
||||
|
||||
```shell
|
||||
nx g @nx/angular:component product-list --directory=libs/products/src/lib/product-list --standalone --export
|
||||
```
|
||||
|
||||
We don't need to implement anything fancy as we just want to learn how to import it into our main Angular application.
|
||||
|
||||
```html {% fileName="libs/products/src/lib/product-list/product-list.component.html" %}
|
||||
<p>product-list works!</p>
|
||||
```
|
||||
|
||||
Make sure the `ProductListComponent` is exported via the `index.ts` file of our `products` library and is listed in the `exports` of the `ProductsModule`. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
|
||||
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';
|
||||
|
||||
export * from './lib/product-list/product-list.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`.
|
||||
@ -426,7 +414,7 @@ And in `app.component.html`:
|
||||
<router-outlet></router-outlet>
|
||||
```
|
||||
|
||||
Then we can add the `ProductListComponent` component to our `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/products` route.
|
||||
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';
|
||||
@ -441,7 +429,7 @@ export const appRoutes: Route[] = [
|
||||
{
|
||||
path: 'products',
|
||||
loadComponent: () =>
|
||||
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
|
||||
import('@angular-monorepo/products').then((m) => m.ProductsComponent),
|
||||
},
|
||||
];
|
||||
```
|
||||
@ -452,8 +440,7 @@ Serving your app (`nx serve angular-store`) and then navigating to `/products` s
|
||||
|
||||
Let's apply the same for our `orders` library.
|
||||
|
||||
- generate a new component `OrderListComponent` in `libs/orders` and export it in the corresponding `index.ts` file
|
||||
- import it into the `app.routes.ts` and render it via the routing mechanism whenever a user hits the `/orders` route
|
||||
- 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:
|
||||
|
||||
@ -470,12 +457,12 @@ export const appRoutes: Route[] = [
|
||||
{
|
||||
path: 'products',
|
||||
loadComponent: () =>
|
||||
import('@angular-monorepo/products').then((m) => m.ProductListComponent),
|
||||
import('@angular-monorepo/products').then((m) => m.ProductsComponent),
|
||||
},
|
||||
{
|
||||
path: 'orders',
|
||||
loadComponent: () =>
|
||||
import('@angular-monorepo/orders').then((m) => m.OrderListComponent),
|
||||
import('@angular-monorepo/orders').then((m) => m.OrdersComponent),
|
||||
},
|
||||
];
|
||||
```
|
||||
@ -484,12 +471,12 @@ Let's also show products in the `inventory` app.
|
||||
|
||||
```ts {% fileName="apps/inventory/src/app/app.component.ts" highlightLines=[2,6] %}
|
||||
import { Component } from '@angular/core';
|
||||
import { ProductListComponent } from '@angular-monorepo/products';
|
||||
import { ProductsComponent } from '@angular-monorepo/products';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
imports: [ProductListComponent],
|
||||
selector: 'angular-monorepo-root',
|
||||
imports: [ProductsComponent],
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css'],
|
||||
})
|
||||
@ -499,7 +486,7 @@ export class AppComponent {
|
||||
```
|
||||
|
||||
```ts {% fileName="apps/inventory/src/app/app.component.html" %}
|
||||
<angular-monorepo-product-list></angular-monorepo-product-list>
|
||||
<lib-products></lib-products>
|
||||
```
|
||||
|
||||
## Visualizing your Project Structure
|
||||
@ -1185,14 +1172,14 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
|
||||
}
|
||||
```
|
||||
|
||||
To test it, go to your `libs/products/src/lib/product-list/product-list.component.ts` file and import the `OrderListComponent` from the `orders` project:
|
||||
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 { OrderListComponent } from '@angular-monorepo/orders';
|
||||
import { OrdersComponent } from '@angular-monorepo/orders';
|
||||
|
||||
@Component({
|
||||
selector: 'angular-monorepo-product-list',
|
||||
@ -1201,7 +1188,7 @@ import { OrderListComponent } from '@angular-monorepo/orders';
|
||||
templateUrl: './product-list.component.html',
|
||||
styleUrls: ['./product-list.component.css'],
|
||||
})
|
||||
export class ProductListComponent {}
|
||||
export class ProductsComponent {}
|
||||
```
|
||||
|
||||
If you lint your workspace you'll get an error now:
|
||||
@ -1213,7 +1200,7 @@ NX Running target lint for 7 projects
|
||||
|
||||
/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 'OrderListComponent' is defined but never used @typescript-eslint/no-unused-vars
|
||||
5:10 warning 'OrdersComponent' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
✖ 2 problems (1 error, 1 warning)
|
||||
|
||||
|
||||
@ -302,7 +302,7 @@ First, let's delete the `outputs` array from `nx.json` so that we don't override
|
||||
Now let's add the `@nx/vite` plugin:
|
||||
|
||||
```{% command="npx nx add @nx/vite" path="~/tuskydesign" %}
|
||||
✔ Installing @nx/vite@18.1.0...
|
||||
✔ Installing @nx/vite...
|
||||
✔ Initializing @nx/vite...
|
||||
|
||||
NX Package @nx/vite added successfully.
|
||||
@ -311,13 +311,13 @@ Now let's add the `@nx/vite` plugin:
|
||||
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/vite`, the initialization script registers the plugin in the `plugins` array of `nx.json` and updates any `package.json` scripts that execute Vite related tasks. Open the project details view for the `demo` app and look at the `build` task.
|
||||
|
||||
```shell {% path="~/tuskydesigns" %}
|
||||
npx nx show project @tuskdesign/demo --web
|
||||
npx nx show project @tuskdesign/demo
|
||||
```
|
||||
|
||||
{% project-details title="Project Details View" jsonFile="shared/tutorials/npm-workspaces-pdv.json" %}
|
||||
{% /project-details %}
|
||||
|
||||
If you hover over the settings for the `build` task, you can see where those settings come from. The `inputs` and `outputs` are defined by the `@nx/vite` plugin from the `vite.config.ts` file where as the `dependsOn` property we set earlier in the tutorial in the `targetDefaults` in the `nx.json` file.
|
||||
If you hover over the settings for the `vite:build` task, you can see where those settings come from. The `inputs` and `outputs` are defined by the `@nx/vite` plugin from the `vite.config.ts` file where as the `dependsOn` property we set earlier in the tutorial in the `targetDefaults` in the `nx.json` file.
|
||||
|
||||
Now let's change where the `build` results are output to in the `vite.config.ts` file.
|
||||
|
||||
@ -403,7 +403,7 @@ This generator creates a `.github/workflows/ci.yml` file that contains a CI pipe
|
||||
The key line in the CI pipeline is:
|
||||
|
||||
```yml
|
||||
- run: npx nx affected -t lint test build e2e-ci
|
||||
- run: npx nx affected -t lint test build
|
||||
```
|
||||
|
||||
### Connect to Nx Cloud
|
||||
|
||||
@ -98,7 +98,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
|
||||
@ -128,7 +128,7 @@ Nx uses the following syntax to run 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
|
||||
nx show project react-store --web
|
||||
nx show project react-store
|
||||
```
|
||||
|
||||
{% project-details title="Project Details View (Simplified)" height="100px" %}
|
||||
@ -137,13 +137,9 @@ nx show project react-store --web
|
||||
{
|
||||
"project": {
|
||||
"name": "react-store",
|
||||
"type": "app",
|
||||
"data": {
|
||||
"metadata": {
|
||||
"technologies": ["react"]
|
||||
},
|
||||
"root": "apps/react-store",
|
||||
"includedScripts": [],
|
||||
"name": "react-store",
|
||||
"targets": {
|
||||
"build": {
|
||||
"options": {
|
||||
@ -161,15 +157,13 @@ nx show project react-store --web
|
||||
],
|
||||
"outputs": ["{workspaceRoot}/dist/apps/react-store"],
|
||||
"executor": "nx:run-commands",
|
||||
"configurations": {},
|
||||
"metadata": {
|
||||
"technologies": ["vite"]
|
||||
}
|
||||
"configurations": {}
|
||||
}
|
||||
},
|
||||
"name": "react-store",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "apps/react-store/src",
|
||||
"projectType": "application",
|
||||
"$schema": "node_modules/nx/schemas/project-schema.json",
|
||||
"tags": [],
|
||||
"implicitDependencies": []
|
||||
}
|
||||
@ -433,35 +427,12 @@ All libraries that we generate automatically have aliases created in the root-le
|
||||
}
|
||||
```
|
||||
|
||||
Hence we can easily import them into other libraries and our React application. As an example, let's create and expose a `ProductList` component from our `libs/products` library. Either create it by hand or run
|
||||
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.
|
||||
|
||||
```shell
|
||||
nx g @nx/react:component product-list --project=products --directory="libs/products/src/lib/product-list"
|
||||
```
|
||||
|
||||
We don't need to implement anything fancy as we just want to learn how to import it into our main React application.
|
||||
|
||||
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
|
||||
import styles from './product-list.module.css';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface ProductListProps {}
|
||||
|
||||
export function ProductList(props: ProductListProps) {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<h1>Welcome to ProductList!</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProductList;
|
||||
```
|
||||
|
||||
Make sure the `ProductList` is exported via the `index.ts` file of our `products` library. This is our public API with the rest of the workspace. Only export what's really necessary to be usable outside the library itself.
|
||||
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/product-list/product-list';
|
||||
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.
|
||||
@ -512,13 +483,13 @@ root.render(
|
||||
);
|
||||
```
|
||||
|
||||
Then we can import the `ProductList` component into our `app.tsx` and render it via the routing mechanism whenever a user hits the `/products` route.
|
||||
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 { ProductList } from '@react-monorepo/products';
|
||||
import { Products } from '@react-monorepo/products';
|
||||
|
||||
function Home() {
|
||||
return <h1>Home</h1>;
|
||||
@ -528,7 +499,7 @@ export function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />}></Route>
|
||||
<Route path="/products" element={<ProductList />}></Route>
|
||||
<Route path="/products" element={<Products />}></Route>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
@ -542,15 +513,14 @@ Serving your app (`nx serve react-store`) and then navigating to `/products` sho
|
||||
|
||||
Let's apply the same for our `orders` library.
|
||||
|
||||
- generate a new component `OrderList` in `libs/orders` and export it in the corresponding `index.ts` file
|
||||
- import it into the `app.tsx` and render it via the routing mechanism whenever a user hits the `/orders` route
|
||||
- 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 { ProductList } from '@react-monorepo/products';
|
||||
import { OrderList } from '@react-monorepo/orders';
|
||||
import { Products } from '@react-monorepo/products';
|
||||
import { Orders } from '@react-monorepo/orders';
|
||||
|
||||
function Home() {
|
||||
return <h1>Home</h1>;
|
||||
@ -560,8 +530,8 @@ export function App() {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />}></Route>
|
||||
<Route path="/products" element={<ProductList />}></Route>
|
||||
<Route path="/orders" element={<OrderList />}></Route>
|
||||
<Route path="/products" element={<Products />}></Route>
|
||||
<Route path="/orders" element={<Orders />}></Route>
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
@ -572,10 +542,10 @@ export default App;
|
||||
Let's also show products in the `inventory` app.
|
||||
|
||||
```tsx {% fileName="apps/inventory/src/app/app.tsx" %}
|
||||
import { ProductList } from '@react-monorepo/products';
|
||||
import { Products } from '@react-monorepo/products';
|
||||
|
||||
export function App() {
|
||||
return <ProductList />;
|
||||
return <Products />;
|
||||
}
|
||||
|
||||
export default App;
|
||||
@ -735,22 +705,19 @@ git commit -a -m "some commit message"
|
||||
|
||||
And then make a small change to the `products` library.
|
||||
|
||||
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
|
||||
import styles from './product-list.module.css';
|
||||
```tsx {% fileName="libs/products/src/lib/products.tsx" %}
|
||||
import styles from './products.module.css';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface ProductListProps {}
|
||||
|
||||
export function ProductList(props: ProductListProps) {
|
||||
export function Products() {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<h1>Welcome to ProductList!</h1>
|
||||
<h1>Welcome to Products!</h1>
|
||||
<p>This is a change. 👋</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProductList;
|
||||
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:
|
||||
@ -970,10 +937,6 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
|
||||
"enforceBuildableLibDependency": true,
|
||||
"allow": [],
|
||||
"depConstraints": [
|
||||
{
|
||||
"sourceTag": "*",
|
||||
"onlyDependOnLibsWithTags": ["*"]
|
||||
},
|
||||
{
|
||||
"sourceTag": "type:feature",
|
||||
"onlyDependOnLibsWithTags": ["type:feature", "type:ui"]
|
||||
@ -1008,27 +971,24 @@ To enforce the rules, Nx ships with a custom ESLint rule. Open the `.eslintrc.ba
|
||||
}
|
||||
```
|
||||
|
||||
To test it, go to your `libs/products/src/lib/product-list/product-list.tsx` file and import the `OrderList` 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:
|
||||
|
||||
```tsx {% fileName="libs/products/src/lib/product-list/product-list.tsx" %}
|
||||
import styles from './product-list.module.css';
|
||||
```tsx {% fileName="libs/products/src/lib/products.tsx" %}
|
||||
import styles from './products.module.css';
|
||||
|
||||
// This import is not allowed 👇
|
||||
import { OrderList } from '@react-monorepo/orders';
|
||||
import { Orders } from '@react-monorepo/orders';
|
||||
|
||||
/* eslint-disable-next-line */
|
||||
export interface ProductListProps {}
|
||||
|
||||
export function ProductList(props: ProductListProps) {
|
||||
export function Products() {
|
||||
return (
|
||||
<div className={styles['container']}>
|
||||
<h1>Welcome to ProductList!</h1>
|
||||
<OrderList />
|
||||
<h1>Welcome to Products!</h1>
|
||||
<p>This is a change. 👋</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ProductList;
|
||||
export default Products;
|
||||
```
|
||||
|
||||
If you lint your workspace you'll get an error now:
|
||||
@ -1038,9 +998,9 @@ If you lint your workspace you'll get an error now:
|
||||
✖ nx run products:lint
|
||||
Linting "products"...
|
||||
|
||||
/Users/isaac/Documents/code/nx-recipes/react-monorepo/libs/products/src/lib/product-list/product-list.tsx
|
||||
/Users/isaac/Documents/code/nx-recipes/react-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 'OrderList' is defined but never used @typescript-eslint/no-unused-vars
|
||||
4:10 warning 'Orders' is defined but never used @typescript-eslint/no-unused-vars
|
||||
|
||||
✖ 2 problems (1 error, 1 warning)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user