跳到正文
cccskills
免费在 GitHub 公开

angular-migration

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

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(1)

  • SKILL.md10.7 KB

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

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)
  • 不十分なテスト

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

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.

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

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.

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

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

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

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.

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

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

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

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

中文简介正在准备中。当前显示原文说明。

amurata/cc-tools62025年11月28日 更新

查看 amurata 的全部技能

报告此技能的问题