(その1)とかつけてみて、シリーズ化出来たらネタ探し楽でいいなぁという安直な考えで作ったタイトル
とりあえず経緯という前フリ
ここ数年、元々Vue使いだった自分が初めてAngular とか言うクソみたいな言語 を使う機会があり、IONIC+Angularでスマホのハイブリッドアプリを作成しています。
開発当初はAngularのバージョンが11とかでAngularバブちゃんの自分としては「こんななんもしないファイル(Moduleファイルとか)を量産しないと駄目なの、なあぜなあぜ?」な状態でよくわからんまま使い続けてましたが、ここ最近のバージョンアップ(Angular17?)でStandalone版が出てグッバイ・モジュールとなるということなので、試しにソレを使って1から現行アプリのリプレイスを試みようとしてる際の備忘録的なアレです。
とにかくimport地獄
イヤ、コレはStandalone版ということで、使う先のコンポーネントでやらなきゃいけないおまじない的なアレとして、何となくの覚悟は出来てたけど。。。
classに付ける@Componentのimportsが兎に角多い、複雑な(Ionicの標準コンポーネントを多用するような)画面だと htmlで使うコンポーネントをimportに書かないといけない ので、マジでclassにたどり着かないという地獄を見た。
import {
IonBackdrop,
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonCheckbox,
IonCol,
IonContent,
IonFab,
IonFabButton,
IonFabList,
IonFooter,
IonGrid,
IonHeader,
IonIcon,
IonImg,
IonInfiniteScroll,
IonInfiniteScrollContent,
IonInput,
IonItem,
IonLabel,
IonList,
IonMenu,
IonMenuButton,
IonProgressBar,
IonRefresher,
IonRefresherContent,
IonRow,
IonSegment,
IonSegmentButton,
IonSelect,
IonSelectOption,
IonText,
IonTitle,
IonToolbar,
MenuController,
} from '@ionic/angular/standalone';
@Component({
selector: 'app-org-component',
templateUrl: 'page.html',
styleUrls: ['page.scss'],
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule,
IonBackdrop,
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonCheckbox,
IonCol,
IonContent,
IonFab,
IonFabButton,
IonFabList,
IonFooter,
IonGrid,
IonHeader,
IonIcon,
IonImg,
IonInfiniteScroll,
IonInfiniteScrollContent,
IonInput,
IonItem,
IonLabel,
IonList,
IonMenu,
IonMenuButton,
IonProgressBar,
IonRefresher,
IonRefresherContent,
IonRow,
IonSegment,
IonSegmentButton,
IonSelect,
IonSelectOption,
IonText,
IonTitle,
IonToolbar,
]
})
export class Page {
まぁフォーマッターの設定で、1項目1行を止めろよって話ですが、IONICでプロジェクト作った際の標準のやつがコレなのでもはやどうしようもないね(遠い目
回避策としてconst.tsとか作って、親子関係になるであろうグループだったり・画面共通で使うであろう項目をまとめて定義するとか思いついたけど、使わないコンポーネントがあると無駄にimportしちゃうし、何が定義されてるのかが分かりにくくなって保守しにくくなるというデメリットもあるので、マジ何が正解なのかわからん。。。
export const IonGridComp = [IonGrid, IonRow, IonCol];
export const IonSegmentComp = [IonSegment, IonSegmentButton];
export const IonMenuComp = [IonMenu, IonMenuButton];
// 使う側
@Component({
selector: 'app-org-component',
templateUrl: 'page.html',
styleUrls: ['page.scss'],
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule,
IonBackdrop,
IonButton,
IonButtons,
IonCard,
IonCardContent,
IonCardHeader,
IonCardTitle,
IonCheckbox,
IonContent,
IonFab,
IonFabButton,
IonFabList,
IonFooter,
IonHeader,
IonIcon,
IonImg,
IonInfiniteScroll,
IonInfiniteScrollContent,
IonInput,
IonItem,
IonLabel,
IonList,
IonProgressBar,
IonRefresher,
IonRefresherContent,
IonSelect,
IonSelectOption,
IonText,
IonTitle,
IonToolbar,
...IonGridComp,
...IonSegmentComp,
...IonMenuComp,
]
})
export class Page {
見ての通り使ったところで微々たる行数なので、ぶっちゃけ諦めて全部書いてやってもいいかなとか思ってる。
ion-iconが正しく動かない
公式の通りに書いてもアイコンが表示されないという罠にハマった。
マジで 「説明書・設計書よりもコードが正」 ってレベルでサイト内で説明が見つからなくて四苦八苦したわ。
※正解はこちらのiconsに記載があるよ
簡単に説明すると「使う先々のコンポーネントのコンストラクターで addicons を呼び出して、使うアイコンを指定しろよ」ってことで、以下のようなHTMLを記述した際には
<ion-icon name="logo-ionic"></ion-icon>
component側で以下のような実装が必要ってことになるみたいです。
import { addIcons } from 'ionicons';
import { logoIonic } from 'ionicons/icons'; // 使いたい画像のnameをキャメル型で記載
// 省略
@Component({
// 省略
}
export class Page {
constructor(){
addicons({logoIonic}); // カンマ区切りで複数定義
}
}
全体で必ず使うよってやつならエントリポイントになるであろうapp.component.tsのコンストラクタで定義すればいいよみたいなことが書いてあったけど、そんな風に書いたら何が定義されてるかがわからなくなり保守しづらくなるだろうから、マジでこの実装をしないといけないのは改悪なんじゃないかと思うレベル。
※イヤ、使うやつだけを定義すれば起動時の読み込みとか無駄がなくなり早くなるんだろうな的なのはわかるけど、実装の仕方がわからなくなるというトレードオフが発生してるなぁという感想
とりあえず今回はここまで
Angularとしては、NgModuleを残しつつの段階的にStandoalone化ができるみたいなことを謳ってますが、そこに外部のフレームワークが絡んでくるとどうなるのかわからんのでだったら1からいっちょやってみっかということで始めてみたアレですが、元の書き方と細かい部分で地味に違うということで、結構四苦八苦しながら作ってみてます。
同じことで悩んでる子羊たちの道標になるように、今後も人柱的な立場で情報を発信できたらと。