はじめに
前回の記事では、Angular on Docker環境を構築した。
アプリケーション名は sample-angular-on-docker
という事にしている。
今回は、Angular公式チュートリアルのうち、『チュートリアル: Tour of Heroes』を実施する。
本チュートリアルは、以下の章立てで進められる。
- イントロダクション
- プロジェクトの作成
- 1.ヒーローエディター
- 2.リストの表示
- 3.フィーチャーコンポーネントの作成
- 4.サービスの追加
- 5.ナビゲーションの追加
- 6.サーバーからデータの取得
基本的にチュートリアルに沿っていくので、写経的な記事を書かず、
各章で詰まった点や、押さえておきたいポイントについて記事として残していく。
各種ポイント
本記事のタイトルの通り、チュートリアルをやるついでに色々と学んでいく。
ポイントとしては以下の通り。
- [POINT] ホットリロード
- [POINT] ディレクトリ構成
- [POINT] 「spec」って何?
- [POINT]
component
とservice
の違い - [POINT] その他
[POINT] ホットリロード
ファイル更新時にホットリロードしてくれると嬉しいなと思って調べてみると、起動オプションに --poll
を設定してあげればよいとの事。
なので、起動時に以下を使うようにする。
# こっちじゃなくて
root@60ff460a2f75:/projects/app# ng serve --host 0.0.0.0
# こっちを使う事で、ホットリロードができる
root@60ff460a2f75:/projects/app# ng serve --host 0.0.0.0 --poll 1 # 起動オプション --poll を指定
[POINT] ディレクトリ構成
ディレクトリ構成(プロジェクト作成直後)
プロジェクト作成直後のディレクトリ構成は以下の通り。
プロジェクト作成直後のディレクトリ構成
.
├── README.md
├── angular.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
├── .browserslistrc
├── .editorconfig
├── .gitignore
├── .vscode
| └── (割愛)
├── node_modules
| └── (割愛)
└── src
├── app
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ └── app.module.ts
├── assets
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts
ディレクトリ構成(チュートリアル完了直後)
チュートリアルを進めていくと分かるが、 component
や service
などをAngular CLIで実行するたびに、 app/
配下に乱雑にファイルが生成される。
チュートリアル完了直後のディレクトリ構成
.
├── README.md
├── angular.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
├── .browserslistrc
├── .editorconfig
├── .gitignore
├── .vscode
| └── (割愛)
├── node_modules
| └── (割愛)
└── src
├── app <---------------------------- app配下が凄い事に!これじゃ管理できないよ X-(
│ ├── dashboard
│ │ ├── dashboard.component.css
│ │ ├── dashboard.component.html
│ │ ├── dashboard.component.spec.ts
│ │ └── dashboard.component.ts
│ ├── hero-detail
│ │ ├── hero-detail.component.css
│ │ ├── hero-detail.component.html
│ │ ├── hero-detail.component.spec.ts
│ │ └── hero-detail.component.ts
│ ├── hero-search
│ │ ├── hero-search.component.css
│ │ ├── hero-search.component.html
│ │ ├── hero-search.component.spec.ts
│ │ └── hero-search.component.ts
│ ├── heroes
│ │ ├── heroes.component.css
│ │ ├── heroes.component.html
│ │ ├── heroes.component.spec.ts
│ │ └── heroes.component.ts
│ ├── messages
│ │ ├── messages.component.css
│ │ ├── messages.component.html
│ │ ├── messages.component.spec.ts
│ │ └── messages.component.ts
│ ├── app-routing.module.ts
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── hero.service.spec.ts
│ ├── hero.service.ts
│ ├── hero.ts
│ ├── in-memory-data.service.spec.ts
│ ├── in-memory-data.service.ts
│ ├── message.service.spec.ts
│ ├── message.service.ts
│ └── mock-heroes.ts
├── assets
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts
ディレクトリ構成(MVVM/最終形)
ソース管理していく上でディレクトリ構成は重要だが、ベストプラクティスが存在しない。
ググってみると、以下のような記事が見つかる。
- https://blog.lacolaco.net/2019/07/angular-ngmodule-and-directories/
- https://mya-ake.com/slides/regret-angular-web-app
- https://mattarishitemota.com/?p=510
「ドメイン単位」や「タイプ単位」で分けるように書かれているが、チュートリアルの時点だとそんなものは存在しない。
(いや、存在はしているんだけども、考えたくない)
AngularはMVVMアーキテクチャで構成されるので、そのままディレクトリにしてしまえばよいのでは?
という事で、MVVMに基づいてディレクトリを構成した。
MVVMで再構成したディレクトリ構成
.
├── README.md
├── angular.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
├── .browserslistrc
├── .editorconfig
├── .gitignore
├── .vscode
| └── (割愛)
├── node_modules
| └── (割愛)
└── src
├── app <---------------------------- だいぶ役割が分かりやすくなった :-)
│ ├── app-routing.module.ts
│ ├── app.module.ts
│ ├── view
│ │ ├── app.component.css
│ │ ├── app.component.html
│ │ ├── app.component.spec.ts
│ │ ├── app.component.ts
│ │ ├── dashboard
│ │ │ ├── dashboard.component.css
│ │ │ ├── dashboard.component.html
│ │ │ ├── dashboard.component.spec.ts
│ │ │ └── dashboard.component.ts
│ │ ├── hero-detail
│ │ │ ├── hero-detail.component.css
│ │ │ ├── hero-detail.component.html
│ │ │ ├── hero-detail.component.spec.ts
│ │ │ └── hero-detail.component.ts
│ │ ├── hero-search
│ │ │ ├── hero-search.component.css
│ │ │ ├── hero-search.component.html
│ │ │ ├── hero-search.component.spec.ts
│ │ │ └── hero-search.component.ts
│ │ ├── heroes
│ │ │ ├── heroes.component.css
│ │ │ ├── heroes.component.html
│ │ │ ├── heroes.component.spec.ts
│ │ │ └── heroes.component.ts
│ │ └── messages
│ │ ├── messages.component.css
│ │ ├── messages.component.html
│ │ ├── messages.component.spec.ts
│ │ └── messages.component.ts
│ ├── viewmodel
│ │ ├── hero.service.spec.ts
│ │ ├── hero.service.ts
│ │ ├── in-memory-data.service.spec.ts
│ │ ├── in-memory-data.service.ts
│ │ ├── message.service.spec.ts
│ │ └── message.service.ts
│ └── model
│ ├── hero.ts
│ └── mock-heroes.ts
├── assets
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
└── test.ts
ちなみに、Angular CLIで component
や service
を作ると app/
配下に作られてしまうが、コマンド実行時にフォルダを作る事も可能。
なので、Angular CLIベースでコードをメンテナンスしていく際には、ディレクトリ構成を決めた上で、実行コマンドに制約をつけて運用するとよいと思う。
# これだと app/ 配下に作られるので、管理しづらい
root@c773d67c1823:/projects/app# ng generate component heroes
# これだと app/view/ 配下に作られるので、管理しやすくなる
root@c773d67c1823:/projects/app# ng generate component view/heroes
[POINT] 「spec」って何?
component
や service
をAngular CLIから生成すると、 xxxx.component.spec.ts
なるファイルが生成される。
# component の生成
root@c773d67c1823:/projects/app# ng generate component heroes
Node.js version v19.0.0 detected.
Odd numbered Node.js versions will not enter LTS status and should not be used for production. For more information, please see https://nodejs.org/en/about/releases/.
CREATE src/app/heroes/heroes.component.css (0 bytes)
CREATE src/app/heroes/heroes.component.html (21 bytes)
CREATE src/app/heroes/heroes.component.spec.ts (599 bytes) <---------- なにこれ!!!!!!!!!!!!!!
CREATE src/app/heroes/heroes.component.ts (275 bytes)
UPDATE src/app/app.module.ts (475 bytes)
# service の生成
root@c773d67c1823:/projects/app# ng generate service hero
Node.js version v19.0.0 detected.
Odd numbered Node.js versions will not enter LTS status and should not be used for production. For more information, please see https://nodejs.org/en/about/releases/.
CREATE src/app/hero.service.spec.ts (347 bytes) <---------- なにこれ!!!!!!!!!!!!!!
CREATE src/app/hero.service.ts (133 bytes)
この xxxx.component.spec.ts
はチュートリアル内では使用しない。
使用しないからこそ、何のために生成されているのか意味が分からない。
調べてみると、単体試験実行用のファイルらしい。
以下、公式サイト。
[POINT] component
と service
の違い
先ほどから component
と service
という単語を乱用していたが、そもそもこれらがよく分からない。
調べてみると、公式サイトに以下の記載があった。
以下、公式サイト。
コンポーネントは ビュー を定義します。
ビューは、プログラムのロジックとデータの中からAngularが選択し、変更できる画面要素のセットです。すべてのアプリケーションには、少なくともルートコンポーネントがあります。コンポーネントは、ビューに直接関係しない特定の機能を提供する サービス を使用します。
サービスプロバイダーは、 依存性 としてコンポーネントに 注入 することができ、コードをモジュール化し、再利用可能で効率的にします。
なるほど。ここでMVVMの観点が生きてくる。
サービスがコンポーネントに注入するという事は、これがデータバインディングの仕組みなのだろうと思う。
なので、コンポーネントは View
であり、サービスは ViewModel
に相当する事が分かる。
View
と ViewModel
は分かったけど、 Model
は?
Model
に相当するものは、おそらく ng generate interface {name}
で生成されるものと思われる。
チュートリアル内だと hero.ts
がそれに相当するが、コマンドではなく直接ファイルを作成するため、MVVM的観点だと分かりづらい。
試しに上記のコマンドを実行すると、以下のようにファイルが生成される。
( hero.ts
と同じ構成なので、これが Model
なんだと思う。)
# interface の生成
root@c773d67c1823:/projects/app# ng generate interface model/dummy
Node.js version v19.0.0 detected.
Odd numbered Node.js versions will not enter LTS status and should not be used for production. For more information, please see https://nodejs.org/en/about/releases/.
CREATE src/app/model/dummy.ts (27 bytes)
# ファイルの確認
root@c773d67c1823:/projects/app# cat src/app/model/dummy.ts
export interface Dummy {
}
[POINT] その他
他にも、チュートリアルを進めていく上で、表面上の理解しかできず、使い方がいまいちピンと来ないものがあった。
まあ開発を進めていくうちに慣れていくだろうから、今は「こういうのがあるんだな」程度に留めておく。
- データバインディングには
ngModel
を用いる-
ngModel
を使用するには、FormsModule
のimportが必要 - https://angular.jp/api/forms/NgModel
-
- classバインディングは、以下を参照
- これは特に import が必要などは書かれていない
- https://angular.jp/guide/class-binding
-
*ngFor
と*ngIf
で html を操作 - ルーティングは
./app/app-routing.module.ts
で行われて、<router-outlet>
を使う
チュートリアルを終えて
どうやって構築していくのかは分かったけど、肝心の仕組みだとが概念だとか規約だとかはチュートリアルでは身につかない。
ので、公式サイトの以下を参考に、勉強を進めていく。
- Angularの概念の紹介
- Angularコーディングスタイルガイド
- 用語集