https://github.com/stefanoslig/angular-ngrx-nx-realworld-example-app
Real world application built with Angular 18, NgRx 18, nrwl/nx 18
https://github.com/stefanoslig/angular-ngrx-nx-realworld-example-app
angular angular18 component-store ngrx ngrx-effects ngrx-signals-store ngrx-store nrwl nrwl-nx nx nx-workspace realworld-angular standalone-components
Last synced: 5 days ago
JSON representation
Real world application built with Angular 18, NgRx 18, nrwl/nx 18
- Host: GitHub
- URL: https://github.com/stefanoslig/angular-ngrx-nx-realworld-example-app
- Owner: stefanoslig
- License: mit
- Created: 2018-01-21T17:48:04.000Z (almost 8 years ago)
- Default Branch: main
- Last Pushed: 2024-10-29T17:28:10.000Z (about 1 year ago)
- Last Synced: 2024-10-29T18:51:14.763Z (about 1 year ago)
- Topics: angular, angular18, component-store, ngrx, ngrx-effects, ngrx-signals-store, ngrx-store, nrwl, nrwl-nx, nx, nx-workspace, realworld-angular, standalone-components
- Language: TypeScript
- Homepage: https://angular-ngrx-nx.netlify.app/
- Size: 26.1 MB
- Stars: 902
- Watchers: 27
- Forks: 264
- Open Issues: 19
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
- fucking-awesome-angular - angular-ngrx-nx-realworld-example-app - Real world application built with Angular 17, NgRx 17, & Nx 17. (State Management / NgRx)
- awesome-angular - angular-ngrx-nx-realworld-example-app - Real world application built with Angular 17, NgRx 17, & Nx 17. (State Management / NgRx)
- awesome-nx - Exemplary real world application built with Angular 10+, NgRx 10+, nrwl/nx 10+
README
# Angular NgRx NX realworld example app

