Chargement Différé
Lazy Load Components (Standalone)
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
loadComponent: () => import('./home/home.component')
.then(m => m.HomeComponent)
},
{
path: 'about',
loadComponent: () => import('./about/about.component')
.then(m => m.AboutComponent)
},
{
path: 'users/:id',
loadComponent: () => import('./user-detail/user-detail.component')
.then(m => m.UserDetailComponent)
}
];
Lazy Load Routes
// Main routes
export const routes: Routes = [
{ path: '', component: HomeComponent },
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
},
{
path: 'shop',
loadChildren: () => import('./shop/shop.routes')
.then(m => m.SHOP_ROUTES)
}
];
// admin/admin.routes.ts
import { Routes } from '@angular/router';
export const ADMIN_ROUTES: Routes = [
{
path: '',
loadComponent: () => import('./admin-dashboard.component')
.then(m => m.AdminDashboardComponent)
},
{
path: 'users',
loadComponent: () => import('./admin-users.component')
.then(m => m.AdminUsersComponent)
}
];
Stratégies de Préchargement
Pas de Préchargement (Par défaut)
import { provideRouter } from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes) // No preloading
]
});
PreloadAllModules
import { provideRouter, withPreloading, PreloadAllModules } from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
routes,
withPreloading(PreloadAllModules) // Preload all lazy routes
)
]
});
Stratégie de Préchargement Personnalisée
import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of, timer } from 'rxjs';
import { mergeMap } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class CustomPreloadStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
// Preload if route has data.preload = true
if (route.data?.['preload']) {
console.log('Preloading:', route.path);
return load();
}
return of(null);
}
}
// Usage
export const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes'),
data: { preload: true } // Will preload
},
{
path: 'shop',
loadChildren: () => import('./shop/shop.routes')
// Won't preload
}
];
bootstrapApplication(AppComponent, {
providers: [
provideRouter(
routes,
withPreloading(CustomPreloadStrategy)
)
]
});
Chargement Différé avec Guards
export const routes: Routes = [
{
path: 'admin',
canActivate: [authGuard],
loadChildren: () => import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
];
Analyse des Bundles
# Build and analyze bundles
ng build --stats-json
npx webpack-bundle-analyzer dist/your-app/stats.json
Chunks Nommés
// Webpack will create named chunks
{
path: 'admin',
loadChildren: () => import(
/* webpackChunkName: "admin" */
'./admin/admin.routes'
).then(m => m.ADMIN_ROUTES)
}
Chargement Différé des Services
// Service only loaded with lazy route
@Injectable()
export class AdminService {
// ...
}
// Fournir dans la route lazy
export const ADMIN_ROUTES: Routes = [
{
path: '',
component: AdminComponent,
providers: [AdminService] // Only loaded with this route
}
];
Tests Chargement Différé
describe('Lazy Loading', () => {
it('should lazy load admin module', async () => {
const router = TestBed.inject(Router);
const fixture = TestBed.createComponent(AppComponent);
await router.navigate(['/admin']);
fixture.detectChanges();
const compiled = fixture.nativeElement;
expect(compiled.querySelector('app-admin')).toBeTruthy();
});
});
Bonnes Pratiques
- Charger en différé les routes de fonctionnalités (pas les fonctionnalités principales)
- Utiliser
PreloadAllModulespour une meilleure UX sur les connexions rapides - Créer des stratégies personnalisées pour le préchargement conditionnel
- Charger en différé les routes admin/dashboard
- Garder les fonctionnalités principales chargées immédiatement
- Utiliser l'analyse des bundles pour optimiser
- Précharger en fonction du comportement utilisateur ou de la priorité des routes
- Regrouper les composants liés dans des modules de routes
- Tester les routes lazy pour s'assurer qu'elles fonctionnent
Conseils de Performance
// ✅ Good: Separate features
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes')
}
// ❌ Bad: Too granular
{
path: 'user',
loadComponent: () => import('./user.component') // Too small
}
// ✅ Good: Group related components
{
path: 'dashboard',
loadChildren: () => import('./dashboard/dashboard.routes')
// dashboard.routes contains multiple related components
}
Surveiller les Performances de Chargement
@Injectable({ providedIn: 'root' })
export class LoadTimePreloadStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
if (route.data?.['preload']) {
const start = performance.now();
return load().pipe(
tap(() => {
const end = performance.now();
console.log(`Loaded ${route.path} in ${end - start}ms`);
})
);
}
return of(null);
}
}