実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part1
lacolaco さん監修の実践 Angular: Standalone Components をざっくりキャッチアップしてみます。 zenn.dev
- Google Developers Expert for Angular
- Angularコントリビューター
- Angular日本ユーザー会代表
- jsprimer.net 著者
Zenn プロフィールから引用
記事内のAngular (NgModule-based minimal app) の構成は下記の通りです。
$ tree . ├── angular.json ├── package.json ├── src │ ├── global_styles.css │ ├── index.html │ └── main.ts └── tsconfig.json
■ 自分は、新規プロジェクト作成して実装してみました。
新規作成プロジェクトの場合の構成です。
$ ng new stand-alone-components-sample $ cd stand-alone-components-sample $ tree . ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ └── app.component.ts │ ├── assets │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.css ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json
- app.component.html の実装例
<h1>{{ title }}</h1>
- app.component.ts の実装例
import 'zone.js/dist/zone.js'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; @Component({ selector: 'app-root', standalone: true, imports: [CommonModule], templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { title = 'stand alone components sample'; }
- main.ts の実装例
import { AppComponent } from './app/app.component'; import { bootstrapApplication } from '@angular/platform-browser'; bootstrapApplication(AppComponent).catch((error) => console.error(error));
- main.ts と app.component.ts の関係を正しく理解しないと実装を失敗します。
- 既存のプロジェクトにスタンドアロンコンポーネントを適用すると上記コードのように変更すれば良いと思いました。
- 既存の Angular アプリケーションプロジェクトをスタンドアロンコンポーネントにマイグレーションしたい場合は、下記記事を参考にすると良いと思います。 kasaharu.hatenablog.com
# スタンドアロンコンポーネント生成コマンド例 $ ng g c list --standalone # <== --standalone オプションを付ける $ ng g c list-item --standalone
■ list と list-item コンポーネントを並列に生成した場合
$ tree . ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── list │ │ │ ├── list.component.css │ │ │ ├── list.component.html │ │ │ ├── list.component.spec.ts │ │ │ └── list.component.ts │ │ └── list-item │ │ ├── list-item.component.css │ │ ├── list-item.component.html │ │ ├── list-item.component.spec.ts │ │ └── list-item.component.ts │ ├── assets │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.css ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json
■ list と list-item のコンポーネントの並列配置の実装例(コンポーネントのみ)
- app.component.html の実装例
<h1>{{ title }}</h1> <app-list> <app-list-item><span>hoge</span></app-list-item> <app-list-item><span>fuga</span></app-list-item> </app-list>
- app.component.ts の実装例
import 'zone.js/dist/zone.js'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { ListComponent } from './list/list.component'; import { ListItemComponent } from './list-item/list-item.component'; @Component({ selector: 'app-root', standalone: true, imports: [CommonModule, ListComponent, ListItemComponent], templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { title = 'stand alone components sample'; }
■ list と list-item のコンポーネントを NgModule で実装した例
- list.module.ts 追加
$ ng g m list $ tree . ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.ts │ │ ├── list.module.ts # <== 追加 │ │ ├── list │ │ └── list-item │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.css ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json
- list.module.ts の実装例
import { NgModule } from '@angular/core'; import { ListComponent } from './list/list.component'; import { ListItemComponent } from './list-item/list-item.component'; @NgModule({ imports: [ListComponent, ListItemComponent], exports: [ListComponent, ListItemComponent], }) export class ListModule {}
- app.component.html の実装例
<h1>{{ title }}</h1> <app-list> <app-list-item><span>hoge</span></app-list-item> <app-list-item><span>fuga</span></app-list-item> </app-list>
- app.component.ts の実装例
import 'zone.js/dist/zone.js'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { ListModule } from './list.module'; @Component({ selector: 'app-root', standalone: true, imports: [CommonModule, ListModule], templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { title = 'stand alone components sample'; }
NgModule の方が、今までの実装の延長線上で理解できるので、分かり易かったです。
■ テンプレートの実装次第では、 list と list-item のコンポーネント構造を下図のように階層化すると実装が簡素になると思いました。
$ tree . ├── LICENSE ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ ├── list │ │ │ ├── list-item # list の中に list-item を配置する │ │ │ │ ├── list-item.component.css │ │ │ │ ├── list-item.component.html │ │ │ │ ├── list-item.component.spec.ts │ │ │ │ └── list-item.component.ts │ │ │ ├── list.component.css │ │ │ ├── list.component.html │ │ │ ├── list.component.spec.ts │ │ │ └── list.component.ts │ │ └── list.module.ts │ ├── assets │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ └── styles.css ├── tsconfig.app.json ├── tsconfig.json └── tsconfig.spec.json
■ list と list-item コンポーネント構造が階層化されている場合の実装例
- list.component.html の実装例
<app-list-item><span>hoge</span></app-list-item> <app-list-item><span>fuga</span></app-list-item>
- list.component.ts の実装例
import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ListItemComponent } from './list-item/list-item.component'; @Component({ selector: 'app-list', standalone: true, // list コンポーネント内で、list-item コンポーネントを定義 imports: [CommonModule, ListItemComponent], templateUrl: './list.component.html', styleUrls: ['./list.component.css'], }) export class ListComponent {}
- app.component.html の実装例
<h1>{{ title }}</h1> <app-list></app-list> <!-- app-list タグのみ -->
- app.component.ts の実装例
import 'zone.js/dist/zone.js'; import { CommonModule } from '@angular/common'; import { Component } from '@angular/core'; import { ListComponent } from './list/list.component'; @Component({ selector: 'app-root', standalone: true, // ListComponent の実装だけで済む & ListModule が不要になります。 imports: [CommonModule, ListComponent], templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent { title = 'stand alone components sample'; }
まとめ
- NgModule 化して実装するか、コンポーネント単体で実装するかは、UI の構造次第で変わると思います。
- list コンポーネントと list-item コンポーネントの実装は、以下の観点で変わると思います。
- スタンドアロンコンポーネントに限った話ではありませんが、スタンドアロンコンポーネントに変更する場合、改修箇所が変わると思います。
- 「依存性の注入」 のキャッチアップは次回に続きます。
- 追記
関連記事
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part1
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part2
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part3
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part4
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part5
- 実践 Angular: Standalone Components をざっくりキャッチアップしてみた Part6(まとめ)
参考文献