angular-architecture
40
总安装量
40
周安装量
#5257
全站排名
安装命令
npx skills add https://github.com/gentleman-programming/gentleman-skills --skill angular-architecture
Agent 安装分布
opencode
27
gemini-cli
22
github-copilot
21
kimi-cli
14
claude-code
14
Skill 文档
The Scope Rule (REQUIRED)
“Scope determines structure” – Where a component lives depends on its usage.
| Usage | Placement |
|---|---|
| Used by 1 feature | features/[feature]/components/ |
| Used by 2+ features | features/shared/components/ |
Example
features/
shopping-cart/
shopping-cart.ts # Main component = feature name
components/
cart-item.ts # Used ONLY by shopping-cart
cart-summary.ts # Used ONLY by shopping-cart
checkout/
checkout.ts
components/
payment-form.ts # Used ONLY by checkout
shared/
components/
button.ts # Used by shopping-cart AND checkout
modal.ts # Used by multiple features
Project Structure
src/app/
features/
[feature-name]/
[feature-name].ts # Main component (same name as folder)
components/ # Feature-specific components
services/ # Feature-specific services
models/ # Feature-specific types
shared/ # ONLY for 2+ feature usage
components/
services/
pipes/
core/ # App-wide singletons
services/
interceptors/
guards/
app.ts
app.config.ts
routes.ts
main.ts
File Naming (REQUIRED)
No .component, .service, .model suffixes. The folder tells you what it is.
â
user-profile.ts
â user-profile.component.ts
â
cart.ts
â cart.service.ts
â
user.ts
â user.model.ts
Style Guide
What We Follow (from official docs)
inject()over constructor injectionclassandstylebindings overngClass/ngStyleprotectedfor template-only membersreadonlyfor inputs, outputs, queries- Name handlers for action (
saveUser) not event (handleClick) - Keep lifecycle hooks simple – delegate to well-named methods
- One concept per file
@Component({...})
export class UserProfileComponent {
// 1. Injected dependencies
private readonly userService = inject(UserService);
// 2. Inputs/Outputs
readonly userId = input.required<string>();
readonly userSaved = output<User>();
// 3. Internal state
private readonly _loading = signal(false);
readonly loading = this._loading.asReadonly();
// 4. Computed
protected readonly displayName = computed(() => ...);
// 5. Methods
save(): void { ... }
}
What We Override
| Official Says | We Do | Why |
|---|---|---|
user-profile.component.ts |
user-profile.ts |
Redundant – folder tells context |
user.service.ts |
user.ts |
Same |
Commands
# New project
ng new my-app --style=scss --ssr=false
# Component in feature
ng g c features/products/components/product-card --flat
# Service in feature
ng g s features/products/services/product --flat
# Guard in core
ng g g core/guards/auth --functional