用途
Angular 是一个框架技能(Framework Skill),提供现代 Angular 的专属规则,覆盖独立组件、signals、块控制流、函数式 provider 等。它把 core-typescript 和 architecture-and-design 中通用表述的规则,落实为 Angular 的具体形式。
该技能建立在 core-typescript(语言规则)和 architecture-and-design(设计)之上,UI 工作还涉及 accessibility。只有当任务确实涉及某一层时才加载对应兄弟技能;若未加载,则用通用知识应用该层,不阻塞工作。
SKILL.md 是自足的:下方 Ruleset 是完整、可执行的清单。每个 references/<topic>.md 保存该组的推理与 ❌ / ✅ 代码示例,references/worked-example.md 是一次完整审查过程;在运行环境允许时可打开它们获取更深入的内容。
主要能力
技能提供三种模式,按顺序执行步骤:
- Generate(生成)——编写新组件、服务或路由:1. 独立组件、OnPush、inject()、signals(bootstrap、components、signals、inputs-outputs);2. 模板中使用块控制流(templates);3. 每个订阅都有清理(rxjs);4. 把 Ruleset 当检查清单逐条运行,交付前修复每个失败项。
- Review(审查)——检查 PR 或 diff:1. 对 diff 运行 Ruleset;2. 每个失败项按下方输出格式写一条发现;3. 排序:must-fix 在前,consider 在后;4. 若无失败,用一行说明,不要编造发现。
- Migrate(迁移)——现代化旧版 Angular:1. 先运行官方迁移 schematic:standalone、control flow、inject、signal inputs、output、signal queries、lazy route loading;2. 对 schematic 未覆盖的部分手工应用 Ruleset;3. 每次提交只做一个迁移,保持测试通过。
输出格式为每行一条发现:
<severity> · <topic> · <file>:<line> — <what is wrong>. <the fix as an action>.
其中 severity 为 must-fix(违反本技能规则或编译器检查)或 consider(安全,但规则偏好另一种形式);topic 为 Ruleset 主题 slug(signals、templates、rxjs 等)。
所有模式的规则:执行规则时点名 Ruleset 主题;优先使用当前 Angular API 而非其装饰器或 NgModule 前身;文件内一致性优先,若文件整体沿用旧风格则匹配它并记录差距,而非半转换。
Ruleset 主题概览
- bootstrap:无 NgModule,所有组件/指令/管道独立;用 bootstrapApplication(App, appConfig) 与函数式 provider(provideRouter、provideHttpClient、provideClientHydration);新应用不用 provideZoneChangeDetection 和 zone.js polyfill,仅在升级 v20 应用时用 provideZonelessChangeDetection();angularCompilerOptions 开启 strictTemplates 等严格选项;angular-eslint 启用推荐规则集。
- components:每个组件使用 ChangeDetectionStrategy.OnPush;依赖来自 inject() 而非构造函数参数;注入成员、输入、输出、查询分组在类顶部;Angular 赋值的成员为 readonly,仅模板使用的成员为 protected;每文件一个组件/指令/服务;选择器带项目前缀;生命周期钩子简短并实现接口;host 绑定与监听放在 host 对象;事件处理器按动作命名;横切行为用 hostDirective;不用 ::ng-deep。
- signals:状态放在 signal(),派生值用 computed() 并保持纯净;不在 effect() 内写 signal,effect() 只把 signal 值推入非响应式 API 并在 onCleanup 释放资源;untracked() 包裹不应成为依赖的读取;signal 写入后不用 cdr.detectChanges() 或 markForCheck();共享状态用 providedIn: 'root' 服务暴露 signal / computed。
- inputs-outputs:使用 input() / input.required() / output() / model() / viewChild() / contentChild(),不用 @Input() / @Output() / @ViewChild / @ContentChild 装饰器;输入以调用方式读取(this.name());双向值用 this.value.set(...) 写入。
- templates:使用 @if / @for / @switch,不用 *ngIf / *ngFor / *ngSwitch;每个 @for 用稳定 id 做 track,不用 $index;绑定中不调用方法,改用 computed() 或纯管道;重或首屏外区块用 @defer 加 on 触发器;用 [class.x] / [style.x.px] 而非 NgClass / NgStyle;调用方内容通过 <ng-content> + 具名插槽、TemplateRef 输入 + *ngTemplateOutlet 或 NgComponentOutlet;自定义管道为纯、独立、有类型且无 I/O。
- dependency-injection:服务用 @Injectable({ providedIn: 'root' }),仅在需要按路由或按组件实例时缩小作用域;路由守卫为函数式(CanActivateFn),HTTP 拦截器为函数式(HttpInterceptorFn 配合 withInterceptors);系统边界注入 InjectionToken<T> 抽象而非具体类;inject() 只在注入上下文调用,之后调用需包在 runInInjectionContext;手动清理绑定 inject(DestroyRef)。
- rxjs:状态用 signal,随时间变化的流用 Observable(HTTP、路由事件、WebSocket、DOM 事件),在边界用 toSignal() 转为 signal;不用没有 takeUntilDestroyed() 或 async 管道的手动 .subscribe();HttpClient 从 repository 调用而非组件;服务端状态用缓存库而非手写 BehaviorSubject store;组件级服务端读取用 resource() / httpResource()(v22 起稳定);传输错误在一个函数式拦截器处理,顶层 ErrorHandler 报告并显示回退。
- forms:signal 组件中的新表单用 Signal Forms(v22 起稳定);代码库已基于响应式表单则沿用;模板驱动仅用于简单单输入;响应式表单要有类型;验证器与领域模型同源;invalid / dirty / 错误文本从表单状态派生;模式不渲染的控件用 disable({ emitEvent: false });保存被阻止时向用户说明原因。
- routing:provideRouter(routes);特性用 loadComponent / loadChildren 懒加载并映射到特性文件夹;仅特性使用的服务作用域在路由 providers 数组;路由参数、查询参数、数据用 withComponentInputBinding() 绑定到输入;过滤器、当前标签、分页保留在 URL。
- rendering-ssr:zoneless-ready,视图由 signals 或 async 管道驱动;DOM 测量与命令式 DOM 工作放在 afterNextRender() / afterEveryRender();不在构造函数或字段初始化器中使用 window / document / localStorage;SSR 应用用 provideClientHydration();NgOptimizedImage(ngSrc)带显式宽高或 fill;不对用户或 API 提供的内容使用 bypassSecurityTrust*;焦点与实时变更播报用 CDK a11y 工具;仍在 Zone.js 的应用中,高频监听器在 NgZone.runOutsideAngular 内运行。
- testing:独立组件通过自身 imports 测试(TestBed.configureTestingModule({ imports: [C] }) 或 @testing-library/angular 的 render(C, …));用 provideHttpClientTesting() 与 HttpTestingController 断言,不触网;导航由 RouterTestingHarness 驱动;DOM 按角色和可访问名称查询;signal / computed 在 fixture.detectChanges() 后读取;仅在 await fixture.whenStable() 无法完成时用 fakeAsync / tick;覆盖层内容通过其控制 signal 或 document 查询断言;每个测试还需通过 test-quality Ruleset。
适用场景
适用于现代 Angular 应用的编写、代码审查、重构与旧版迁移,尤其是采用独立组件、signals、块控制流和函数式 provider 的项目。
限制
本技能是 Angular 框架规则,不覆盖:语言规则(见 core-typescript)或框架无关架构(见 architecture-and-design);深层 RxJS 操作符设计与 store 库(NgRx、NGXS);Nx 或 monorepo 设置、Angular Material 主题、@angular/animations;样式属于 styling-and-design-tokens,i18n 属于 i18n-and-localization,加载与交互成本属于 web-performance;可访问性深度(焦点管理、ARIA、a11y 测试)属于 accessibility;独立组件与块控制流之前的 Angular 版本(旧应用先迁移);其他框架(react 和 vue 是兄弟技能)。Zoneless 变更检测自 v21 起稳定且为默认;本规则让仍在 Zone.js 的应用保持 zoneless-ready。
组合关系
与 core-typescript(语言基础)、architecture-and-design(设计层,冲突时它决定设计、本技能决定 Angular API)、accessibility(UI 审查视角)、test-quality(评判本技能 testing 组产出的单个测试)、react / vue(兄弟框架技能)组合使用。