SOC 직업 분류 기준
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/Objective-Arts/lens-dist --skill angular-perf명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SKILL.md 표시 중
| name | angular-perf |
| description | Angular performance and optimization patterns |
| allowed-tools | [] |
Minko Gechev's core belief: Performance is a feature, not an afterthought. Every millisecond of load time and every kilobyte of bundle size affects user experience.
"The fastest code is code that doesn't run. The smallest bundle is the one you don't ship."
Performance optimization in Angular is about:
Every feature module should be lazy loaded unless proven otherwise.
Not this:
// app.module.ts - everything loaded upfront
@NgModule({
imports: [
UsersModule,
AdminModule,
ReportsModule,
SettingsModule // User may never visit settings
]
})
class AppModule {}
This:
// app-routing.module.ts - load on demand
const routes: Routes = [
{ path: 'users', loadChildren: () => import('./users/users.module').then(m => m.UsersModule) },
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) },
{ path: 'reports', loadChildren: () => import('./reports/reports.module').then(m => m.ReportsModule) },
{ path: 'settings', loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule) }
];
With standalone components (Angular 14+):
const routes: Routes = [
{
path: 'dashboard',
loadComponent: () => import('./dashboard.component').then(c => c.DashboardComponent)
}
];
Default change detection checks every component on every event. OnPush checks only when inputs change.
Not this:
@Component({
// Default change detection - checks on every click anywhere
})
class ExpensiveListComponent {
@Input() items: Item[];
}
This:
@Component({
changeDetection: ChangeDetectionStrategy.OnPush // Only checks when items reference changes
})
class ExpensiveListComponent {
@Input() items: Item[];
}
Rules for OnPush:
@Input() must be immutable (new reference on change)async pipe for observables (triggers change detection correctly)ChangeDetectorRef.markForCheck() only when truly neededWithout trackBy, Angular destroys and recreates DOM for every change.
Not this:
<li *ngFor="let user of users">{{ user.name }}</li>
<!-- Entire list re-rendered when any user changes -->
This:
<li *ngFor="let user of users; trackBy: trackByUserId">{{ user.name }}</li>
<!-- Only changed items re-rendered -->
trackByUserId(index: number, user: User): string {
return user.id;
}
Manual subscriptions leak memory. Async pipe handles cleanup.
Not this:
class UserComponent implements OnInit, OnDestroy {
user: User;
private subscription: Subscription;
ngOnInit() {
this.subscription = this.userService.getUser().subscribe(u => this.user = u);
}
ngOnDestroy() {
this.subscription.unsubscribe(); // Easy to forget
}
}
This:
class UserComponent {
user$ = this.userService.getUser();
constructor(private userService: UserService) {}
}
<div *ngIf="user$ | async as user">{{ user.name }}</div>
Set budgets, enforce them, analyze violations.
angular.json:
{
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
]
}
Analyze bundles:
ng build --stats-json
npx webpack-bundle-analyzer dist/stats.json
Don't just lazy load—preload intelligently.
// Preload all modules after initial load
@NgModule({
imports: [RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
})]
})
// Or custom strategy - preload based on user behavior
@Injectable()
class CustomPreloadingStrategy implements PreloadingStrategy {
preload(route: Route, load: () => Observable<any>): Observable<any> {
return route.data?.['preload'] ? load() : of(null);
}
}
Never render thousands of DOM nodes. Use virtual scrolling.
import { ScrollingModule } from '@angular/cdk/scrolling';
@Component({
template: `
<cdk-virtual-scroll-viewport itemSize="50" class="viewport">
<div *cdkVirtualFor="let item of items" class="item">
{{ item.name }}
</div>
</cdk-virtual-scroll-viewport>
`
})
class LargeListComponent {
items = Array.from({ length: 10000 }, (_, i) => ({ name: `Item ${i}` }));
}
Offload CPU-intensive work to avoid blocking the main thread.
// app.worker.ts
addEventListener('message', ({ data }) => {
const result = heavyComputation(data);
postMessage(result);
});
// component.ts
if (typeof Worker !== 'undefined') {
const worker = new Worker(new URL('./app.worker', import.meta.url));
worker.onmessage = ({ data }) => {
this.result = data;
};
worker.postMessage(this.inputData);
}
Angular's built-in image optimization directive.
import { NgOptimizedImage } from '@angular/common';
@Component({
imports: [NgOptimizedImage],
template: `
<img ngSrc="hero.jpg" width="800" height="600" priority>
<img ngSrc="thumbnail.jpg" width="200" height="150" loading="lazy">
`
})
Benefits:
priorityDeclarative lazy loading in templates.
@defer (on viewport) {
<heavy-component />
} @placeholder {
<lightweight-skeleton />
} @loading (minimum 500ms) {
<spinner />
}
Trigger options:
on viewport - when enters viewporton idle - when browser is idleon interaction - on click/focuson hover - on mouse hoveron timer(500ms) - after delayBefore shipping, ask:
Apply these checks:
ChangeDetectionStrategy.OnPush on componentstrackBy on all *ngForasync pipe instead of manual subscriptionsNgOptimizedImage// Enable Angular DevTools profiler
// In browser: Angular DevTools extension
// Measure change detection
import { enableDebugTools } from '@angular/platform-browser';
enableDebugTools(appRef.components[0]);
// Then in console: ng.profiler.timeChangeDetection()
// Trace what triggers change detection
constructor(private ngZone: NgZone) {
ngZone.onStable.subscribe(() => console.log('CD cycle complete'));
}
Use a different skill when:
angular-core (DI, testability)design-patternsclaritytypescript (TypeScript)Minko Gechev is the Angular performance skill—use it for optimization, lazy loading, and runtime efficiency.
"Measure first. Optimize what matters. Ship less JavaScript." — Minko Gechev