routing-performance-implementation

Routing & Performance Implementation Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "routing-performance-implementation" with this command: npx skills add pluginagentmarketplace/custom-plugin-angular/pluginagentmarketplace-custom-plugin-angular-routing-performance-implementation

Routing & Performance Implementation Skill

Quick Start

Basic Routing

import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { HomeComponent, AboutComponent, NotFoundComponent } from './components';

const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'about', component: AboutComponent }, { path: '**', component: NotFoundComponent } ];

@NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }

Navigation

import { Component } from '@angular/core'; import { Router } from '@angular/router';

@Component({ template: <button (click)="goHome()">Home</button> <a routerLink="/about">About</a> <a routerLink="/users" [queryParams]="{ tab: 'active' }">Users</a> }) export class NavComponent { constructor(private router: Router) {}

goHome() { this.router.navigate(['/']); } }

Route Parameters

const routes: Routes = [ { path: 'users/:id', component: UserDetailComponent }, { path: 'users/:id/posts/:postId', component: PostDetailComponent } ];

// Component @Component({...}) export class UserDetailComponent { userId!: string;

constructor(private route: ActivatedRoute) { this.route.params.subscribe(params => { this.userId = params['id']; }); } }

// Or with snapshot ngOnInit() { const id = this.route.snapshot.params['id']; }

Lazy Loading

Feature Modules with Lazy Loading

// app-routing.module.ts const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'users', loadChildren: () => import('./users/users.module').then(m => m.UsersModule) }, { path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) } ];

// users/users-routing.module.ts const routes: Routes = [ { path: '', component: UserListComponent }, { path: ':id', component: UserDetailComponent } ];

@NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class UsersRoutingModule { }

Lazy Loading with Standalone Components

const routes: Routes = [ { path: 'admin', loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES) } ];

// admin/admin.routes.ts export const ADMIN_ROUTES: Routes = [ { path: '', component: AdminDashboardComponent }, { path: 'users', component: AdminUsersComponent } ];

Route Guards

CanActivate Guard

import { Injectable } from '@angular/core'; import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; import { map } from 'rxjs/operators';

@Injectable() export class AuthGuard implements CanActivate { constructor( private authService: AuthService, private router: Router ) {}

canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> { return this.authService.isAuthenticated$.pipe( map(isAuth => { if (isAuth) return true; this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } }); return false; }) ); } }

// Usage const routes: Routes = [ { path: 'admin', component: AdminComponent, canActivate: [AuthGuard] } ];

CanDeactivate Guard

export interface CanComponentDeactivate { canDeactivate: () => Observable<boolean> | boolean; }

@Injectable() export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> { canDeactivate(component: CanComponentDeactivate): Observable<boolean> | boolean { return component.canDeactivate(); } }

// Component @Component({...}) export class FormComponent implements CanComponentDeactivate { form!: FormGroup;

canDeactivate(): Observable<boolean> | boolean { return !this.form.dirty || confirm('Discard changes?'); } }

// Usage { path: 'form', component: FormComponent, canDeactivate: [CanDeactivateGuard] }

Resolve Guard

@Injectable() export class UserResolver implements Resolve<User> { constructor(private userService: UserService) {}

resolve(route: ActivatedRouteSnapshot): Observable<User> { return this.userService.getUser(route.params['id']); } }

// Usage { path: 'users/:id', component: UserDetailComponent, resolve: { user: UserResolver } }

// Component receives data @Component({...}) export class UserDetailComponent { user!: User;

constructor(private route: ActivatedRoute) { this.route.data.subscribe(data => { this.user = data['user']; }); } }

Query Parameters

// Navigation this.router.navigate(['/users'], { queryParams: { page: 1, sort: 'name', filter: 'active' } });

// Reading this.route.queryParams.subscribe(params => { const page = params['page']; const sort = params['sort']; });

// Template <a [routerLink]="['/users']" [queryParams]="{ page: 2, sort: 'name' }"> Next Page </a>

Fragment (Hash)

// Navigation this.router.navigate(['/docs'], { fragment: 'section1' });

