angular-best-practices
Angular ベストプラクティスワークフロースキルです。ユーザーが Angular のパフォーマンス最適化とベストプラクティスガイドを必要とする場合に使用します。Angular コードの作成、レビュー、またはリファクタリングを行い、最適なパフォーマンス、バンドルサイズ、およびレンダリング効率を実現する際に使用してください。マージまたは引き継ぎの前に、オペレータはアップストリームワークフロー、コピーされたサポートファイル、および来歴を保持する必要があります。
description の原文を見る
Angular Best Practices workflow skill. Use this skill when the user needs Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency and the operator should preserve the upstream workflow, copied support files, and provenance before merging or handing off.
SKILL.md 本文
---
name: angular-best-practices
description: "Angular Best Practices workflow skill. Use this skill when the user needs Angular performance optimization and best practices guide. Use when writing, reviewing, or refactoring Angular code for optimal performance, bundle size, and rendering efficiency and the operator should preserve the upstream workflow, copied support files, and provenance before merging or handing off."
version: "0.0.1"
category: development
tags: ["angular-best-practices", "angular", "performance", "optimization", "and", "best", "practices", "guide"]
complexity: advanced
risk: caution
tools: ["codex-cli", "claude-code", "cursor", "gemini-cli", "opencode"]
source: community
author: "sickn33"
date_added: "2026-04-14"
date_updated: "2026-04-25"
---
# Angular ベストプラクティス
## 概要
このパブリックインテイク版は、`https://github.com/sickn33/antigravity-awesome-skills` から `plugins/antigravity-awesome-skills-claude/skills/angular-best-practices` をパッケージ化し、ネイティブな Omni Skills の編集形式に変換したもので、オリジンを隠さずに保持しています。
オペレーターがアップストリームのワークフロー、サポートファイル、およびリポジトリコンテキストを保全する必要があり、パブリックバリデーターとプライベートエンハンサーが通常のダウンストリームフローを継続する場合に使用してください。
このインテイクは、コピーされたアップストリームファイルを保全に保ち、`metadata.json` の `external_source` ブロックと `ORIGIN.md` をプロビナンスアンカーとしてレビュー用に使用します。
# Angular ベストプラクティス Angular アプリケーション向けの包括的なパフォーマンス最適化ガイド。パフォーマンスボトルネックの排除、バンドルの最適化、レンダリング効率の向上のための優先順位付きルールが含まれます。
パブリックヘッダーに完全にマップされなかったインポートされたソースセクションは、以下またはサポートファイルで保持されています。注目すべきインポートされたセクション: 1. Change Detection (CRITICAL)、2. Async Operations & Waterfalls (CRITICAL)、3. Bundle Optimization (CRITICAL)、4. Rendering Performance (HIGH)、5. Server-Side Rendering (HIGH)、6. Template Optimization (MEDIUM)。
## このスキルを使用する場合
このセクションをトリガーフィルターとして使用します。オペレーターがファイルを読み込む、コマンドを実行する、またはプルリクエストを開く前に、アクティベーション境界を明示する必要があります。
- 新しい Angular コンポーネントまたはページを作成するとき
- データフェッチングパターンを実装するとき
- パフォーマンスの問題がないかコードをレビューするとき
- 既存の Angular コードをリファクタリングするとき
- バンドルサイズまたは読み込み時間を最適化するとき
- SSR/ハイドレーションを設定するとき
## オペレーティングテーブル
| 状況 | ここから開始 | なぜ重要か |
| --- | --- | --- |
| 初回使用 | `metadata.json` | コピーされたワークフローに触れる前に、`external_source` ブロックを通じてリポジトリ、ブランチ、コミット、およびインポートされたパスを確認します |
| プロビナンスレビュー | `ORIGIN.md` | レビューアーにインポートされたソースの平文監査証跡を提供します |
| ワークフロー実行 | `README.md` | 実行を実質的に変更する最小のコピーされたファイルから開始します |
| サポーティングコンテキスト | `README.md` | パッケージ全体を読み込まずに、次に関連性の高いコピーされたソースファイルを追加します |
| ハンドオフ判定 | `## Related Skills` | タスクが別の専門領域に逸脱したときに、オペレーターがより強力なネイティブスキルに切り替えるのに役立ちます |
## ワークフロー
このワークフローは、意図的に編集的かつ運用的です。インポートされたソースをオペレーターに有用に保つ一方で、ダウンストリームエンハンサーフローを供給するパブリックインテイク標準を満たしています。
1. ユーザーの目標、インポートされたワークフローのスコープ、およびこのスキルがタスクの適切なルーターであるかどうかを確認します。
2. コピーされたアップストリームサポートファイルを読み込む前に、概要およびプロビナンスファイルを読みます。
3. 現在のリクエストの結果を実質的に変更するリファレンス、例、プロンプト、またはスクリプトのみを読み込みます。
4. プロビナンスとソース境界を作業メモで明示的に保つながら、アップストリームワークフローを実行します。
5. コピーされたファイルの結果をアップストリーム期待値と、指摘できる証拠に対して検証します。
6. 作業がこのインポートされたワークフローの重心から逸脱したときに、関連スキルにエスカレートまたはハンドオフします。
7. マージまたはクロージャーの前に、何が使用されたか、何が変更されたか、そしてレビューアーが何を検証する必要があるかを記録します。
### インポートされたワークフロー注記
#### インポート: 1. Change Detection (CRITICAL)
### OnPush Change Detection を使用
```typescript
// 正しい - OnPush with Signals
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `<div>{{ count() }}</div>`,
})
export class CounterComponent {
count = signal(0);
}
// 間違い - デフォルト change detection
@Component({
template: `<div>{{ count }}</div>`, // 毎サイクルチェック
})
export class CounterComponent {
count = 0;
}
Mutable Properties より Signals を優先
// 正しい - Signals は正確な更新をトリガー
@Component({
template: `
<h1>{{ title() }}</h1>
<p>Count: {{ count() }}</p>
`,
})
export class DashboardComponent {
title = signal("Dashboard");
count = signal(0);
}
// 間違い - Mutable properties は zone.js チェックが必要
@Component({
template: `
<h1>{{ title }}</h1>
<p>Count: {{ count }}</p>
`,
})
export class DashboardComponent {
title = "Dashboard";
count = 0;
}
新規プロジェクトで Zoneless を有効化
// main.ts - Zoneless Angular (v20+)
bootstrapApplication(AppComponent, {
providers: [provideZonelessChangeDetection()],
});
メリット:
- 非同期 API への zone.js パッチなし
- より小さいバンドル (~15KB 削減)
- デバッグのためのクリーンなスタックトレース
- マイクロフロントエンドとの互換性向上
例
例 1: アップストリームワークフローを直接リクエスト
@angular-best-practices を使用して <task> を処理します。コピーされたアップストリームワークフローから開始し、結果を変更するファイルのみを読み込み、答えのプロビナンスを可視化を保ちます。
説明: これはオペレーターがインポートされたワークフローが必要だが、リポジトリ全体は不要な場合の最も安全な開始点です。
例 2: プロビナンス根拠のあるレビューをリクエスト
@angular-best-practices を metadata.json および ORIGIN.md に対してレビューし、最初に読み込むコピーされたアップストリームファイルがどれであり、その理由を説明します。
説明: レビューまたはトラブルシューティングの前にこれを使用して、オリジンとファイル選択の正確で監査可能な説明が必要な場合に使用します。
例 3: 実行前にコピーされたサポートファイルを絞る
@angular-best-practices を <task> に使用します。結果を変更するコピーされたリファレンス、例、またはスクリプトのみを読み込み、進める前にファイルを明示的に名前付けします。
説明: これにより、デフォルトでコピーされたパッケージ全体を読み込む代わりに、段階的な情報公開と一致するスキルを保ちます。
例 4: レビューアーパケットを構築
@angular-best-practices をコピーされたアップストリームファイルとプロビナンスを使用してレビューし、マージ前にギャップを要約します。
説明: これはPRが人的レビュー待ちで、反復可能な監査パケットが必要な場合に便利です。
ベストプラクティス
生成されたパブリックスキルを、アップストリームリポジトリの周りのレビュー可能なパッケージング層として扱います。目標は、プロビナンスを明示的に保ち、実行を実質的に改善するコピーされたソース素材のみを読み込むことです。
- 優先度 - カテゴリ - インパクト - フォーカス
- 1 - Change Detection - CRITICAL - Signals、OnPush、Zoneless
- 2 - Async Waterfalls - CRITICAL - RxJS パターン、SSR プリロード
- 3 - Bundle Optimization - CRITICAL - 遅延ロード、tree shaking
- 4 - Rendering Performance - HIGH - @defer、trackBy、仮想化
- 5 - Server-Side Rendering - HIGH - ハイドレーション、プリレンダリング
- 6 - Template Optimization - MEDIUM - 制御フロー、パイプ
インポートされたオペレーティング注記
インポート: 優先度別ルールカテゴリ
| 優先度 | カテゴリ | インパクト | フォーカス |
|---|---|---|---|
| 1 | Change Detection | CRITICAL | Signals、OnPush、Zoneless |
| 2 | Async Waterfalls | CRITICAL | RxJS パターン、SSR プリロード |
| 3 | Bundle Optimization | CRITICAL | 遅延ロード、tree shaking |
| 4 | Rendering Performance | HIGH | @defer、trackBy、仮想化 |
| 5 | Server-Side Rendering | HIGH | ハイドレーション、プリレンダリング |
| 6 | Template Optimization | MEDIUM | 制御フロー、パイプ |
| 7 | State Management | MEDIUM | Signal パターン、セレクター |
| 8 | Memory Management | LOW-MEDIUM | クリーンアップ、サブスクリプション |
トラブルシューティング
問題: オペレーターがインポートされたコンテキストをスキップして、あまりに一般的に応答した
症状: 結果が plugins/antigravity-awesome-skills-claude/skills/angular-best-practices のアップストリームワークフローを無視する、プロビナンスについて言及しない、またはコピーされたソースファイルをまったく使用しません。
解決策: metadata.json、ORIGIN.md、および最も関連するコピーされたアップストリームファイルを再度開きます。external_source ブロックを最初にチェックし、続行する前にプロビナンスを再度述べてください。
問題: インポートされたワークフローがレビュー中に不完全に感じられる
症状: レビューアーは生成された SKILL.md を見ることができますが、現在のタスクにどのリファレンス、例、またはスクリプトが関係するかをすぐに判断できません。
解決策: 取った道を正当化する正確なコピーされたリファレンス、例、スクリプト、またはアセットを指摘します。ギャップがまだ実際の場合は、隠さずにPRに記録してください。
問題: タスクが別の専門化に逸脱した
症状: インポートされたスキルが適切な場所から開始しますが、作業がデバッグ、アーキテクチャ、デザイン、セキュリティ、またはネイティブスキルがより良く処理するリリースオーケストレーションに変わります。 解決策: 関連スキルセクションを使用して、意図的にハンドオフします。インポートされたプロビナンスを可視化したままにして、次のスキルが盲目的に開始する代わりに適切なコンテキストを継承できるようにします。
関連スキル
@00-andruia-consultant- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門化によってより良く処理される場合に使用します。@00-andruia-consultant-v2- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門化によってより良く処理される場合に使用します。@10-andruia-skill-smith- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門化によってより良く処理される場合に使用します。@10-andruia-skill-smith-v2- このインポートされたスキルがコンテキストを確立した後、作業がそのネイティブ専門化によってより良く処理される場合に使用します。
追加リソース
このサポートマトリックスと以下のリンク済みファイルをこのインポートされたスキルのオペレーターパケットとして使用します。これらは汎用スキャフォールディングではなく、実際のコピーされたソース素材を反映する必要があります。
| リソースファミリ | レビューアーに何を提供するか | 例パス |
|---|---|---|
references | アップストリームからコピーされたリファレンスノート、ガイド、または背景素材 | references/n/a |
examples | アップストリームからコピーされた実装例または再利用可能なプロンプト | examples/n/a |
scripts | 実行またはバリデーションを実質的に変更するアップストリームヘルパースクリプト | scripts/n/a |
agents | ルーティングまたはデリゲーション注記で、インポートされたパッケージの一部 | agents/n/a |
assets | ソースパッケージからコピーされたサポーティングアセットまたはスキーマ | assets/n/a |
インポートされたリファレンスノート
インポート: クイックリファレンスチェックリスト
新規コンポーネント
-
changeDetection: ChangeDetectionStrategy.OnPush -
standalone: true - 状態用 Signals (
signal()、input()、output()) - 依存関係用
inject() -
track式付き@for
パフォーマンスレビュー
- テンプレートにメソッドなし (パイプまたはコンピュータを使用)
- 大きなリストの仮想化
- 重いコンポーネントの遅延
- ルートの遅延ロード
- サードパーティライブラリの動的インポート
SSR チェック
- ハイドレーション設定済み
- クリティカルコンテンツが最初にレンダリング
- 非クリティカルコンテンツが
@defer (hydrate on ...)を使用 - サーバーフェッチデータ用の TransferState
インポート: リソース
インポート: 2. Async Operations & Waterfalls (CRITICAL)
シーケンシャルなデータフェッチングを排除
// 間違い - ネストされたサブスクリプションはウォーターフォールを作成
this.route.params.subscribe((params) => {
// 1. params を待つ
this.userService.getUser(params.id).subscribe((user) => {
// 2. user を待つ
this.postsService.getPosts(user.id).subscribe((posts) => {
// 3. posts を待つ
});
});
});
// 正しい - forkJoin で並列実行
forkJoin({
user: this.userService.getUser(id),
posts: this.postsService.getPosts(id),
}).subscribe((data) => {
// 並列でフェッチ
});
// 正しい - switchMap で依存呼び出しをフラット化
this.route.params
.pipe(
map((p) => p.id),
switchMap((id) => this.userService.getUser(id)),
)
.subscribe();
SSR のクライアント側ウォーターフォールを回避
// 正しい - ナビゲーション前にサーバーでフェッチするため、リゾルバーまたはブロッキングハイドレーションを使用
export const route: Route = {
path: "profile/:id",
resolve: { data: profileResolver }, // ナビゲーション前にサーバーでフェッチ
component: ProfileComponent,
};
// 間違い - コンポーネントが init 時にデータをフェッチ
class ProfileComponent implements OnInit {
ngOnInit() {
// JS がロードされてコンポーネントがレンダリングされた後にのみ開始
this.http.get("/api/profile").subscribe();
}
}
インポート: 3. Bundle Optimization (CRITICAL)
ルートの遅延ロード
// 正しい - フィーチャールートの遅延ロード
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,
),
},
];
// 間違い - すべてを即座ロード
import { AdminModule } from "./admin/admin.module";
export const routes: Routes = [
{ path: "admin", component: AdminComponent }, // メインバンドルに入る
];
重いコンポーネント向けに @defer を使用
<!-- 正しい - 重いコンポーネントはオンデマンドでロード -->
@defer (on viewport) {
<app-analytics-chart [data]="data()" />
} @placeholder {
<div class="chart-skeleton"></div>
}
<!-- 間違い - 重いコンポーネントが初期バンドルに入る -->
<app-analytics-chart [data]="data()" />
Barrel File の再エクスポートを回避
// 間違い - barrel 全体をインポート、tree-shaking を破壊
import { Button, Modal, Table } from "@shared/components";
// 正しい - 直接インポート
import { Button } from "@shared/components/button/button.component";
import { Modal } from "@shared/components/modal/modal.component";
サードパーティライブラリを動的にインポート
// 正しい - 重いライブラリをオンデマンドでロード
async loadChart() {
const { Chart } = await import('chart.js');
this.chart = new Chart(this.canvas, config);
}
// 間違い - Chart.js をメインチャンクにバンドル
import { Chart } from 'chart.js';
インポート: 4. Rendering Performance (HIGH)
@for で常に trackBy を使用
<!-- 正しい - 効率的な DOM 更新 -->
@for (item of items(); track item.id) {
<app-item-card [item]="item" />
}
<!-- 間違い - 任意の変更でリスト全体が再レンダリング -->
@for (item of items(); track $index) {
<app-item-card [item]="item" />
}
大きなリスト向けに仮想スクロール使用
import { CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll } from '@angular/cdk/scrolling';
@Component({
imports: [CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll],
template: `
<cdk-virtual-scroll-viewport itemSize="50" class="viewport">
<div *cdkVirtualFor="let item of items" class="item">
{{ item.name }}
</div>
</cdk-virtual-scroll-viewport>
`
})
メソッド上に Pure Pipes を優先
// 正しい - Pure パイプ、メモ化
@Pipe({ name: 'filterActive', standalone: true, pure: true })
export class FilterActivePipe implements PipeTransform {
transform(items: Item[]): Item[] {
return items.filter(i => i.active);
}
}
// テンプレート
@for (item of items() | filterActive; track item.id) { ... }
// 間違い - 変更検出のたびにメソッドが呼ばれる
@for (item of getActiveItems(); track item.id) { ... }
派生データ向けに computed() を使用
// 正しい - コンピュータ、依存関係が変更されるまでキャッシュ
export class ProductStore {
products = signal<Product[]>([]);
filter = signal('');
filteredProducts = computed(() => {
const f = this.filter().toLowerCase();
return this.products().filter(p =>
p.name.toLowerCase().includes(f)
);
});
}
// 間違い - アクセスのたびに再計算
get filteredProducts() {
return this.products.filter(p =>
p.name.toLowerCase().includes(this.filter)
);
}
インポート: 5. Server-Side Rendering (HIGH)
インクリメンタルハイドレーションを設定
// app.config.ts
import {
provideClientHydration,
withIncrementalHydration,
} from "@angular/platform-browser";
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(withIncrementalHydration(), withEventReplay()),
],
};
非クリティカルコンテンツを遅延
<!-- クリティカルなスクロール上部コンテンツ -->
<app-header />
<app-hero />
<!-- スクロール下部遅延、ハイドレーショントリガー -->
@defer (hydrate on viewport) {
<app-product-grid />
} @defer (hydrate on interaction) {
<app-chat-widget />
}
SSR データに TransferState を使用
@Injectable({ providedIn: "root" })
export class DataService {
private http = inject(HttpClient);
private transferState = inject(TransferState);
private platformId = inject(PLATFORM_ID);
getData(key: string): Observable<Data> {
const stateKey = makeStateKey<Data>(key);
if (isPlatformBrowser(this.platformId)) {
const cached = this.transferState.get(stateKey, null);
if (cached) {
this.transferState.remove(stateKey);
return of(cached);
}
}
return this.http.get<Data>(`/api/${key}`).pipe(
tap((data) => {
if (isPlatformServer(this.platformId)) {
this.transferState.set(stateKey, data);
}
}),
);
}
}
インポート: 6. Template Optimization (MEDIUM)
新しい制御フロー構文を使用
<!-- 正しい - 新しい制御フロー (より高速、より小さいバンドル) -->
@if (user()) {
<span>{{ user()!.name }}</span>
} @else {
<span>Guest</span>
} @for (item of items(); track item.id) {
<app-item [item]="item" />
} @empty {
<p>No items</p>
}
<!-- 間違い - レガシー構造ディレクティブ -->
<span *ngIf="user; else guest">{{ user.name }}</span>
<ng-template #guest><span>Guest</span></ng-template>
複雑なテンプレート式を回避
// 正しい - コンポーネント内で事前計算
class Component {
items = signal<Item[]>([]);
sortedItems = computed(() =>
[...this.items()].sort((a, b) => a.name.localeCompare(b.name))
);
}
// テンプレート
@for (item of sortedItems(); track item.id) { ... }
// 間違い - テンプレートでソート、毎レンダリング
@for (item of items() | sort:'name'; track item.id) { ... }
インポート: 7. State Management (MEDIUM)
セレクターを使用して再レンダリングを防止
// 正しい - 選択的なサブスクリプション
@Component({
template: `<span>{{ userName() }}</span>`,
})
class HeaderComponent {
private store = inject(Store);
// userName が変更されたときのみ再レンダリング
userName = this.store.selectSignal(selectUserName);
}
// 間違い - 全状態をサブスクライブ
@Component({
template: `<span>{{ state().user.name }}</span>`,
})
class HeaderComponent {
private store = inject(Store);
// 任意の状態変更で再レンダリング
state = toSignal(this.store);
}
状態をフィーチャーと共存
// 正しい - フィーチャー範囲内ストア
@Injectable() // NOT providedIn: 'root'
export class ProductStore { ... }
@Component({
providers: [ProductStore], // コンポーネントツリーにスコープ
})
export class ProductPageComponent {
store = inject(ProductStore);
}
// 間違い - グローバルストアに全て
@Injectable({ providedIn: 'root' })
export class GlobalStore {
// アプリ全体の状態を
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- diegosouzapw
- ライセンス
- MIT
- 最終更新
- 2026/5/10
Source: https://github.com/diegosouzapw/awesome-omni-skills / ライセンス: MIT