### Modern Angular features:
- New Control Flow
- Deferred Loading
- Zoneless
- Signal inputs and outputs
- State management using NgRx Signals Store
- DI using the inject function
- Functional resolvers and guards
> ### Angular, ngrx/platform, nrwl/nx codebase containing real world examples (CRUD, auth, advanced patterns, etc) that adheres to the [RealWorld](https://github.com/gothinkster/realworld) spec and API.
### [Demo](https://angular-ngrx-nx-realworld-example-app-lyart.vercel.app) [RealWorld](https://github.com/gothinkster/realworld)
#### [NgRx Signal Store Article](https://www.stefanos-lignos.dev/posts/ngrx-signals-store)
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](https://github.com/gothinkster/realworld) repo.
## Functionality overview
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:**
- Authenticate users via JWT (login/signup pages + logout button on settings page)
- CRU\* users (sign up & settings page - no deleting required)
- CRUD Articles
- CR\*D Comments on articles (no updating required)
- GET and display paginated lists of articles
- Favorite articles
- Follow other users
**The general page breakdown looks like this:**
- Home page (URL: /#/ )
- List of tags
- List of articles pulled from either Feed, Global, or by Tag
- Pagination for list of articles
- Sign in/Sign up pages (URL: /#/login, /#/register )
- Uses JWT
- Cookie based authentication
- Settings page (URL: /#/settings )
- Editor page to create/edit articles (URL: /#/editor, /#/editor/article-slug-here )
- Article page (URL: /#/article/article-slug-here )
- Delete article button (only shown to article's author)
- Render markdown from server client side
- Comments section at bottom of page
- Delete comment button (only shown to comment's author)
- Profile page (URL: /#/profile/:username, /#/profile/:username/favorites )
- Show basic user info
- List of articles populated from author's created articles or author's favorited articles
## Commands
### Run the application
`npm run start`
### Unit tests
Run all the tests: `nx run-many -t test`
### Lint
`nx run-many -t lint`
## Architecture
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:
### Monorepo Structure with Nx
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:
- **Scalability**: The codebase can easily grow while maintaining clear separation of concerns
- **Dependency Graph Management**: Nx automatically tracks dependencies between libraries
- **Improved Build Performance**: Nx's powerful caching and affected commands allow for faster builds and tests
### Library Organization
Libraries are classified using two dimensions:
1. **Scope (Domain)**: Defines which section of the app can use the library
- `auth`: Authentication-related features
- `articles`: Article-related features
- `profile`: User profile features
- `home`: Home page features
- `core` (to be renamed to `shared`): Common utilities and components that can be used across the application
2. **Type**: Defines the purpose of the library
- `feature-*`: Contains smart components that communicate with data sources
- `data-access`: Contains services and state management for interacting with the server
- `ui`: Contains presentational (dumb) components that are reusable within their scope
- `api-types`: Contains TypeScript interfaces for API models
- `forms`: Contains form-related components and utilities
The 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
```
### State Management with NgRx Signal Store
The application uses NgRx Signal Store, a modern state management approach based on Angular's Signals, providing:
- **Reactivity**: Based on Angular's Signal API for efficient change detection
- **TypeScript Integration**: Strong typing throughout the state management system
- **Simplified API**: More concise and intuitive compared to traditional NgRx with reducers and effects
- **Immutability**: Enforces immutable state updates
Here's how the store pattern is implemented:
```typescript
export const AuthStore = signalStore(
{ providedIn: 'root' },
withState(authInitialState),
withMethods(
(store, formErrorsStore = inject(FormErrorsStore), authService = inject(AuthService), router = inject(Router)) => ({
getUser: rxMethod(
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 state
- `withMethods`: To define methods that can modify the state
- `rxMethod`: To handle asynchronous operations using RxJS
- `patchState`: To update the state immutably
- `withCallState`: To track loading, error and success states
### Standalone Components
The application exclusively uses standalone components, eliminating the need for NgModules. This results in:
- **Simplified Architecture**: No need for complex module hierarchy
- **Improved Tree-Shaking**: Better optimization of the final bundle
- **Explicit Dependencies**: Each component declares its own dependencies
Example of a standalone component:
```typescript
@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
}
```
### Dependency Injection with inject()
The application uses the modern `inject()` function instead of constructor-based dependency injection:
- **Cleaner Code**: Reduces boilerplate compared to constructor injection
- **Better TypeScript Inference**: TypeScript can better infer types with inject
- **More Flexible**: Can be used within functions, not just classes
### Lazy Loading
The application implements lazy loading for all major routes to improve initial load time:
```typescript
{
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 components
- `loadChildren`: For lazy loading entire route trees
### Smart vs Dumb Components Pattern
The application follows the smart/dumb component pattern:
- **Smart Components**:
- Handle data fetching and state management
- Located in `feature-*` libraries
- Inject services and stores
- Pass data to dumb components
- **Dumb Components**:
- Are purely presentational
- Located in `ui` libraries
- Receive data via inputs and emit events via outputs
- Have no dependencies on services or stores
- Easily testable and reusable
### Minimal External Dependencies
The project avoids external UI libraries and frameworks to:
- Maintain full control over the codebase
- Avoid opinionated styles
- Simplify migration to newer Angular versions
- Reduce bundle size
### Testing Strategy
The application uses Jest for unit testing and Playwright for end-to-end testing:
- Unit tests focus on testing individual components, services, and stores in isolation
- E2E tests validate the full user experience
### Modern Angular Features
The application leverages the latest Angular features:
- **New Control Flow**: Uses the new `@if`, `@for`, and `@switch` syntax for clearer templates
- **Deferred Loading**: Implements content deferral for better initial load performance
- **Zoneless**: Uses zoneless change detection for improved performance
- **Signal Inputs and Outputs**: Uses the new signals-based inputs/outputs for better reactivity
- **Functional Resolvers and Guards**: Replaces class-based guards and resolvers with more concise functions
### Build and Deployment
The application uses Nx's build system for:
- Fast builds with caching
- Affected-only testing and building