feat(skills): enhance Angular skills with Composition and Async Waterfalls
- Add Component Composition & Reusability section to angular/SKILL.md - Content Projection with ng-content and select - Host Directives for behavior composition - Add Async Operations & Waterfalls section to angular-best-practices/SKILL.md - Parallel execution with forkJoin - Flattening with switchMap - SSR waterfall prevention with resolvers
This commit is contained in:
@@ -25,12 +25,13 @@ Reference these guidelines when:
|
|||||||
| Priority | Category | Impact | Focus |
|
| Priority | Category | Impact | Focus |
|
||||||
| -------- | --------------------- | ---------- | ------------------------------- |
|
| -------- | --------------------- | ---------- | ------------------------------- |
|
||||||
| 1 | Change Detection | CRITICAL | Signals, OnPush, Zoneless |
|
| 1 | Change Detection | CRITICAL | Signals, OnPush, Zoneless |
|
||||||
| 2 | Bundle Optimization | CRITICAL | Lazy loading, tree shaking |
|
| 2 | Async Waterfalls | CRITICAL | RxJS patterns, SSR preloading |
|
||||||
| 3 | Rendering Performance | HIGH | @defer, trackBy, virtualization |
|
| 3 | Bundle Optimization | CRITICAL | Lazy loading, tree shaking |
|
||||||
| 4 | Server-Side Rendering | HIGH | Hydration, prerendering |
|
| 4 | Rendering Performance | HIGH | @defer, trackBy, virtualization |
|
||||||
| 5 | Template Optimization | MEDIUM | Control flow, pipes |
|
| 5 | Server-Side Rendering | HIGH | Hydration, prerendering |
|
||||||
| 6 | State Management | MEDIUM | Signal patterns, selectors |
|
| 6 | Template Optimization | MEDIUM | Control flow, pipes |
|
||||||
| 7 | Memory Management | LOW-MEDIUM | Cleanup, subscriptions |
|
| 7 | State Management | MEDIUM | Signal patterns, selectors |
|
||||||
|
| 8 | Memory Management | LOW-MEDIUM | Cleanup, subscriptions |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -103,7 +104,63 @@ bootstrapApplication(AppComponent, {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Bundle Optimization (CRITICAL)
|
---
|
||||||
|
|
||||||
|
## 2. Async Operations & Waterfalls (CRITICAL)
|
||||||
|
|
||||||
|
### Eliminate Sequential Data Fetching
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 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
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 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
|
### Lazy Load Routes
|
||||||
|
|
||||||
@@ -171,7 +228,7 @@ import { Chart } from 'chart.js';
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Rendering Performance (HIGH)
|
## 4. Rendering Performance (HIGH)
|
||||||
|
|
||||||
### Always Use trackBy with @for
|
### Always Use trackBy with @for
|
||||||
|
|
||||||
@@ -248,7 +305,7 @@ get filteredProducts() {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Server-Side Rendering (HIGH)
|
## 5. Server-Side Rendering (HIGH)
|
||||||
|
|
||||||
### Configure Incremental Hydration
|
### Configure Incremental Hydration
|
||||||
|
|
||||||
@@ -314,7 +371,7 @@ export class DataService {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Template Optimization (MEDIUM)
|
## 6. Template Optimization (MEDIUM)
|
||||||
|
|
||||||
### Use New Control Flow Syntax
|
### Use New Control Flow Syntax
|
||||||
|
|
||||||
@@ -355,7 +412,7 @@ class Component {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. State Management (MEDIUM)
|
## 7. State Management (MEDIUM)
|
||||||
|
|
||||||
### Use Selectors to Prevent Re-renders
|
### Use Selectors to Prevent Re-renders
|
||||||
|
|
||||||
@@ -404,7 +461,7 @@ export class GlobalStore {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Memory Management (LOW-MEDIUM)
|
## 8. Memory Management (LOW-MEDIUM)
|
||||||
|
|
||||||
### Use takeUntilDestroyed for Subscriptions
|
### Use takeUntilDestroyed for Subscriptions
|
||||||
|
|
||||||
|
|||||||
@@ -436,7 +436,65 @@ export class ApiService {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. State Management Patterns
|
---
|
||||||
|
|
||||||
|
## 7. Component Composition & Reusability
|
||||||
|
|
||||||
|
### Content Projection (Slots)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
@Component({
|
||||||
|
selector: 'app-card',
|
||||||
|
template: `
|
||||||
|
<div class="card">
|
||||||
|
<div class="header">
|
||||||
|
<!-- Select by attribute -->
|
||||||
|
<ng-content select="[card-header]"></ng-content>
|
||||||
|
</div>
|
||||||
|
<div class="body">
|
||||||
|
<!-- Default slot -->
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class CardComponent {}
|
||||||
|
|
||||||
|
// Usage
|
||||||
|
<app-card>
|
||||||
|
<h3 card-header>Title</h3>
|
||||||
|
<p>Body content</p>
|
||||||
|
</app-card>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Host Directives (Composition)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Reusable behaviors without inheritance
|
||||||
|
@Directive({
|
||||||
|
standalone: true,
|
||||||
|
selector: '[appTooltip]',
|
||||||
|
inputs: ['tooltip'] // Signal input alias
|
||||||
|
})
|
||||||
|
export class TooltipDirective { ... }
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-button',
|
||||||
|
standalone: true,
|
||||||
|
hostDirectives: [
|
||||||
|
{
|
||||||
|
directive: TooltipDirective,
|
||||||
|
inputs: ['tooltip: title'] // Map input
|
||||||
|
}
|
||||||
|
],
|
||||||
|
template: `<ng-content />`
|
||||||
|
})
|
||||||
|
export class ButtonComponent {}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. State Management Patterns
|
||||||
|
|
||||||
### Signal-Based State Service
|
### Signal-Based State Service
|
||||||
|
|
||||||
@@ -525,7 +583,7 @@ export class ProductStore {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Forms with Signals (Coming in v22+)
|
## 9. Forms with Signals (Coming in v22+)
|
||||||
|
|
||||||
### Current Reactive Forms
|
### Current Reactive Forms
|
||||||
|
|
||||||
@@ -588,7 +646,7 @@ export class SignalFormComponent {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Performance Optimization
|
## 10. Performance Optimization
|
||||||
|
|
||||||
### Change Detection Strategies
|
### Change Detection Strategies
|
||||||
|
|
||||||
@@ -653,7 +711,7 @@ import { NgOptimizedImage } from '@angular/common';
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Testing Modern Angular
|
## 11. Testing Modern Angular
|
||||||
|
|
||||||
### Testing Signal Components
|
### Testing Signal Components
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user