Real world application built with Angular 21, NgRx 21, nrwl/nx 22
See the code
Angular, ngrx/platform, nrwl/nx codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.
This codebase was created to demonstrate a fully fledged fullstack application built with Angular, ngrx/platform, nrwl/nx including CRUD operations, authentication, routing, pagination, and more.
We've gone to great lengths to adhere to the Angular community styleguides & best practices.
For more information on how to this works with other frontends/backends, head over to the RealWorld repo.
The example application is a social blogging site (i.e. a Medium.com clone) called "Conduit". It uses a custom API for all requests, including authentication.
General functionality:
The general page breakdown looks like this:
npm run start
Run all the tests: nx run-many -t test
nx run-many -t lint
The project utilizes a cutting-edge Angular architecture with Nx monorepo workspace and NgRx Signal Store for state management. Here's a comprehensive overview of the key architectural concepts:
This project is organized as a monorepo using Nx, which enables a modular, scalable architecture with clear boundaries between different parts of the application. The main benefits include:
Libraries are classified using two dimensions:
Scope (Domain): Defines which section of the app can use the library
auth: Authentication-related featuresarticles: Article-related featuresprofile: User profile featureshome: Home page featurescore (to be renamed to shared): Common utilities and components that can be used across the applicationType: Defines the purpose of the library
feature-*: Contains smart components that communicate with data sourcesdata-access: Contains services and state management for interacting with the serverui: Contains presentational (dumb) components that are reusable within their scopeapi-types: Contains TypeScript interfaces for API modelsforms: Contains form-related components and utilitiesThe folder structure follows this pattern:
├── libs
│ ├── articles
│ │ ├── data-access
│ │ ├── feature-article-edit
│ │ ├── feature-article
│ │ ├── feature-articles-list
│ ├── auth
│ │ ├── data-access
│ │ ├── feature-auth
│ ├── core
│ │ ├── api-types
│ │ ├── error-handler
│ │ ├── http-client
│ │ ├── forms
│ ├── profile
│ │ ├── data-access
│ │ ├── feature-profile
│ ├── ui
│ │ ├── components
The application uses NgRx Signal Store, a modern state management approach based on Angular's Signals, providing:
Here's how the store pattern is implemented:
export const AuthStore = signalStore(
{ providedIn: 'root' },
withState<AuthState>(authInitialState),
withMethods(
(store, formErrorsStore = inject(FormErrorsStore), authService = inject(AuthService), router = inject(Router)) => ({
getUser: rxMethod<void>(
pipe(
switchMap(() => authService.user()),
tap(({ user }) => patchState(store, { user, loggedIn: true, ...setLoaded('getUser') })),
),
),
// Additional methods for login, register, updateUser, logout, etc.
}),
),
withCallState({ collection: 'getUser' }),
);
The store uses:
withState: To define the initial statewithMethods: To define methods that can modify the staterxMethod: To handle asynchronous operations using RxJSpatchState: To update the state immutablywithCallState: To track loading, error and success statesThe application exclusively uses standalone components, eliminating the need for NgModules. This results in:
Example of a standalone component:
@Component({
selector: 'cdt-login',
templateUrl: './login.component.html',
imports: [ListErrorsComponent, RouterLink, ReactiveFormsModule, InputErrorsComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginComponent {
private readonly authStore = inject(AuthStore);
private readonly fb = inject(FormBuilder);
// Component implementation
}
The application uses the modern inject() function instead of constructor-based dependency injection:
The application implements lazy loading for all major routes to improve initial load time:
{
path: 'home',
loadChildren: () => import('@realworld/home/src/lib/home.routes').then((home) => home.HOME_ROUTES),
},
{
path: 'login',
loadComponent: () => import('@realworld/auth/feature-auth').then((m) => m.LoginComponent),
},
// Additional routes...
This implementation uses:
loadComponent: For lazy loading standalone componentsloadChildren: For lazy loading entire route treesThe application follows the smart/dumb component pattern:
Smart Components:
feature-* librariesDumb Components:
ui librariesThe project avoids external UI libraries and frameworks to:
The application uses Jest for unit testing and Playwright for end-to-end testing:
The application leverages the latest Angular features:
@if, @for, and @switch syntax for clearer templatesThe application uses Nx's build system for:
571 followers · starred Nov 2019
37 followers · starred Oct 2018
40 followers · starred Sep 2019
108 followers · starred Dec 2023
Real world application built with Angular 21, NgRx 21, nrwl/nx 22
See the code
Angular, ngrx/platform, nrwl/nx codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the RealWorld spec and API.
This codebase was created to demonstrate a fully fledged fullstack application built with Angular, ngrx/platform, nrwl/nx including CRUD operations, authentication, routing, pagination, and more.
We've gone to great lengths to adhere to the Angular community styleguides & best practices.
For more information on how to this works with other frontends/backends, head over to the RealWorld repo.
The example application is a social blogging site (i.e. a Medium.com clone) called "Conduit". It uses a custom API for all requests, including authentication.
General functionality:
The general page breakdown looks like this:
npm run start
Run all the tests: nx run-many -t test
nx run-many -t lint
The project utilizes a cutting-edge Angular architecture with Nx monorepo workspace and NgRx Signal Store for state management. Here's a comprehensive overview of the key architectural concepts:
This project is organized as a monorepo using Nx, which enables a modular, scalable architecture with clear boundaries between different parts of the application. The main benefits include:
Libraries are classified using two dimensions:
Scope (Domain): Defines which section of the app can use the library
auth: Authentication-related featuresarticles: Article-related featuresprofile: User profile featureshome: Home page featurescore (to be renamed to shared): Common utilities and components that can be used across the applicationType: Defines the purpose of the library
feature-*: Contains smart components that communicate with data sourcesdata-access: Contains services and state management for interacting with the serverui: Contains presentational (dumb) components that are reusable within their scopeapi-types: Contains TypeScript interfaces for API modelsforms: Contains form-related components and utilitiesThe folder structure follows this pattern:
├── libs
│ ├── articles
│ │ ├── data-access
│ │ ├── feature-article-edit
│ │ ├── feature-article
│ │ ├── feature-articles-list
│ ├── auth
│ │ ├── data-access
│ │ ├── feature-auth
│ ├── core
│ │ ├── api-types
│ │ ├── error-handler
│ │ ├── http-client
│ │ ├── forms
│ ├── profile
│ │ ├── data-access
│ │ ├── feature-profile
│ ├── ui
│ │ ├── components
The application uses NgRx Signal Store, a modern state management approach based on Angular's Signals, providing:
Here's how the store pattern is implemented:
export const AuthStore = signalStore(
{ providedIn: 'root' },
withState<AuthState>(authInitialState),
withMethods(
(store, formErrorsStore = inject(FormErrorsStore), authService = inject(AuthService), router = inject(Router)) => ({
getUser: rxMethod<void>(
pipe(
switchMap(() => authService.user()),
tap(({ user }) => patchState(store, { user, loggedIn: true, ...setLoaded('getUser') })),
),
),
// Additional methods for login, register, updateUser, logout, etc.
}),
),
withCallState({ collection: 'getUser' }),
);
The store uses:
withState: To define the initial statewithMethods: To define methods that can modify the staterxMethod: To handle asynchronous operations using RxJSpatchState: To update the state immutablywithCallState: To track loading, error and success statesThe application exclusively uses standalone components, eliminating the need for NgModules. This results in:
Example of a standalone component:
@Component({
selector: 'cdt-login',
templateUrl: './login.component.html',
imports: [ListErrorsComponent, RouterLink, ReactiveFormsModule, InputErrorsComponent],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class LoginComponent {
private readonly authStore = inject(AuthStore);
private readonly fb = inject(FormBuilder);
// Component implementation
}
The application uses the modern inject() function instead of constructor-based dependency injection:
The application implements lazy loading for all major routes to improve initial load time:
{
path: 'home',
loadChildren: () => import('@realworld/home/src/lib/home.routes').then((home) => home.HOME_ROUTES),
},
{
path: 'login',
loadComponent: () => import('@realworld/auth/feature-auth').then((m) => m.LoginComponent),
},
// Additional routes...
This implementation uses:
loadComponent: For lazy loading standalone componentsloadChildren: For lazy loading entire route treesThe application follows the smart/dumb component pattern:
Smart Components:
feature-* librariesDumb Components:
ui librariesThe project avoids external UI libraries and frameworks to:
The application uses Jest for unit testing and Playwright for end-to-end testing:
The application leverages the latest Angular features:
@if, @for, and @switch syntax for clearer templatesThe application uses Nx's build system for:
571 followers · starred Nov 2019
37 followers · starred Oct 2018
40 followers · starred Sep 2019
108 followers · starred Dec 2023