Add comprehensive Claude Code tooling: - Agents: docs-researcher, docs-researcher-advanced for documentation research - Commands: dev:add-e2e-attrs, docs:library, docs:refresh-reference, quality:bundle-analyze, quality:coverage - Skills: 8 specialized skills including api-change-analyzer, architecture-enforcer, library-scaffolder, and more Update documentation: - Comprehensive CLAUDE.md overhaul with library reference system - Update testing guidelines in docs/guidelines/testing.md - Update READMEs for checkout, icons, scanner, and scroll-position libraries Remove outdated checkout-completion-flow-documentation.md Update .gitignore for Claude Code files
5.6 KiB
name, description
| name | description |
|---|---|
| standalone-component-migrator | This skill should be used when converting Angular NgModule-based components to standalone architecture. It handles dependency analysis, template scanning, route refactoring, and test updates. Use this skill when the user requests component migration to standalone, mentions "convert to standalone", or wants to modernize Angular components to the latest patterns. |
Standalone Component Migrator
Overview
Automate the conversion of Angular components from NgModule-based architecture to standalone components with explicit imports. This skill analyzes component dependencies, updates routing configurations, migrates tests, and optionally converts to modern Angular control flow syntax (@if, @for, @switch).
When to Use This Skill
Invoke this skill when:
- User requests component conversion to standalone
- User mentions "migrate to standalone" or "modernize component"
- User wants to remove NgModule declarations
- User references Angular's standalone component architecture
Migration Workflow
Step 1: Analyze Component Dependencies
-
Read Component File
- Identify component decorator configuration
- Note selector, template path, style paths
- Check if already standalone
-
Analyze Template
- Read template file (HTML)
- Scan for directives:
*ngIf,*ngFor,*ngSwitch→ requires CommonModule - Scan for forms:
ngModel,formControl→ requires FormsModule or ReactiveFormsModule - Scan for built-in pipes:
async,date,json→ CommonModule - Scan for custom components: identify all component selectors
- Scan for router directives:
routerLink,router-outlet→ RouterModule
-
Find Parent NgModule
- Search for NgModule that declares this component
- Read NgModule file to understand current imports
Step 2: Convert Component to Standalone
Add standalone: true and explicit imports array:
// BEFORE
import { Component } from '@angular/core';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html'
})
export class MyComponent { }
// AFTER
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { ChildComponent } from './child.component';
import { CustomPipe } from '@isa/utils/pipes';
@Component({
selector: 'app-my-component',
standalone: true,
imports: [
CommonModule,
FormsModule,
RouterModule,
ChildComponent,
CustomPipe
],
templateUrl: './my-component.component.html'
})
export class MyComponent { }
Step 3: Update Parent NgModule
Remove component from declarations, add to imports if exported:
// BEFORE
@NgModule({
declarations: [MyComponent, OtherComponent],
imports: [CommonModule],
exports: [MyComponent]
})
// AFTER
@NgModule({
declarations: [OtherComponent],
imports: [CommonModule, MyComponent], // Import standalone component
exports: [MyComponent]
})
If NgModule becomes empty (no declarations), consider removing it entirely.
Step 4: Update Routes (if applicable)
Convert to lazy-loaded standalone component:
// BEFORE
const routes: Routes = [
{ path: 'feature', component: MyComponent }
];
// AFTER (lazy loading)
const routes: Routes = [
{
path: 'feature',
loadComponent: () => import('./my-component.component').then(m => m.MyComponent)
}
];
Step 5: Update Tests
Convert test configuration:
// BEFORE
TestBed.configureTestingModule({
declarations: [MyComponent],
imports: [CommonModule, FormsModule]
});
// AFTER
TestBed.configureTestingModule({
imports: [MyComponent] // Component imports its own dependencies
});
Step 6: Optional - Migrate to Modern Control Flow
If requested, convert to new Angular control flow syntax:
// OLD
<div *ngIf="condition">Content</div>
<div *ngFor="let item of items; trackBy: trackById">{{ item.name }}</div>
<div [ngSwitch]="value">
<div *ngSwitchCase="'a'">A</div>
<div *ngSwitchDefault>Default</div>
</div>
// NEW
@if (condition) {
<div>Content</div>
}
@for (item of items; track item.id) {
<div>{{ item.name }}</div>
}
@switch (value) {
@case ('a') { <div>A</div> }
@default { <div>Default</div> }
}
Step 7: Validate and Test
-
Compile Check
npx tsc --noEmit -
Run Tests
npx nx test [library-name] --skip-nx-cache -
Lint Check
npx nx lint [library-name] -
Verify Application Runs
npm start
Common Import Patterns
| Template Usage | Required Import |
|---|---|
*ngIf, *ngFor, *ngSwitch |
CommonModule |
ngModel |
FormsModule |
formControl, formGroup |
ReactiveFormsModule |
routerLink, router-outlet |
RouterModule |
async, date, json pipes |
CommonModule |
| Custom components | Direct component import |
| Custom pipes | Direct pipe import |
Error Handling
Issue: Circular dependencies
- Extract shared interfaces to util library
- Use dependency injection for services
- Avoid component A importing component B when B imports A
Issue: Missing imports causing template errors
- Check browser console for specific errors
- Verify all template dependencies are in imports array
- Use Angular Language Service in IDE for hints
References
- Angular Standalone Components: https://angular.dev/guide/components/importing
- Modern Control Flow: https://angular.dev/guide/templates/control-flow
- CLAUDE.md Component Architecture section