{"id":"bdcd9d51-e950-4953-a4aa-5c1e9b12b286","shortId":"FkY8qQ","kind":"skill","title":"angular-best-practices","tagline":"Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency.","description":"# Angular Best Practices\n\nComprehensive performance optimization guide for Angular applications. Contains prioritized rules for eliminating performance bottlenecks, optimizing bundles, and improving rendering.\n\n## When to Use\nReference these guidelines when:\n\n- Writing new Angular components or pages\n- Implementing data fetching patterns\n- Reviewing code for performance issues\n- Refactoring existing Angular code\n- Optimizing bundle size or load times\n- Configuring SSR/hydration\n\n---\n\n## Rule Categories by Priority\n\n| Priority | Category              | Impact     | Focus                           |\n| -------- | --------------------- | ---------- | ------------------------------- |\n| 1        | Change Detection      | CRITICAL   | Signals, OnPush, Zoneless       |\n| 2        | Async Waterfalls      | CRITICAL   | RxJS patterns, SSR preloading   |\n| 3        | Bundle Optimization   | CRITICAL   | Lazy loading, tree shaking      |\n| 4        | Rendering Performance | HIGH       | @defer, trackBy, virtualization |\n| 5        | Server-Side Rendering | HIGH       | Hydration, prerendering         |\n| 6        | Template Optimization | MEDIUM     | Control flow, pipes             |\n| 7        | State Management      | MEDIUM     | Signal patterns, selectors      |\n| 8        | Memory Management     | LOW-MEDIUM | Cleanup, subscriptions          |\n\n---\n\n## 1. Change Detection (CRITICAL)\n\n### Use OnPush Change Detection\n\n```typescript\n// CORRECT - OnPush with Signals\n@Component({\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  template: `<div>{{ count() }}</div>`,\n})\nexport class CounterComponent {\n  count = signal(0);\n}\n\n// WRONG - Default change detection\n@Component({\n  template: `<div>{{ count }}</div>`, // Checked every cycle\n})\nexport class CounterComponent {\n  count = 0;\n}\n```\n\n### Prefer Signals Over Mutable Properties\n\n```typescript\n// CORRECT - Signals trigger precise updates\n@Component({\n  template: `\n    <h1>{{ title() }}</h1>\n    <p>Count: {{ count() }}</p>\n  `,\n})\nexport class DashboardComponent {\n  title = signal(\"Dashboard\");\n  count = signal(0);\n}\n\n// WRONG - Mutable properties require zone.js checks\n@Component({\n  template: `\n    <h1>{{ title }}</h1>\n    <p>Count: {{ count }}</p>\n  `,\n})\nexport class DashboardComponent {\n  title = \"Dashboard\";\n  count = 0;\n}\n```\n\n### Enable Zoneless for New Projects\n\n```typescript\n// main.ts - Zoneless Angular (v20+)\nbootstrapApplication(AppComponent, {\n  providers: [provideZonelessChangeDetection()],\n});\n```\n\n**Benefits:**\n\n- No zone.js patches on async APIs\n- Smaller bundle (~15KB savings)\n- Clean stack traces for debugging\n- Better micro-frontend compatibility\n\n---\n\n## 2. Async Operations & Waterfalls (CRITICAL)\n\n### Eliminate Sequential Data Fetching\n\n```typescript\n// WRONG - Nested subscriptions create waterfalls\nthis.route.params.subscribe((params) => {\n  // 1. Wait for params\n  this.userService.getUser(params.id).subscribe((user) => {\n    // 2. Wait for user\n    this.postsService.getPosts(user.id).subscribe((posts) => {\n      // 3. Wait for posts\n    });\n  });\n});\n\n// CORRECT - Parallel execution with forkJoin\nforkJoin({\n  user: this.userService.getUser(id),\n  posts: this.postsService.getPosts(id),\n}).subscribe((data) => {\n  // Fetched in parallel\n});\n\n// CORRECT - Flatten dependent calls with switchMap\nthis.route.params\n  .pipe(\n    map((p) => p.id),\n    switchMap((id) => this.userService.getUser(id)),\n  )\n  .subscribe();\n```\n\n### Avoid Client-Side Waterfalls in SSR\n\n```typescript\n// CORRECT - Use resolvers or blocking hydration for critical data\nexport const route: Route = {\n  path: \"profile/:id\",\n  resolve: { data: profileResolver }, // Fetched on server before navigation\n  component: ProfileComponent,\n};\n\n// WRONG - Component fetches data on init\nclass ProfileComponent implements OnInit {\n  ngOnInit() {\n    // Starts ONLY after JS loads and component renders\n    this.http.get(\"/api/profile\").subscribe();\n  }\n}\n```\n\n---\n\n## 3. Bundle Optimization (CRITICAL)\n\n### Lazy Load Routes\n\n```typescript\n// CORRECT - Lazy load feature routes\nexport const routes: Routes = [\n  {\n    path: \"admin\",\n    loadChildren: () =>\n      import(\"./admin/admin.routes\").then((m) => m.ADMIN_ROUTES),\n  },\n  {\n    path: \"dashboard\",\n    loadComponent: () =>\n      import(\"./dashboard/dashboard.component\").then(\n        (m) => m.DashboardComponent,\n      ),\n  },\n];\n\n// WRONG - Eager loading everything\nimport { AdminModule } from \"./admin/admin.module\";\nexport const routes: Routes = [\n  { path: \"admin\", component: AdminComponent }, // In main bundle\n];\n```\n\n### Use @defer for Heavy Components\n\n```html\n<!-- CORRECT - Heavy component loads on demand -->\n@defer (on viewport) {\n<app-analytics-chart [data]=\"data()\" />\n} @placeholder {\n<div class=\"chart-skeleton\"></div>\n}\n\n<!-- WRONG - Heavy component in initial bundle -->\n<app-analytics-chart [data]=\"data()\" />\n```\n\n### Avoid Barrel File Re-exports\n\n```typescript\n// WRONG - Imports entire barrel, breaks tree-shaking\nimport { Button, Modal, Table } from \"@shared/components\";\n\n// CORRECT - Direct imports\nimport { Button } from \"@shared/components/button/button.component\";\nimport { Modal } from \"@shared/components/modal/modal.component\";\n```\n\n### Dynamic Import Third-Party Libraries\n\n```typescript\n// CORRECT - Load heavy library on demand\nasync loadChart() {\n  const { Chart } = await import('chart.js');\n  this.chart = new Chart(this.canvas, config);\n}\n\n// WRONG - Bundle Chart.js in main chunk\nimport { Chart } from 'chart.js';\n```\n\n---\n\n## 4. Rendering Performance (HIGH)\n\n### Always Use trackBy with @for\n\n```html\n<!-- CORRECT - Efficient DOM updates -->\n@for (item of items(); track item.id) {\n<app-item-card [item]=\"item\" />\n}\n\n<!-- WRONG - Entire list re-renders on any change -->\n@for (item of items(); track $index) {\n<app-item-card [item]=\"item\" />\n}\n```\n\n### Use Virtual Scrolling for Large Lists\n\n```typescript\nimport { CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll } from '@angular/cdk/scrolling';\n\n@Component({\n  imports: [CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll],\n  template: `\n    <cdk-virtual-scroll-viewport itemSize=\"50\" class=\"viewport\">\n      <div *cdkVirtualFor=\"let item of items\" class=\"item\">\n        {{ item.name }}\n      </div>\n    </cdk-virtual-scroll-viewport>\n  `\n})\n```\n\n### Prefer Pure Pipes Over Methods\n\n```typescript\n// CORRECT - Pure pipe, memoized\n@Pipe({ name: 'filterActive', standalone: true, pure: true })\nexport class FilterActivePipe implements PipeTransform {\n  transform(items: Item[]): Item[] {\n    return items.filter(i => i.active);\n  }\n}\n\n// Template\n@for (item of items() | filterActive; track item.id) { ... }\n\n// WRONG - Method called every change detection\n@for (item of getActiveItems(); track item.id) { ... }\n```\n\n### Use computed() for Derived Data\n\n```typescript\n// CORRECT - Computed, cached until dependencies change\nexport class ProductStore {\n  products = signal<Product[]>([]);\n  filter = signal('');\n\n  filteredProducts = computed(() => {\n    const f = this.filter().toLowerCase();\n    return this.products().filter(p =>\n      p.name.toLowerCase().includes(f)\n    );\n  });\n}\n\n// WRONG - Recalculates every access\nget filteredProducts() {\n  return this.products.filter(p =>\n    p.name.toLowerCase().includes(this.filter)\n  );\n}\n```\n\n---\n\n## 5. Server-Side Rendering (HIGH)\n\n### Configure Incremental Hydration\n\n```typescript\n// app.config.ts\nimport {\n  provideClientHydration,\n  withIncrementalHydration,\n} from \"@angular/platform-browser\";\n\nexport const appConfig: ApplicationConfig = {\n  providers: [\n    provideClientHydration(withIncrementalHydration(), withEventReplay()),\n  ],\n};\n```\n\n### Defer Non-Critical Content\n\n```html\n<!-- Critical above-the-fold content -->\n<app-header />\n<app-hero />\n\n<!-- Below-fold deferred with hydration triggers -->\n@defer (hydrate on viewport) {\n<app-product-grid />\n} @defer (hydrate on interaction) {\n<app-chat-widget />\n}\n```\n\n### Use TransferState for SSR Data\n\n```typescript\n@Injectable({ providedIn: \"root\" })\nexport class DataService {\n  private http = inject(HttpClient);\n  private transferState = inject(TransferState);\n  private platformId = inject(PLATFORM_ID);\n\n  getData(key: string): Observable<Data> {\n    const stateKey = makeStateKey<Data>(key);\n\n    if (isPlatformBrowser(this.platformId)) {\n      const cached = this.transferState.get(stateKey, null);\n      if (cached) {\n        this.transferState.remove(stateKey);\n        return of(cached);\n      }\n    }\n\n    return this.http.get<Data>(`/api/${key}`).pipe(\n      tap((data) => {\n        if (isPlatformServer(this.platformId)) {\n          this.transferState.set(stateKey, data);\n        }\n      }),\n    );\n  }\n}\n```\n\n---\n\n## 6. Template Optimization (MEDIUM)\n\n### Use New Control Flow Syntax\n\n```html\n<!-- CORRECT - New control flow (faster, smaller bundle) -->\n@if (user()) {\n<span>{{ user()!.name }}</span>\n} @else {\n<span>Guest</span>\n} @for (item of items(); track item.id) {\n<app-item [item]=\"item\" />\n} @empty {\n<p>No items</p>\n}\n\n<!-- WRONG - Legacy structural directives -->\n<span *ngIf=\"user; else guest\">{{ user.name }}</span>\n<ng-template #guest><span>Guest</span></ng-template>\n```\n\n### Avoid Complex Template Expressions\n\n```typescript\n// CORRECT - Precompute in component\nclass Component {\n  items = signal<Item[]>([]);\n  sortedItems = computed(() =>\n    [...this.items()].sort((a, b) => a.name.localeCompare(b.name))\n  );\n}\n\n// Template\n@for (item of sortedItems(); track item.id) { ... }\n\n// WRONG - Sorting in template every render\n@for (item of items() | sort:'name'; track item.id) { ... }\n```\n\n---\n\n## 7. State Management (MEDIUM)\n\n### Use Selectors to Prevent Re-renders\n\n```typescript\n// CORRECT - Selective subscription\n@Component({\n  template: `<span>{{ userName() }}</span>`,\n})\nclass HeaderComponent {\n  private store = inject(Store);\n  // Only re-renders when userName changes\n  userName = this.store.selectSignal(selectUserName);\n}\n\n// WRONG - Subscribing to entire state\n@Component({\n  template: `<span>{{ state().user.name }}</span>`,\n})\nclass HeaderComponent {\n  private store = inject(Store);\n  // Re-renders on ANY state change\n  state = toSignal(this.store);\n}\n```\n\n### Colocate State with Features\n\n```typescript\n// CORRECT - Feature-scoped store\n@Injectable() // NOT providedIn: 'root'\nexport class ProductStore { ... }\n\n@Component({\n  providers: [ProductStore], // Scoped to component tree\n})\nexport class ProductPageComponent {\n  store = inject(ProductStore);\n}\n\n// WRONG - Everything in global store\n@Injectable({ providedIn: 'root' })\nexport class GlobalStore {\n  // Contains ALL app state - hard to tree-shake\n}\n```\n\n---\n\n## 8. Memory Management (LOW-MEDIUM)\n\n### Use takeUntilDestroyed for Subscriptions\n\n```typescript\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\n@Component({...})\nexport class DataComponent {\n  private destroyRef = inject(DestroyRef);\n\n  constructor() {\n    this.data$.pipe(\n      takeUntilDestroyed(this.destroyRef)\n    ).subscribe(data => this.process(data));\n  }\n}\n\n// WRONG - Manual subscription management\nexport class DataComponent implements OnDestroy {\n  private subscription!: Subscription;\n\n  ngOnInit() {\n    this.subscription = this.data$.subscribe(...);\n  }\n\n  ngOnDestroy() {\n    this.subscription.unsubscribe(); // Easy to forget\n  }\n}\n```\n\n### Prefer Signals Over Subscriptions\n\n```typescript\n// CORRECT - No subscription needed\n@Component({\n  template: `<div>{{ data().name }}</div>`,\n})\nexport class Component {\n  data = toSignal(this.service.data$, { initialValue: null });\n}\n\n// WRONG - Manual subscription\n@Component({\n  template: `<div>{{ data?.name }}</div>`,\n})\nexport class Component implements OnInit, OnDestroy {\n  data: Data | null = null;\n  private sub!: Subscription;\n\n  ngOnInit() {\n    this.sub = this.service.data$.subscribe((d) => (this.data = d));\n  }\n\n  ngOnDestroy() {\n    this.sub.unsubscribe();\n  }\n}\n```\n\n---\n\n## Quick Reference Checklist\n\n### New Component\n\n- [ ] `changeDetection: ChangeDetectionStrategy.OnPush`\n- [ ] `standalone: true`\n- [ ] Signals for state (`signal()`, `input()`, `output()`)\n- [ ] `inject()` for dependencies\n- [ ] `@for` with `track` expression\n\n### Performance Review\n\n- [ ] No methods in templates (use pipes or computed)\n- [ ] Large lists virtualized\n- [ ] Heavy components deferred\n- [ ] Routes lazy-loaded\n- [ ] Third-party libs dynamically imported\n\n### SSR Check\n\n- [ ] Hydration configured\n- [ ] Critical content renders first\n- [ ] Non-critical content uses `@defer (hydrate on ...)`\n- [ ] TransferState for server-fetched data\n\n---\n\n## Resources\n\n- [Angular Performance Guide](https://angular.dev/best-practices/performance)\n- [Zoneless Angular](https://angular.dev/guide/experimental/zoneless)\n- [Angular SSR Guide](https://angular.dev/guide/ssr)\n- [Change Detection Deep Dive](https://angular.dev/guide/change-detection)\n\n## When to Use\nThis skill is applicable to execute the workflow or actions described in the overview.\n\n## Limitations\n- Use this skill only when the task clearly matches the scope described above.\n- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.\n- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.","tags":["angular","best","practices","antigravity","awesome","skills","sickn33","agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding"],"capabilities":["skill","source-sickn33","skill-angular-best-practices","topic-agent-skills","topic-agentic-skills","topic-ai-agent-skills","topic-ai-agents","topic-ai-coding","topic-ai-workflows","topic-antigravity","topic-antigravity-skills","topic-claude-code","topic-claude-code-skills","topic-codex-cli","topic-codex-skills"],"categories":["antigravity-awesome-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/sickn33/antigravity-awesome-skills/angular-best-practices","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add sickn33/antigravity-awesome-skills","source_repo":"https://github.com/sickn33/antigravity-awesome-skills","install_from":"skills.sh"}},"qualityScore":"0.700","qualityRationale":"deterministic score 0.70 from registry signals: · indexed on github topic:agent-skills · 34964 github stars · SKILL.md body (13,259 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-04-25T00:50:25.934Z","embedding":null,"createdAt":"2026-04-18T21:30:57.385Z","updatedAt":"2026-04-25T00:50:25.934Z","lastSeenAt":"2026-04-25T00:50:25.934Z","tsv":"'/admin/admin.module':436 '/admin/admin.routes':416 '/api':780 '/api/profile':393 '/best-practices/performance)':1159 '/dashboard/dashboard.component':425 '/guide/change-detection)':1177 '/guide/experimental/zoneless)':1164 '/guide/ssr)':1170 '0':175,190,215,233 '1':92,152,286 '15kb':257 '2':99,269,294 '3':107,302,395 '4':115,537 '5':122,692 '6':130,791 '7':137,871 '8':144,980 'a.name.localecompare':848 'access':683 'action':1190 'admin':413,442 'admincompon':444 'adminmodul':434 'alway':541 'analyt':459,466 'angular':2,5,18,28,36,59,74,242,1154,1161,1165 'angular-best-practic':1 'angular.dev':1158,1163,1169,1176 'angular.dev/best-practices/performance)':1157 'angular.dev/guide/change-detection)':1175 'angular.dev/guide/experimental/zoneless)':1162 'angular.dev/guide/ssr)':1168 'angular/cdk/scrolling':582 'angular/core/rxjs-interop':994 'angular/platform-browser':707 'api':254 'app':458,465,554,566,814,973 'app-analytics-chart':457,464 'app-item':813 'app-item-card':553,565 'app.config.ts':702 'appcompon':245 'appconfig':710 'applic':37,1184 'applicationconfig':711 'ask':1228 'async':100,253,270,515 'avoid':339,470,828 'await':519 'b':847 'b.name':849 'barrel':471,480 'benefit':248 'best':3,9,29 'better':264 'block':351 'bootstrapappl':244 'bottleneck':44 'boundari':1236 'break':481 'bundl':23,46,77,108,256,396,447,528 'button':486,495 'cach':655,767,772,777 'call':326,637 'card':556,568 'categori':85,89 'cdkfixedsizevirtualscrol':580,586 'cdkvirtualfor':589 'cdkvirtualscrollviewport':579,585 'chang':93,153,158,178,639,658,901,926,1171 'changedetect':166,1088 'changedetectionstrategy.onpush':167,1089 'chart':460,467,518,524,534 'chart.js':521,529,536 'check':183,221,1132 'checklist':1085 'chunk':532 'clarif':1230 'class':171,187,208,228,379,594,615,660,740,837,889,914,945,955,969,997,1017,1047,1062 'clean':259 'cleanup':150 'clear':1203 'client':341 'client-sid':340 'code':19,68,75 'coloc':930 'compat':268 'complex':829 'compon':60,165,180,202,222,371,374,390,443,452,583,836,838,886,910,947,952,995,1042,1048,1057,1063,1087,1119 'comprehens':31 'comput':648,654,668,843,1114 'config':526 'configur':82,698,1134 'const':357,409,438,517,669,709,759,766 'constructor':1003 'contain':38,971 'content':720,1136,1142 'control':134,797 'correct':161,197,306,323,347,403,491,509,603,653,833,883,935,1038 'count':169,173,182,189,205,206,213,225,226,232 'countercompon':172,188 'creat':282 'criteria':1239 'critic':95,102,110,155,273,354,398,719,1135,1141 'cycl':185 'd':1078,1080 'dashboard':212,231,422 'dashboardcompon':209,229 'data':64,276,319,355,364,376,461,462,468,469,651,734,784,790,1009,1011,1044,1049,1059,1067,1068,1152 'datacompon':998,1018 'dataservic':741 'debug':263 'deep':1173 'default':177 'defer':119,449,454,716,722,726,1120,1144 'demand':514 'depend':325,657,1100 'deriv':650 'describ':1191,1207 'destroyref':1000,1002 'detect':94,154,159,179,640,1172 'direct':492 'div':588 'dive':1174 'dynam':502,1129 'eager':430 'easi':1030 'effici':27 'elimin':42,274 'els':805,824 'empti':818 'enabl':234 'entir':479,908 'environ':1219 'environment-specif':1218 'everi':184,638,682,861 'everyth':432,961 'execut':308,1186 'exist':73 'expert':1224 'export':170,186,207,227,356,408,437,475,614,659,708,739,944,954,968,996,1016,1046,1061 'express':831,1104 'f':670,679 'featur':406,933,937 'feature-scop':936 'fetch':65,277,320,366,375,1151 'file':472 'filter':665,675 'filteract':609,632 'filteractivepip':616 'filteredproduct':667,685 'first':1138 'flatten':324 'flow':135,798 'focus':91 'forget':1032 'forkjoin':310,311 'frontend':267 'get':684 'getactiveitem':644 'getdata':755 'global':963 'globalstor':970 'guest':806,825,827 'guid':11,34,1156,1167 'guidelin':55 'hard':975 'headercompon':890,915 'heavi':451,511,1118 'high':118,127,540,697 'html':453,546,721,800 'http':743 'httpclient':745 'hydrat':128,352,700,723,727,1133,1145 'i.active':626 'id':314,317,335,337,362,754 'impact':90 'implement':63,381,617,1019,1064 'import':415,424,433,478,485,493,494,498,503,520,533,578,584,703,991,1130 'improv':48 'includ':678,690 'increment':699 'index':564 'init':378 'initialvalu':1052 'inject':736,744,748,752,893,918,940,958,965,1001,1098 'input':1096,1233 'interact':729 'isplatformbrows':764 'isplatformserv':786 'issu':71 'item':548,550,555,557,558,560,562,567,569,570,591,593,595,620,621,622,629,631,642,808,810,815,816,817,820,839,841,852,864,866 'item.id':552,634,646,812,856,870 'item.name':596 'items.filter':624 'js':387 'key':756,762,781 'larg':575,1115 'lazi':111,399,404,1123 'lazy-load':1122 'let':590 'lib':1128 'librari':507,512 'limit':1195 'list':576,1116 'load':80,112,388,400,405,431,510,1124 'loadchart':516 'loadchildren':414 'loadcompon':423 'low':148,984 'low-medium':147,983 'm':418,427 'm.admin':419 'm.dashboardcomponent':428 'main':446,531 'main.ts':240 'makestatekey':761 'manag':139,146,873,982,1015 'manual':1013,1055 'map':331 'match':1204 'medium':133,140,149,794,874,985 'memoiz':606 'memori':145,981 'method':601,636,1108 'micro':266 'micro-frontend':265 'miss':1241 'modal':487,499 'mutabl':194,217 'name':608,804,868,1045,1060 'navig':370 'need':1041 'nest':280 'new':58,237,523,796,1086 'ngif':822 'ngondestroy':1028,1081 'ngoninit':383,1024,1074 'non':718,1140 'non-crit':717,1139 'null':770,1053,1069,1070 'observ':758 'ondestroy':1020,1066 'oninit':382,1065 'onpush':97,157,162 'oper':271 'optim':7,21,33,45,76,109,132,397,793 'output':1097,1213 'overview':1194 'p':332,676,688 'p.id':333 'p.name.tolowercase':677,689 'page':62 'parallel':307,322 'param':285,289 'params.id':291 'parti':506,1127 'patch':251 'path':360,412,421,441 'pattern':66,104,142 'perform':6,22,32,43,70,117,539,1105,1155 'permiss':1234 'pipe':136,330,599,605,607,782,1005,1112 'pipetransform':618 'placehold':463 'platform':753 'platformid':751 'post':301,305,315 'practic':4,10,30 'precis':200 'precomput':834 'prefer':191,597,1033 'preload':106 'prerend':129 'prevent':878 'priorit':39 'prioriti':87,88 'privat':742,746,750,891,916,999,1021,1071 'product':662,664 'productpagecompon':956 'productstor':661,946,949,959 'profil':361 'profilecompon':372,380 'profileresolv':365 'project':238 'properti':195,218 'provid':246,712,948 'provideclienthydr':704,713 'providedin':737,942,966 'providezonelesschangedetect':247 'pure':598,604,612 'quick':1083 're':474,880,897,921 're-export':473 're-rend':879,896,920 'recalcul':681 'refactor':17,72 'refer':53,1084 'render':26,49,116,126,391,538,696,862,881,898,922,1137 'requir':219,1232 'resolv':349,363 'resourc':1153 'return':623,673,686,775,778 'review':15,67,1106,1225 'root':738,943,967 'rout':358,359,401,407,410,411,420,439,440,1121 'rule':40,84 'rxjs':103 'safeti':1235 'save':258 'scope':938,950,1206 'scroll':573 'select':884 'selector':143,876 'selectusernam':904 'sequenti':275 'server':124,368,694,1150 'server-fetch':1149 'server-sid':123,693 'shake':114,484,979 'shared/components':490 'shared/components/button/button.component':497 'shared/components/modal/modal.component':501 'side':125,342,695 'signal':96,141,164,174,192,198,211,214,663,666,840,1034,1092,1095 'size':24,78 'skill':1182,1198 'skill-angular-best-practices' 'smaller':255 'sort':845,858,867 'sorteditem':842,854 'source-sickn33' 'span':821 'specif':1220 'ssr':105,345,733,1131,1166 'ssr/hydration':83 'stack':260 'standalon':610,1090 'start':384 'state':138,872,909,912,925,927,931,974,1094 'statekey':760,769,774,789 'stop':1226 'store':892,894,917,919,939,957,964 'string':757 'sub':1072 'subscrib':292,300,318,338,394,906,1008,1027,1077 'subscript':151,281,885,989,1014,1022,1023,1036,1040,1056,1073 'substitut':1216 'success':1238 'switchmap':328,334 'syntax':799 'tabl':488 'takeuntildestroy':987,992,1006 'tap':783 'task':1202 'templat':131,168,181,203,223,587,627,792,830,850,860,887,911,1043,1058,1110 'test':1222 'third':505,1126 'third-parti':504,1125 'this.canvas':525 'this.chart':522 'this.data':1004,1026,1079 'this.destroyref':1007 'this.filter':671,691 'this.http.get':392,779 'this.items':844 'this.platformid':765,787 'this.postsservice.getposts':298,316 'this.process':1010 'this.products':674 'this.products.filter':687 'this.route.params':329 'this.route.params.subscribe':284 'this.service.data':1051,1076 'this.store':929 'this.store.selectsignal':903 'this.sub':1075 'this.sub.unsubscribe':1082 'this.subscription':1025 'this.subscription.unsubscribe':1029 'this.transferstate.get':768 'this.transferstate.remove':773 'this.transferstate.set':788 'this.userservice.getuser':290,313,336 'time':81 'titl':204,210,224,230 'tolowercas':672 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agent-skills' 'topic-ai-agents' 'topic-ai-coding' 'topic-ai-workflows' 'topic-antigravity' 'topic-antigravity-skills' 'topic-claude-code' 'topic-claude-code-skills' 'topic-codex-cli' 'topic-codex-skills' 'tosign':928,1050 'trace':261 'track':551,563,633,645,811,855,869,1103 'trackbi':120,543 'transferst':731,747,749,1147 'transform':619 'treat':1211 'tree':113,483,953,978 'tree-shak':482,977 'trigger':199 'true':611,613,1091 'typescript':160,196,239,278,346,402,476,508,577,602,652,701,735,832,882,934,990,1037 'updat':201 'use':12,52,156,348,448,542,571,647,730,795,875,986,1111,1143,1180,1196 'user':293,297,312,802,803,823 'user.id':299 'user.name':826,913 'usernam':888,900,902 'v20':243 'valid':1221 'viewport':456,725 'virtual':121,572,1117 'wait':287,295,303 'waterfal':101,272,283,343 'witheventreplay':715 'withincrementalhydr':705,714 'workflow':1188 'write':14,57 'wrong':176,216,279,373,429,477,527,635,680,857,905,960,1012,1054 'zone.js':220,250 'zoneless':98,235,241,1160","prices":[{"id":"274c773c-6d54-48b2-b457-e7f50033fe9b","listingId":"bdcd9d51-e950-4953-a4aa-5c1e9b12b286","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"sickn33","category":"antigravity-awesome-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T21:30:57.385Z"}],"sources":[{"listingId":"bdcd9d51-e950-4953-a4aa-5c1e9b12b286","source":"github","sourceId":"sickn33/antigravity-awesome-skills/angular-best-practices","sourceUrl":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular-best-practices","isPrimary":false,"firstSeenAt":"2026-04-18T21:30:57.385Z","lastSeenAt":"2026-04-25T00:50:25.934Z"}],"details":{"listingId":"bdcd9d51-e950-4953-a4aa-5c1e9b12b286","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"sickn33","slug":"angular-best-practices","github":{"repo":"sickn33/antigravity-awesome-skills","stars":34964,"topics":["agent-skills","agentic-skills","ai-agent-skills","ai-agents","ai-coding","ai-workflows","antigravity","antigravity-skills","claude-code","claude-code-skills","codex-cli","codex-skills","cursor","cursor-skills","developer-tools","gemini-cli","gemini-skills","kiro","mcp","skill-library"],"license":"mit","html_url":"https://github.com/sickn33/antigravity-awesome-skills","pushed_at":"2026-04-24T06:41:17Z","description":"Installable GitHub library of 1,400+ agentic skills for Claude Code, Cursor, Codex CLI, Gemini CLI, Antigravity, and more. Includes installer CLI, bundles, workflows, and official/community skill collections.","skill_md_sha":"a2a72d2fb1a39ee58c9d08885940558d146d75c6","skill_md_path":"skills/angular-best-practices/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/sickn33/antigravity-awesome-skills/tree/main/skills/angular-best-practices"},"layout":"multi","source":"github","category":"antigravity-awesome-skills","frontmatter":{"name":"angular-best-practices","description":"Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency."},"skills_sh_url":"https://skills.sh/sickn33/antigravity-awesome-skills/angular-best-practices"},"updatedAt":"2026-04-25T00:50:25.934Z"}}