codemodsを使って、Ionic Angularを自動的にStandalone構成に移行する
Ionic公式が提供している @ionic/angular-standalone-codemods
を使って、Ionic Angularを自動的にStandalone構成に移行する方法についてご紹介します。なお、Ionic AngularのStandalone構成については、以下の記事をご参照ください。
推奨する事前準備
@ionic/angular-standalone-codemods
は、 ts-morph
を使ってコード変換を行います。変換されるすべてのファイルは ts-morph
を通して改行やインテントが変更されるため、変更箇所以外にも大きな差分がでます。そのため、コード整形ツールを使って、変更前後の差分を必要最小限にすることをおすすめします。以下はひとつの整形例です。
% npm install -D prettier
% npx prettier --parser typescript --write "./src/**/*.ts" && prettier --parser angular --write "./src/**/*.html"
もちろん、すでにPrettierを導入してコード整形をしている場合は、この手順は不要です。
@ionic/angular-standalone-codemodsとは
@ionic/angular-standalone-codemods
は、Ionic公式が提供している、Ionic AngularをStandalone構成に移行するためのコード変換ツールです。AngularのCLIで提供されている ng update
と同じように、Ionic AngularのStandalone構成に移行するためのコード変換を自動的に行ってくれます。
実行するのはとても簡単で、以下をIonic Angularのプロジェクトルートフォルダで実行するだけです。
% npx @ionic/angular-standalone-codemods
実行すると、プロンプトが表示されます。まず表示されるのは以下の通り。
▲ ⚠️ This utility is experimental. Always review the changes made before committing them to your project. ⚠️
│
▲ For manual migration, see the guide at: https://www.ionicframework.com/docs/angular/build-options#migrating-from-modules-to-standalone
ただの確認ですね。自動的に大きな差分をつくりだすので、実行する前には必ず今までの変更をコミットするようにしてください。続いて、以下が表示されます。
◆ Would you like to run this migration as a dry run? No changes will be written to your project.
│ ● Yes / ○ No
└
ここでは、実際にコードの変更を実行するのか、変更内容をプレビューするだけ(dry run)なのかの確認が行われます。 Yes
を選択すると、プレビューだけを行うことができます。実際にマイグレーションを行う場合は No
を変更しましょう。
◆ Please enter the path to your project (default is the current working directory):
│ /Users/sakakibara/dev/winecode/app_
最後にプロジェクトパスを確認されます。デフォルトでは、カレントディレクトリが指定されていますが、プロジェクトのパスを指定することもできます。そして、エンターキーを押すと、実行されます。数秒で終了し、以下のメッセージが表示されます。
◇ Project migration at /Users/sakakibara/dev/winecode/app completed successfully.
│
◆ We recommend reviewing the changes made by this migration and formatting your code (e.g., with Prettier) before committing.
これで、Ionic AngularのStandalone構成に移行するためのコード変換が完了しました。Prettierを使って再度整形し、どう差分がでたかGitでみることをおすすめします。
% npx prettier --parser typescript --write "./src/**/*.ts" && prettier --parser angular --write "./src/**/*.html"
どういった変更が行われているか
0001-migrate-app-module
ひとつめの変更は、ルートのNgModuleでインポートしてる IonicModule.forRoot
が、provideIonicAngularに置き換わります。これはAngularをStandalone構成に移行していないユーザのための変更です。
import { NgModule } from '@angular/core';
- import { IonicModule } from '@ionic/angular';
-
+ import { provideIonicAngular } from '@ionic/angular/standalone';
+
@NgModule({
- imports: [IonicModule.forRoot({ mode: 'md' })]
+ imports: [],
+ providers: [provideIonicAngular({ mode: 'md' })]
})
- export class AppModule {}
+ export class AppModule { }
0002-import-standalone-componen
ふたつめの変更は、IonicのStandaloneコンポーネントをインポートするようになります。IonicModuleを使わなくなったためですね。
import { Component } from "@angular/core";
+ import { IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel } from "@ionic/angular/standalone";
@Component({
selector: 'my-component',
...
</ion-list>
</ion-content>
\`,
- standalone: true
- })
+ standalone: true,
+ imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonList, IonItem, IonLabel]
+ })
export class MyComponent { }
また、IonIconが、 assets
の中身を参照するのではなく、 addIcons
で登録したアイコンを参照するようになったため、以下も変わりました。
import { Component } from "@angular/core";
+ import { addIcons } from "ionicons";
+ import { logoIonic } from "ionicons/icons";
+ import { IonIcon } from "@ionic/angular/standalone";
@Component({
selector: 'my-component',
template: '<ion-icon name="logo-ionic"></ion-icon>',
- standalone: true
- })
- export class MyComponent { }
+ standalone: true,
+ imports: [IonIcon]
+ })
+ export class MyComponent {
+ constructor() {
+ addIcons({ logoIonic });
+ }
+ }
addIcons
で登録されていないアイコンは表示されないことに注意が必要です。ただ、事前に他の場所(Window関数に格納されるので、 main.ts
でも、他のコンポーネントでも、他のサービスでも)、登録されていれば表示することができます。ただ、当該コンポーネントで登録するのが一番総バンドルサイズは小さくなります。
0003-migrate-bootstrap-application / 0006-migrate-angular-app-config
3つめの変更は、bootstrapApplication
でimportProvidersFromを使って読み込んでた IonicModule.forRoot
が、provideIonicAngularに置き換わります。これは、AngularをStandalone構成に移行済のユーザ向けの変更です。
- import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
+ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
...
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
- importProvidersFrom(IonicModule.forRoot({ mode: 'ios' })),
provideRouter(routes),
+ provideIonicAngular({ mode: 'ios' })
],
});
0004-migrate-import-statements
4つめの変更は、 @ionic/angular
からのインポートが、すべて @ionic/angular/standalone
からのインポートになります。 なお、移行後は、 @ionic/angular
からのインポートは利用できません。 Moduleを読み込んでないので当然ですよね。
import { Injectable } from '@angular/core';
- import { ModalController } from '@ionic/angular';
+ import { ModalController } from '@ionic/angular/standalone';
@Injectable()
export class MyService {
0005-migrate-angular-json-assets
5つめの変更は、 angular.json
で node_modules/ionicons/dist/ionicons/svg
をコピーしてた部分が削除されます。これは、Ionic AngularのStandalone構成では、IonIconは addIcons
経由にBundleするようになり、 assets
から削除されたためです。
architect: {
build: {
options: {
- assets: [
- "src/favicon.ico",
- "src/assets",
- {
- glob: "**/*.svg",
- input: "node_modules/ionicons/dist/ionicons/svg",
- output: "./svg",
- },
- ],
+ assets: ["src/favicon.ico", "src/assets"],
},
},
},
まとめ
Ionicチームは、 ng update
に触発され、大きな変更がある度に(Capacitorのメジャーバージョンアップ含め)マイグレーションツールを提供しています。これらのツールを使うことで、Ionicのアップデートをより簡単に行うことができます。ぜひ、ご利用ください。
Discussion