PluginBench
Skill
Pass
Audit score 90

angular-migration

wshobson/agents

Migrate AngularJS apps to Angular using hybrid mode, incremental rewriting, and dependency injection updates.

What is angular-migration?

This skill guides AngularJS to Angular migration using three strategies: big bang rewrite, incremental hybrid approach, or vertical slice. Use it when upgrading legacy AngularJS applications, planning framework migrations, or modernizing Angular code with best practices.

  • Set up hybrid AngularJS/Angular applications using ngUpgrade for side-by-side execution
  • Convert AngularJS controllers and directives to Angular components with proper TypeScript syntax
  • Migrate AngularJS services to Angular services with dependency injection
  • Downgrade Angular services for use in AngularJS and upgrade AngularJS services for Angular consumption
  • Migrate routing from AngularJS $routeProvider to Angular RouterModule
  • Choose between big bang, incremental, and vertical slice migration strategies

How to install angular-migration

npx skills add https://github.com/wshobson/agents --skill angular-migration
Prerequisites
  • Angular 2+ installed and configured
  • AngularJS 1.x application as migration source
  • @angular/upgrade package for hybrid app support
  • Understanding of AngularJS controllers, directives, and services
Claude Code
Cursor
Windsurf
Cline

How to use angular-migration

  1. 1.Choose a migration strategy (big bang, incremental, or vertical slice) based on app size and delivery needs
  2. 2.Set up hybrid app bootstrap using UpgradeModule to run AngularJS and Angular side-by-side
  3. 3.Migrate one component at a time: convert AngularJS controllers to Angular components
  4. 4.Update services to Angular pattern with HttpClient and Observable
  5. 5.Use downgradeInjectable and upgradeInjectable to share services between frameworks
  6. 6.Migrate routing from $routeProvider to Angular RouterModule
  7. 7.Test hybrid app thoroughly before removing AngularJS dependencies

Use cases

Good for
  • Incrementally migrate a large AngularJS monolith to Angular while maintaining continuous delivery
  • Convert an AngularJS directive library to reusable Angular components
  • Modernize legacy AngularJS applications by running Angular features alongside old code
  • Update dependency injection patterns when moving from AngularJS to Angular services
  • Migrate routing systems from AngularJS routes to Angular Router configuration
Who it's for
  • Backend developers maintaining legacy AngularJS applications
  • Frontend teams planning framework upgrades
  • Developers modernizing older Angular codebases
  • Teams managing large applications requiring gradual migration

angular-migration FAQ

What is the best migration strategy for a large AngularJS app?

The incremental (hybrid) approach is best for large apps. Run AngularJS and Angular side-by-side using ngUpgrade, migrate feature by feature, and gradually replace old code. This enables continuous delivery without a risky big bang rewrite.

How do I share services between AngularJS and Angular?

Use downgradeInjectable to make Angular services available to AngularJS, and upgradeInjectable to make AngularJS services available to Angular. Both are provided by @angular/upgrade/static.

Can I run AngularJS and Angular at the same time?

Yes, using the hybrid app setup with UpgradeModule. Bootstrap Angular first, then bootstrap AngularJS within the same application. This allows gradual migration without rewriting everything at once.

What replaces AngularJS directives in Angular?

AngularJS directives become Angular components. Use @Component decorator, @Input/@Output for bindings, and event binding syntax (click) instead of ng-click.

How do I migrate AngularJS routing to Angular?

Replace $routeProvider.when() calls with Angular Routes array, use RouterModule.forRoot(), and replace ng-view with <router-outlet>. Map old route paths to new Angular components.

Full instructions (SKILL.md)

Source of truth, from wshobson/agents.


name: angular-migration description: Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.

Angular Migration

Master AngularJS to Angular migration, including hybrid apps, component conversion, dependency injection changes, and routing migration.

When to Use This Skill

  • Migrating AngularJS (1.x) applications to Angular (2+)
  • Running hybrid AngularJS/Angular applications
  • Converting directives to components
  • Modernizing dependency injection
  • Migrating routing systems
  • Updating to latest Angular versions
  • Implementing Angular best practices

Migration Strategies

1. Big Bang (Complete Rewrite)

  • Rewrite entire app in Angular
  • Parallel development
  • Switch over at once
  • Best for: Small apps, green field projects

2. Incremental (Hybrid Approach)

  • Run AngularJS and Angular side-by-side
  • Migrate feature by feature
  • ngUpgrade for interop
  • Best for: Large apps, continuous delivery

3. Vertical Slice

  • Migrate one feature completely
  • New features in Angular, maintain old in AngularJS
  • Gradually replace
  • Best for: Medium apps, distinct features

Hybrid App Setup

