From harness-claude
Helps build module-free Angular apps using standalone components, bootstrapApplication, and lazy-loaded routes. Covers migration, code generation, and provider scoping.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:angular-standalone-componentsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Build module-free Angular apps with standalone: true, bootstrapApplication, and lazy-loaded standalone routes
Build module-free Angular apps with standalone: true, bootstrapApplication, and lazy-loaded standalone routes
standalone: true in the @Component, @Directive, or @Pipe decorator. Standalone components declare their own dependencies in the imports array instead of through a module.imports array: other standalone components, directives, pipes, and Angular built-ins like NgIf, NgFor, AsyncPipe, RouterLink, ReactiveFormsModule.bootstrapApplication(AppComponent, appConfig) in main.ts. Move all providers (provideRouter, provideHttpClient, provideAnimations) into the appConfig object.provideRouter(routes). Use loadComponent for lazy-loaded standalone components and loadChildren for lazy feature route arrays.CommonModule only as a last resort when migrating. Prefer importing individual directives (NgIf, NgFor, AsyncPipe) for better tree-shaking.providers array on a route object — this creates a scoped injector for that route subtree.ng generate component --standalone (or set standalone: true as the default in angular.json schematics) to generate standalone components by default.// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideAnimations } from '@angular/platform-browser/animations';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
import { authInterceptor } from './app/auth.interceptor';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideHttpClient(withInterceptors([authInterceptor])),
provideAnimations(),
],
});
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{
path: 'home',
loadComponent: () => import('./home/home.component').then((m) => m.HomeComponent),
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes').then((m) => m.ADMIN_ROUTES),
// providers scoped to this route subtree
providers: [AdminStateService],
},
];
// A standalone component
import { Component } from '@angular/core';
import { NgFor, AsyncPipe } from '@angular/common';
import { RouterLink } from '@angular/router';
import { ProductCardComponent } from '../product-card/product-card.component';
@Component({
selector: 'app-product-list',
standalone: true,
imports: [NgFor, AsyncPipe, RouterLink, ProductCardComponent],
template: `
<app-product-card
*ngFor="let p of products$ | async"
[product]="p"
[routerLink]="['/product', p.id]"
/>
`,
})
export class ProductListComponent { ... }
Why standalone over NgModules: NgModules were a layer of indirection that required declaring, exporting, and importing components in multiple places. Standalone components are self-describing — the imports array is the entire dependency manifest. This makes the component portable, tree-shakeable, and easier to test (no TestBed.configureTestingModule module imports needed, just the component itself).
provideRouter features: The functional router API supports feature flags as composable functions:
provideRouter(
routes,
withDebugTracing(), // logs route events to console
withPreloading(PreloadAllModules),
withComponentInputBinding(), // binds route params to @Input()
withViewTransitions() // enables View Transitions API
);
withComponentInputBinding: Enables binding route params, query params, and data directly to component inputs without injecting ActivatedRoute. The route param id maps to @Input() id: string.
Migrating from NgModules: Use the Angular CLI migration: ng generate @angular/core:standalone. It runs in three passes: convert declarations to standalone, remove unnecessary NgModules, switch the bootstrap call.
Scoped providers on routes: When a provider is listed in a route's providers array, it creates an Environment Injector scoped to that route. Services provided here are singletons within the lazy subtree but destroyed when the route is unloaded. This replaces the forRoot()/forChild() pattern from modules.
Testing standalone components:
await TestBed.configureTestingModule({
imports: [ProductListComponent], // import, not declare
}).compileComponents();
https://angular.dev/guide/components/importing
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeProvides expertise for modern Angular v20+ apps using Signals, Standalone Components, Zoneless change detection, SSR/Hydration, and reactive patterns. Ideal for new builds and performance optimization.
Provides Angular 14+ expertise for standalone components, signals, RxJS patterns, NgRx state management, dependency injection, lazy loading routes, OnPush change detection, and testing.
Generates Angular 17+ standalone components, sets up NgRx state management, configures lazy-loaded routing with guards, applies RxJS patterns, and optimizes bundle performance for enterprise apps.