angular-best-practices
🤖 AI Summary
Analyzes Angular code to enforce performance best practices, including change detection optimization, lazy loading, bundle size reduction, and efficient rendering patterns during development, review, or refactoring.
How to Install
Claude Code:
git clone --depth 1 https://github.com/self.git && cp skills/angular-best-practices ~/.claude/skills/angular-best-practices -rAngular Best Practices
Comprehensive performance optimization guide for Angular applications. Contains prioritized rules for eliminating performance bottlenecks, optimizing bundles, and improving rendering.
When to Use
Reference these guidelines when:
- Writing new Angular components or pages
- Implementing data fetching patterns
- Reviewing code for performance issues
- Refactoring existing Angular code
- Optimizing bundle size or load times
- Configuring SSR/hydration
Rule Categories by Priority
| Priority | Category | Impact | Focus |
|---|---|---|---|
| 1 | Change Detection | CRITICAL | Signals, OnPush, Zoneless |
| 2 | Async Waterfalls | CRITICAL | RxJS patterns, SSR preloading |
| 3 | Bundle Optimization | CRITICAL | Lazy loading, tree shaking |
| 4 | Rendering Performance | HIGH | @defer, trackBy, virtualization |
| 5 | Server-Side Rendering | HIGH | Hydration, prerendering |
| 6 | Template Optimization | MEDIUM | Control flow, pipes |
| 7 | State Management | MEDIUM | Signal patterns, selectors |
| 8 | Memory Management | LOW-MEDIUM | Cleanup, subscriptions |
1. Change Detection (CRITICAL)
Use OnPush Change Detection
// CORRECT - OnPush with Signals
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ count() }}</div>`,
})
export class CounterComponent {
count = signal(0);
}
// WRONG - Default change detection
@Component({
template: `<div>{{ count }}</div>`, // Checked every cycle
})
export class CounterComponent {
count = 0;
}
Prefer Signals Over Mutable Properties
// CORRECT - Signals trigger precise updates
@Component({
template: `
<h1>{{ title() }}</h1>
<p>Count: {{ count() }}</p>
`,
})
export class DashboardComponent {
title = signal("Dashboard");
count = signal(0);
}
// WRONG - Mutable properties require zone.js checks
@Component({
template: `
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
`,
})
export class DashboardComponent {
title = "Dashboard";
count = 0;
}
Enable Zoneless for New Projects
// main.ts - Zoneless Angular (v20+)
bootstrapApplication(AppComponent, {
providers: [provideZonelessChangeDetection()],
});
Benefits:
- No zone.js patches on async APIs
- Smaller bundle (~15KB savings)
- Clean stack traces for debugging
- Better micro-frontend compatibility
2. Async Operations & Waterfalls (CRITICAL)
Eliminate Sequential Data Fetching
// WRONG - Nested subscriptions create waterfalls
this.route.params.subscribe((params) => {
// 1. Wait for params
this.userService.getUser(params.id).subscribe((user) => {
// 2. Wait for user
this.postsService.getPosts(user.id).subscribe((posts) => {
// 3. Wait for posts
});
});
});
// CORRECT - Parallel execution with forkJoin
forkJoin({
user: this.userService.getUser(id),
posts: this.postsService.getPosts(id),
}).subscribe((data) => {
// Fetched in parallel
});
// CORRECT - Flatten dependent calls with switchMap
this.route.params
.pipe(
map((p) => p.id),
switchMap((id) => this.userService.getUser(id)),
)
.subscribe();
Avoid Client-Side Waterfalls in SSR
// CORRECT - Use resolvers or blocking hydration for critical data
export const route: Route = {
path: "profile/:id",
resolve: { data: profileResolver }, // Fetched on server before navigation
component: ProfileComponent,
};
// WRONG - Component fetches data on init
class ProfileComponent implements OnInit {
ngOnInit() {
// Starts ONLY after JS loads and component renders
this.http.get("/api/profile").subscribe();
}
}
3. Bundle Optimization (CRITICAL)
Lazy Load Routes
// CORRECT - Lazy load feature routes
export const routes: Routes = [
{
path: "admin",
loadChildren: () =>
import("./admin/admin.routes").then((m) => m.ADMIN_ROUTES),
},
{
path: "dashboard",
loadComponent: () =>
import("./dashboard/dashboard.component").then(
(m) => m.DashboardComponent,
),
},
];
// WRONG - Eager loading everything
import { AdminModule } from "./admin/admin.module";
export const routes: Routes = [
{ path: "admin", component: AdminComponent }, // In main bundle
];
Use @defer for Heavy Components
<!-- CORRECT - Heavy component loads on demand -->
@defer (on viewport) {
<app-analytics-chart [data]="data()" />
} @placeholder {
<div class="chart-skeleton"></div>
}
<!-- WRONG - Heavy component in initial bundle -->
<app-analytics-chart [data]="data()" />
Avoid Barrel File Re-exports
```typescript // WRONG - Imports entire barrel, breaks tree-shaking import { Button, Mod
Details
| Category | Coding → generation |
| Source | self |
| SKILL.md | View on GitHub → |
| Repo Stars | N/A |
| Est. per Skill | N/A (shared across 53 skills from this repo) |
| Difficulty | Advanced |
| Risk Level | Safe |
Related Skills
pubmed-database
PubMed Database Overview PubMed is the U.S. National Library of Medicine's comprehensive database pr
angular-ui-patterns
Angular UI Patterns Core Principles Never show stale UI - Loading states only when actually loading
cc-skill-continuous-learning
cc-skill-continuous-learning Development skill skill. When to Use This skill is applicable to execut
git-hooks-automation
Git Hooks Automation Automate code quality enforcement at the Git level. Set up hooks that lint, for
Works Well With
Skills from the same repository — often designed to work together
angular
Angular Expert Master modern Angular development with Signals, Standalone Components, Zoneless appli
angular-state-management
Angular State Management Comprehensive guide to modern Angular state management patterns, from Signa
angular-ui-patterns
Angular UI Patterns Core Principles Never show stale UI - Loading states only when actually loading