// main.ts - Bootstrap hybrid app
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { UpgradeModule } from "@angular/upgrade/static";
import { AppModule } from "./app/app.module";

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .then((platformRef) => {
    const upgrade = platformRef.injector.get(UpgradeModule);
    // Bootstrap AngularJS
    upgrade.bootstrap(document.body, ["myAngularJSApp"], { strictDi: true });
  });
// app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { UpgradeModule } from "@angular/upgrade/static";

@NgModule({
  imports: [BrowserModule, UpgradeModule],
})
export class AppModule {
  constructor(private upgrade: UpgradeModule) {}

  ngDoBootstrap() {
    // Bootstrapped manually in main.ts
  }
}

Component Migration

AngularJS Controller → Angular Component

// Before: AngularJS controller
angular
  .module("myApp")
  .controller("UserController", function ($scope, UserService) {
    $scope.user = {};

    $scope.loadUser = function (id) {
      UserService.getUser(id).then(function (user) {
        $scope.user = user;
      });
    };

    $scope.saveUser = function () {
      UserService.saveUser($scope.user);
    };
  });
// After: Angular component
import { Component, OnInit } from "@angular/core";
import { UserService } from "./user.service";

@Component({
  selector: "app-user",
  template: `
    <div>
      <h2>{{ user.name }}</h2>
      <button (click)="saveUser()">Save</button>
    </div>
  `,
})
export class UserComponent implements OnInit {
  user: any = {};

  constructor(private userService: UserService) {}

  ngOnInit() {
    this.loadUser(1);
  }

  loadUser(id: number) {
    this.userService.getUser(id).subscribe((user) => {
      this.user = user;
    });
  }

  saveUser() {
    this.userService.saveUser(this.user);
  }
}

AngularJS Directive → Angular Component

// Before: AngularJS directive
angular.module("myApp").directive("userCard", function () {
  return {
    restrict: "E",
    scope: {
      user: "=",
      onDelete: "&",
    },
    template: `
      <div class="card">
        <h3>{{ user.name }}</h3>
        <button ng-click="onDelete()">Delete</button>
      </div>
    `,
  };
});
// After: Angular component
import { Component, Input, Output, EventEmitter } from "@angular/core";

@Component({
  selector: "app-user-card",
  template: `
    <div class="card">
      <h3>{{ user.name }}</h3>
      <button (click)="delete.emit()">Delete</button>
    </div>
  `,
})
export class UserCardComponent {
  @Input() user: any;
  @Output() delete = new EventEmitter<void>();
}

// Usage: <app-user-card [user]="user" (delete)="handleDelete()"></app-user-card>

Service Migration

// Before: AngularJS service
angular.module("myApp").factory("UserService", function ($http) {
  return {
    getUser: function (id) {
      return $http.get("/api/users/" + id);
    },
    saveUser: function (user) {
      return $http.post("/api/users", user);
    },
  };
});
// After: Angular service
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";

@Injectable({
  providedIn: "root",
})
export class UserService {
  constructor(private http: HttpClient) {}

  getUser(id: number): Observable<any> {
    return this.http.get(`/api/users/${id}`);
  }

  saveUser(user: any): Observable<any> {
    return this.http.post("/api/users", user);
  }
}

Dependency Injection Changes

Downgrading Angular → AngularJS

// Angular service
import { Injectable } from "@angular/core";

@Injectable({ providedIn: "root" })
export class NewService {
  getData() {
    return "data from Angular";
  }
}

// Make available to AngularJS
import { downgradeInjectable } from "@angular/upgrade/static";

angular.module("myApp").factory("newService", downgradeInjectable(NewService));

// Use in AngularJS
angular.module("myApp").controller("OldController", function (newService) {
  console.log(newService.getData());
});

Upgrading AngularJS → Angular

// AngularJS service
angular.module('myApp').factory('oldService', function() {
  return {
    getData: function() {
      return 'data from AngularJS';
    }
  };
});

// Make available to Angular
import { InjectionToken } from '@angular/core';

export const OLD_SERVICE = new InjectionToken<any>('oldService');

@NgModule({
  providers: [
    {
      provide: OLD_SERVICE,
      useFactory: (i: any) => i.get('oldService'),
      deps: ['$injector']
    }
  ]
})

// Use in Angular
@Component({...})
export class NewComponent {
  constructor(@Inject(OLD_SERVICE) private oldService: any) {
    console.log(this.oldService.getData());
  }
}

Routing Migration

// Before: AngularJS routing
angular.module("myApp").config(function ($routeProvider) {
  $routeProvider
    .when("/users", {
      template: "<user-list></user-list>",
    })
    .when("/users/:id", {
      template: "<user-detail></user-detail>",
    });
});
// After: Angular routing
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";

const routes: Routes = [
  { path: "users", component: UserListComponent },
  { path: "users/:id", component: UserDetailComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
})
export class AppRoutingModule {}

Additional patterns and templates

More detailed templates and worked examples live in references/details.md. Read that file for the full pattern library.