// Reading this.route.fragment.subscribe(fragment => { console.log('Fragment:', fragment); });

// Template <a routerLink="/docs" fragment="section1">Section 1</a>

Preloading Strategies

// Default: no preloading RouterModule.forRoot(routes);

// Preload all lazy modules RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules });

// Custom preloading strategy @Injectable() export class SelectivePreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: () => Observable<any>): Observable<any> { if (route.data && route.data['preload']) { return load(); } return of(null); } }

// Usage const routes: Routes = [ { path: 'users', loadChildren: '...', data: { preload: true } } ];

RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })

Route Reuse Strategy

@Injectable() export class CustomRouteReuseStrategy implements RouteReuseStrategy { storedRoutes: { [key: string]: RouteData } = {};

shouldDetach(route: ActivatedRouteSnapshot): boolean { return route.data['cache'] === true; }

store(route: ActivatedRouteSnapshot, detachedTree: DetachedRouteHandle): void { this.storedRoutes[route.url.join('/')] = { route, handle: detachedTree }; }

shouldAttach(route: ActivatedRouteSnapshot): boolean { return !!this.storedRoutes[route.url.join('/')]; }

retrieve(route: ActivatedRouteSnapshot): DetachedRouteHandle | null { return this.storedRoutes[route.url.join('/')]?.handle || null; }

shouldReuseRoute(future: ActivatedRouteSnapshot, current: ActivatedRouteSnapshot): boolean { return future.routeConfig === current.routeConfig; } }

Performance Optimization

Code Splitting

// Only load admin module when needed { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) }

Change Detection with Routes

@Component({ selector: 'app-root', template: &#x3C;router-outlet>&#x3C;/router-outlet>, changeDetection: ChangeDetectionStrategy.OnPush }) export class AppComponent { }

Scroll Position

// Scroll to top on route change RouterModule.forRoot(routes, { scrollPositionRestoration: 'top' })

// Or custom scroll export class ScrollToTopComponent implements OnInit { constructor(private router: Router) {}

ngOnInit() { this.router.events.pipe( filter(event => event instanceof NavigationEnd) ).subscribe(() => { window.scrollTo(0, 0); }); } }

Advanced Patterns

Auxiliary Routes

// URL: /users/1(admin:admin-panel) <router-outlet></router-outlet> <router-outlet name="admin"></router-outlet>

// Navigation this.router.navigate([ { outlets: { primary: ['users', userId], admin: ['admin-panel'] }} ]);

Child Routes with Components

const routes: Routes = [ { path: 'dashboard', component: DashboardComponent, children: [ { path: 'stats', component: StatsComponent }, { path: 'reports', component: ReportsComponent } ] } ];

// DashboardComponent template <nav> <a routerLink="stats" routerLinkActive="active">Stats</a> <a routerLink="reports" routerLinkActive="active">Reports</a> </nav> <router-outlet></router-outlet>

Testing Routes

describe('Routing', () => { let router: Router; let location: Location; let fixture: ComponentFixture<AppComponent>;

beforeEach(async () => { await TestBed.configureTestingModule({ imports: [AppRoutingModule, AppComponent] }).compileComponents();

router = TestBed.inject(Router);
location = TestBed.inject(Location);
fixture = TestBed.createComponent(AppComponent);

});

it('should navigate to home', fakeAsync(() => { router.navigate(['']); tick(); expect(location.path()).toBe('/'); })); });

Best Practices

  • Lazy load features: Reduce initial bundle size

  • Use route guards: Control access and preload data

  • Implement RouteReuseStrategy: Cache components when needed

  • Handle 404s: Provide meaningful error pages

  • Query params for filters: Keep state in URL

  • Preload strategically: Balance performance vs initial load

  • Use fragments for anchors: Scroll to page sections

Resources

  • Angular Routing Guide

  • Route Guards

  • Lazy Loading

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Automation

angular-material

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

rxjs-implementation

No summary provided by upstream source.

Repository SourceNeeds Review
Automation

state-implementation

No summary provided by upstream source.

Repository SourceNeeds Review