Skip to content
cccskills
FreePublished on GitHub

angular-migration

ハイブリッドモード、段階的コンポーネント書き換え、依存性注入更新を使用してAngularJSからAngularへ移行します。AngularJSアプリケーションのアップグレード、フレームワーク移行の計画、またはレガシーAngularコードのモダナイゼーション時に使用します。

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md10.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

English | 日本語

Angular移行

ハイブリッドアプリ、コンポーネント変換、依存性注入の変更、ルーティング移行を含む、AngularJSからAngularへの移行をマスターします。

このスキルを使用するタイミング

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

移行戦略

1. ビッグバン(完全な書き換え)

  • Angularでアプリ全体を書き直す
  • 並行開発
  • 一度に切り替える
  • 最適: 小規模アプリ、グリーンフィールドプロジェクト

2. 段階的(ハイブリッドアプローチ)

  • AngularJSとAngularを並行実行
  • 機能ごとに移行
  • 相互運用のためのngUpgrade
  • 最適: 大規模アプリ、継続的デリバリー

3. バーティカルスライス

  • 1つの機能を完全に移行
  • Angularで新機能、AngularJSで既存を維持
  • 段階的に置き換え
  • 最適: 中規模アプリ、明確な機能

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

// main.ts - ハイブリッドアプリをブートストラップ
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);
    // 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() {
    // main.tsで手動でブートストラップ
  }
}

コンポーネント移行

AngularJSコントローラー → Angularコンポーネント

// Before: AngularJSコントローラー
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コンポーネント
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ディレクティブ
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コンポーネント
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>();
}

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

サービス移行

// Before: AngularJSサービス
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サービス
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サービス
import { Injectable } from '@angular/core';

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

// AngularJSで利用可能にする
import { downgradeInjectable } from '@angular/upgrade/static';

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

// AngularJSで使用
angular.module('myApp').controller('OldController', function(newService) {
  console.log(newService.getData());
});

アップグレード AngularJS → Angular

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

// 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']
    }
  ]
})

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

ルーティング移行

// Before: AngularJSルーティング
angular.module('myApp').config(function($routeProvider) {
  $routeProvider
    .when('/users', {
      template: '<user-list></user-list>'
    })
    .when('/users/:id', {
      template: '<user-detail></user-detail>'
    });
});
// After: Angularルーティング
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 {}

フォーム移行

<!-- Before: AngularJS -->
<form name="userForm" ng-submit="saveUser()">
  <input type="text" ng-model="user.name" required>
  <input type="email" ng-model="user.email" required>
  <button ng-disabled="userForm.$invalid">Save</button>
</form>
// After: Angular (テンプレート駆動)
@Component({
  template: `
    <form #userForm="ngForm" (ngSubmit)="saveUser()">
      <input type="text" [(ngModel)]="user.name" name="name" required>
      <input type="email" [(ngModel)]="user.email" name="email" required>
      <button [disabled]="userForm.invalid">Save</button>
    </form>
  `
})

// またはリアクティブフォーム(推奨)
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  template: `
    <form [formGroup]="userForm" (ngSubmit)="saveUser()">
      <input formControlName="name">
      <input formControlName="email">
      <button [disabled]="userForm.invalid">Save</button>
    </form>
  `
})
export class UserFormComponent {
  userForm: FormGroup;

  constructor(private fb: FormBuilder) {
    this.userForm = this.fb.group({
      name: ['', Validators.required],
      email: ['', [Validators.required, Validators.email]]
    });
  }

  saveUser() {
    console.log(this.userForm.value);
  }
}

移行タイムライン

フェーズ1: セットアップ(1-2週間)
- Angular CLIをインストール
- ハイブリッドアプリをセットアップ
- ビルドツールを設定
- テストをセットアップ

フェーズ2: インフラストラクチャ(2-4週間)
- サービスを移行
- ユーティリティを移行
- ルーティングをセットアップ
- 共有コンポーネントを移行

フェーズ3: 機能移行(様々)
- 機能ごとに移行
- 徹底的にテスト
- 段階的にデプロイ

フェーズ4: クリーンアップ(1-2週間)
- AngularJSコードを削除
- ngUpgradeを削除
- バンドルを最適化
- 最終テスト

リソース

  • references/hybrid-mode.md: ハイブリッドアプリパターン
  • references/component-migration.md: コンポーネント変換ガイド
  • references/dependency-injection.md: DI移行戦略
  • references/routing.md: ルーティング移行
  • assets/hybrid-bootstrap.ts: ハイブリッドアプリテンプレート
  • assets/migration-timeline.md: プロジェクト計画
  • scripts/analyze-angular-app.sh: アプリ分析スクリプト

ベストプラクティス

  1. サービスから開始: サービスを最初に移行(より簡単)
  2. 段階的アプローチ: 機能ごとの移行
  3. 継続的にテスト: 各ステップでテスト
  4. TypeScriptを使用: 早期にTypeScriptに移行
  5. スタイルガイドに従う: 初日からAngularスタイルガイド
  6. 後で最適化: まず動作させ、次に最適化
  7. 文書化: 移行ノートを保持

一般的な落とし穴

  • ハイブリッドアプリを正しくセットアップしない
  • ロジックの前にUIを移行
  • 変更検出の違いを無視
  • スコープを適切に処理しない
  • パターンの混在(AngularJS + Angular)
  • 不十分なテスト

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

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.

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

開発者を喜ばせる直感的でスケーラブルで保守可能なAPIを構築するために、RESTとGraphQL APIの設計原則をマスターします。新しいAPIの設計、API仕様のレビュー、またはAPI設計標準の確立時に使用してください。

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use when architecting complex backend systems or refactoring existing applications for better maintainability.

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

クリーンアーキテクチャ、ヘキサゴナルアーキテクチャ、ドメイン駆動設計を含む実証済みのバックエンドアーキテクチャパターンを実装します。複雑なバックエンドシステムの設計や、保守性向上のための既存アプリケーションのリファクタリング時に使用します。

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

Python asyncio、並行プログラミング、高性能アプリケーション向けの非同期/awaitパターンをマスター。非同期API、並行システム、ノンブロッキング操作が必要なI/OバウンドアプリケーションをPythonで構築する際に使用。

The English summary is being prepared. Showing the original description.

amurata/cc-tools6Updated Nov 28, 2025

See all skills by amurata

Report a problem with this skill