如何用 ECC 的 angular-developer 技能开发 Angular 应用?
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
当你在 Claude Code、Codex 等 agent 工具中开发 Angular 项目时,让 agent 自由发挥很容易得到不符合 Angular 规范的代码。ECC 仓库中的 angular-developer 技能 提供了一套完整的 Angular 开发约束:从ng new的执行规则、CLI 代码生成,到组件控制流、Signal Forms、依赖注入、路由和构建验证。本文沿着这条技能的主路径,完成「新建 Angular 项目 → 生成代码 → 实现核心功能 → 通过ng build与测试验证」这一连续任务。
准备工作:在 agent 中安装 ECC
技能要先被 agent 加载才能生效。按 README 的安装说明,原生插件路径(以 Claude Code 为例)是:
/plugin install ecc@ecc该路径会安装 ECC 的 skills、agents、commands 和插件管理的 hooks。注意不要在同一 harness 里叠加其他手动安装方式,否则可能重复安装 skills 和 hooks;一次装到多个 harness 则没有问题。
技能何时生效,以及两条硬性规则
根据 SKILL.md 的激活条件,该技能在以下情况触发:处于任意 Angular 项目中、创建脚手架新项目或库、生成 component/service/directive/pipe/guard/resolver、使用 Signals(signal、linkedSignal、resource)、处理表单、配置依赖注入与路由、编写 Angular 测试或配置 CLI/MCP 工具。
技能要求 agent 遵守两条贯穿全流程的规则:
- 先分析项目的 Angular 版本再给建议,因为不同版本可用的特性差异很大;用 Angular CLI 创建新项目时,除非用户明确要求某个版本,否则不要指定版本号。
- 生成代码后必须运行
ng build,如果有编译错误,先分析错误信息并修复,再进入下一步——不能跳过这一步。
第一步:创建新的 Angular 项目
技能为ng new定义了三步判定逻辑,按顺序执行:
1. 用户指定了明确版本(例如要求 Angular 15):绕过本地安装,严格用npx:
npx @angular/cli@<requested_version> new <project-name><requested_version>替换为用户要求的版本号,<project-name>替换为项目名。
2. 未指定版本:先运行ng version检查本机是否已安装 Angular CLI。命令成功返回版本号时,直接使用本地/全局安装:
ng new <project-name>3.ng version失败(说明系统没有安装 Angular CLI):回退到npx拉取最新版本:
npx @angular/cli@latest new <project-name>创建新项目的默认约定(用户没有额外要求时):使用最新稳定版 Angular;新项目在目标 Angular 版本支持 Signal Forms 时优先使用 Signal Forms(详见 signal-forms.md)。
第二步:用 CLI 管理依赖和生成代码
cli.md 要求修改项目结构或添加 Angular 特定依赖时,始终优先 CLI 命令而不是手动建文件或裸npm命令。
依赖安装用ng add而不是npm install,因为ng add除了安装包还会运行初始化 schematics(如配置angular.json、更新根 providers):
ng add @angular/material ng add tailwindcss ng add @angular/fire代码生成用ng g,保证代码符合 Angular 标准并自动更新必要的配置文件:
| 目标 | 命令 | 说明 |
|---|---|---|
| Component | ng g c path/to/name | 生成组件;按需加--inline-style(-s)或--inline-template(-t) |
| Service | ng g s path/to/name | 生成@Injectable({providedIn: 'root'})服务 |
| Directive | ng g d path/to/name | 生成指令 |
| Pipe | ng g p path/to/name | 生成管道 |
| Guard | ng g g path/to/name | 生成功能式路由守卫 |
| Environments | ng g environments | 生成src/environments/并更新angular.json的 file replacements |
注意:CLI 没有生成单条路由定义的命令。正确做法是先ng g c生成组件,再手动把它加进app.routes.ts的Routes数组。
本地开发用ng serve启动带 HMR 的服务器。如果开发时需要把/api代理到本地后端(例如http://localhost:3000),创建src/proxy.conf.json:
{ "/api/**": {"target": "http://localhost:3000", "secure": false} }并在angular.json的servetarget 中加入"options": { "proxyConfig": "src/proxy.conf.json" }。
第三步:实现核心功能——组件、服务、表单与路由
组件与模板控制流(参见 components.md)。现代 Angular 使用内置块做条件渲染和循环:@if支持@else if/@else;@for的track表达式是必需的,用于性能和 DOM 复用;@switch使用严格相等匹配且没有 fallthrough。组件默认是 standalone(Angular 19 起standalone: true是默认值);使用其他组件时把它加进消费方组件的imports数组。
服务与依赖注入(参见 creating-services.md)。用ng generate service my-data生成服务,推荐providedIn: 'root':它为整个应用创建单例、无需在 providers 数组中列出、并支持 tree-shaking。在组件或另一个服务中用inject()函数注入:
import {Component, inject} from '@angular/core'; import {BasicDataStore} from './basic-data-store.service'; @Component({ selector: 'app-example', template: `<p>Data items: {{ dataStore.getData().length }}</p>`, }) export class Example { dataStore = inject(BasicDataStore); }Signal Forms 表单。目标版本支持时,新表单优先用 Signal Forms:用一个 Signal model 定义表单结构,form()基于 model 派生表单,校验规则写在 schema 回调里。关键约束:model 初始值不能用null/undefined(字符串用''、数字用0、数组用[]);模板中用[formField]指令绑定字段,且不要在绑定了[formField]的 input 上再写min、max、value、[disabled]、[readonly]等属性——这些应定义为 schema 规则;提交回调必须async:
import {Component, signal} from '@angular/core'; import {form, FormField, submit, required, email} from '@angular/forms/signals'; @Component({ selector: 'app-example', imports: [FormField], template: ` <form (submit)="onSubmit(); $event.preventDefault()"> <input [formField]="userForm.name" /> <input type="email" [formField]="userForm.email" /> <button [disabled]="userForm().invalid()">Submit</button> </form> `, }) export class Example { userModel = signal({name: '', email: '', age: 0}); userForm = form(this.userModel, (s) => { required(s.name, {message: 'Name is required'}); email(s.email, {message: 'Invalid email'}); }); onSubmit() { submit(this.userForm, async () => { // 仅在表单有效时执行 }); } }访问字段状态时注意「先调用字段函数再取状态信号」:userForm.email().touched()是正确的,userForm.email.touched()会报错。完整规则、异步校验validateAsync(onError为必填项)和常见错误对照表见 signal-forms.md。
路由(参见 define-routes.md)。在Routes数组中定义路由,通过provideRouter提供;Angular 采用 first-match-wins 策略,具体路由要放在更宽泛的路由之前,通配符**路由永远放在数组末尾:
// app.routes.ts export const routes: Routes = [ {path: '', component: HomePage}, {path: 'admin', component: AdminPage}, ]; // app.config.ts export const appConfig: ApplicationConfig = { providers: [provideRouter(routes)], };第四步:构建与测试验证
这是技能强制的验证环节,也是判断生成代码是否可用的标准:
ng buildng build默认走 production 配置,启用 AOT 编译、压缩和 tree-shaking,产物输出到默认目录dist/<project-name>/browser;也可以用--configuration指定angular.json中定义的其他配置。出现编译错误时按错误信息逐项修复后重新构建。
ng test单元测试通过项目已配置的 runner(如 Karma 或 Vitest)执行。写测试时优先采用「Act, Wait, Assert」模式:先操作组件状态,再await fixture.whenStable()等待异步更新(Signals、zoneless 变更检测下状态变更往往是异步调度的),最后断言 DOM。基本结构(文档示例):
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [MyComponent], }).compileComponents(); fixture = TestBed.createComponent(MyComponent); component = fixture.componentInstance; h1 = fixture.nativeElement.querySelector('h1'); }); it('should display a different title after a change', async () => { component.title.set('New Test Title'); await fixture.whenStable(); expect(h1.textContent).toContain('New Test Title'); });更多测试实践(TestBed/ComponentFixture、组件 harness、RouterTestingHarness)见 testing-fundamentals.md。
可选分支:Tailwind CSS 与 Angular MCP Server
Tailwind CSS(参见 tailwind-css.md)。推荐自动化方式:
ng add tailwindcss该命令会安装依赖、配置项目并在全局样式中加入正确的 import。若手动配置,注意 Tailwind v4 的工作流:npm install tailwindcss @tailwindcss/postcss postcss,在项目根创建.postcssrc.json("plugins": {"@tailwindcss/postcss": {}}),在全局样式中写@import 'tailwindcss';(SCSS 用@use 'tailwindcss';)。不要创建tailwind.config.js,也不要使用 v3 的@tailwind base; @tailwind components; @tailwind utilities;写法,文档明确说明这会破坏应用构建。
Angular CLI MCP Server(参见 mcp.md)。Angular CLI 自带 MCP server,可让 AI 助手直接调用代码生成、最佳实践查询等工具。在你的宿主工具(IDE 或 CLI)中配置运行npx @angular/cli mcp,例如 Cursor 项目根下的.cursor/mcp.json:
{ "mcpServers": { "angular-cli": { "command": "npx", "args": ["-y", "@angular/cli", "mcp"] } } }默认提供ai_tutor、find_examples、get_best_practices、list_projects、search_documentation等工具;build、test、modernize、devserver.*、e2e属于实验工具,需显式加-E(--experimental-tool)启用,例如"args": ["-y", "@angular/cli", "mcp", "--read-only", "-E", "build"]。--read-only只注册不修改项目的工具,--local-only只注册不依赖网络的工具。
高频错误模式与限制
技能文档给出的反模式清单,都是生成代码后ng build前后最容易踩中的问题:
- 用
null或undefined作为 signal form 字段初始值——应使用''、0或[]; - 未调用字段就访问状态标志:
form.field.valid()错误,应为form.field().valid(); - 在绑定了
[formField]的 input 上设置min、max、value、disabled、readonly属性——应写成 schema 规则; - 在注入上下文之外调用
inject()——必要时使用runInInjectionContext; - 用
effect()管理本应由computed()派生的状态; - 在嵌套
@for循环中引用$parent.$index——Angular 不支持$parent,用let outerIdx = $index保存外层索引; - 目标版本支持 Signal Forms 时,却用旧版表单 API 开新表单;老项目和已有表单应沿用项目当前策略,不要混用。
另外两条适用边界:Signal Forms 只在新项目/新表单且目标版本支持时使用;standalone组件在旧版本中需要显式声明standalone: true或归属 NgModule。
需要深入某个主题时,技能在 references 目录 下按主题拆分了参考文档:依赖注入(di-fundamentals.md、injection-context.md)、路由守卫与解析器(route-guards.md、data-resolvers.md)、resource异步响应性(resource.md)、组件样式与 Tailwind(component-styling.md)、E2E 测试(e2e-testing.md)。按当前任务读取对应文件即可,不必全部通读。
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考