mcpField
A
angular-migration

angular-migration

github.com/wshobson開発41.9k11.0k 回インストール2 週間前に更新
リポジトリ

angular-migration について

angular-migrationは、AngularJSアプリをAngularへ移行するチーム向けのスキルです。一括書き換えや段階的移行、ハイブリッド運用に加え、コンポーネント、サービス、依存性注入、ルーティングの移行を扱います。

主な機能

  1. 01一括・段階的・垂直スライス移行
  2. 02AngularJSとAngularのハイブリッド運用
  3. 03コントローラーやディレクティブの変換
  4. 04サービスと依存性注入の移行
  5. 05ルーティングシステムの移行

活用シーン

  1. 01小規模アプリの全面書き換え計画
  2. 02大規模アプリの機能単位での移行
  3. 03AngularJSディレクティブのAngularコンポーネント化
  4. 04サービス、依存性注入、ルーティングの更新

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/wshobson/agents --skill angular-migration

インストール後、Claude Code で/angular-migrationを入力して読み込まれたか確認します。

同梱ファイルreferences/details.md

詳細

Angular マイグレーション

AngularJS から Angular へのマイグレーションをマスターしましょう。ハイブリッドアプリ、コンポーネントの変換、依存性注入の変更、ルーティングのマイグレーションなどを含みます。

このスキルを使用する場面

  • AngularJS (1.x) アプリケーションを Angular (2+) へマイグレーションする
  • AngularJS/Angular のハイブリッドアプリケーションを実行する
  • ディレクティブをコンポーネントに変換する
  • 依存性注入をモダナイズする
  • ルーティングシステムをマイグレーションする
  • 最新の Angular バージョンへアップデートする
  • Angular のベストプラクティスを実装する

マイグレーション戦略

1. ビッグバン (完全な書き換え)
  • アプリ全体を Angular で書き換える
  • 並行して開発する
  • 一度に切り替える
  • 最適な用途: 小規模なアプリ、グリーンフィールドプロジェクト
2. インクリメンタル (ハイブリッドアプローチ)
  • AngularJS と Angular を並行して実行する
  • 機能ごとにマイグレーションする
  • 相互運用に ngUpgrade を使用する
  • 最適な用途: 大規模なアプリ、継続的デリバリー
3. バーティカルスライス
  • 1 つの機能を完全にマイグレーションする
  • 新機能は Angular で、既存のものは AngularJS で維持する
  • 徐々に置き換える
  • 最適な用途: 中規模なアプリ、明確に分かれた機能

ハイブリッドアプリのセットアップ

// 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
  }
}

コンポーネントのマイグレーション

AngularJS コントローラー → Angular コンポーネント
// 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 ディレクティブ → Angular コンポーネント
// 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>

サービスのマイグレーション

// 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);
  }
}

依存性注入の変更

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());
});
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());
  }
}

ルーティングのマイグレーション

// 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 {}

追加のパターンとテンプレート

より詳細なテンプレートと実例は references/details.md にあります。完全なパターンライブラリについては、そのファイルをお読みください。

コメント