LoginSignup
16
1

𝓗𝓪𝓹𝓹𝔂 𝓜𝓮𝓻𝓻𝔂 𝓒𝓱𝓻𝓲𝓼𝓽𝓶𝓪𝓼...

Last updated at Posted at 2023-12-24

本記事は Angular Advent Calendar 2023 の24日目の記事です❗

23日目は@ic_lifewoodさんで25日目は@lacolacoさんです❗


最新のAngularの機能をふんだんに使って、
Angular Advent Calendarの記事をツリーの飾り(オーナメント)にしたサイトをつくりました❗❗

20231224234656.png

あまりおもしろみのあるサイトではないかもしれませんが、
「見た目から要件がすぐにわかる」ことを目指して作成しました。

他の方のAdvent Calendar記事に言及しつつ、実装の詳細を解説していきますので、
実際に触りながら読み進めていただければと思います❗

他の記事で言及されていた実装

Prettier & ESLint

Angularを入れたら最初に設定しておきたい、リンターとフォーマッタの設定です。

次のコマンドで導入したあと、生成された.eslintrc.jsonを編集しました。

$ npm i -D prettier eslint-plugin-prettier eslint-config-prettier
$ # commit
$ ng add @angular-eslint/schematics 

基本的に、最新のrecommendedな設定を使いたいニンゲンなので、
prettierとの共存のための設定以外ルールの変更などは特に行っていません。
(「アップデートのたびにルールの名前や設定ファイルの構造が変わったことを検知するのが難しくて嫌じゃない?」という気持ちがある)

しかし、有用なオプトインルールはたくさんあるので、導入の際は都度一考することをお勧めします。

Angular CDK

普通にWebサイトを作成すると、CDKの使いどころは結構多いのですが、今回はダイアログの作成のみに利用しています。

20231225011120.png

UI面は非常に薄いですが、反してアクセシビリティなどのサポートなどは手厚く、
実装の際は積極的に利用したいライブラリですね。
(この画面を見ただけでも「モーダルを開いたときに、UI上の最初の要素にフォーカスを当てる」粋なアクセシビリティポイントが嬉しい)

ちなみに、Dialogは内部的に利用しているOverlayなどが、
専用のCSSを読み込まないとなんのスタイルも当てられていない状態になるので、
次の一行をstyles.cssに書いておきましょう。

@import '@angular/cdk/overlay-prebuilt.css';

なぜかDialogのDocumentにはこのことが記載されていません。

CDK Dialogについて、より詳しい説明は次の記事をどうぞ。

NgOptimizedImage

「開発者があまり意識しなくても画像表示を最適化してくれるくん」です。

適当に使ってみると(NgOptimizedImageをimportしてimgタグのsrcをngSrcにするだけ)、
実行時に警告を出してくれるので、対話的に実装できます。

より詳しい説明は次の記事をどうぞ。

ngSrcを記述する際はルートから始まるパスを書かないように注意!

assetsディレクトリに入れている画像を参照するために
/assets/xxx.pngなどと書くと、build時にbase-hrefを設定している場合
パスの解決ができなくなってしまうため、
assets/xxx.png./assets/xxx.pngのように書く必要がある。

筆者はデプロイ時に画像が読み込まれない自体に陥って少しだけハマりました😢

SSG(SSR)

v17からはServer Side Generation(Rendering)がヒッッジョ〜に簡単になりました❗

プロジェクト作成時、対話的にssrサポートをONにするか聞かれるので、
ここで有効化したあとはnpm run buildでSSGの生成物が作成されます。

本サイトではSSRオプションをオンにしてGitHub Pagesにデプロイしているので、
すでに一度レンダリングされた結果が返ってくるようになっています。

背景のパーティクルの位置やオーナメントの色がランダムで変わるようになっているので、
JSをオフにした状態でページのリロードを走らせると違いが分かりやすいです。

他にもSSRについて、次の記事でそれぞれ詳しく書かれています。

SSGを利用した外部リソースのキャッシング

今回、オーナメントを表示するために、アプリ内のHttpClientでQiitaのRSSフィードから記事情報を25個取得しています。

ところが、実際にブラウザを更新すると、該当の通信は走りません。

What’s next for Server Side Rendering in Angularの記事によれば、

We’ve also made some updates to HttpClient. It will now cache requests made on the server to avoid re-fetching that same data again on the client.

とのことなので、どうやらSSRモードを有効にするとデフォルトでいい感じにキャッシュしてくれるようです!ス、スゲーー!!!

本サイトではmainブランチへのpush時に、GitHub ActionsのCI上でビルドが走るので、
このタイミングで通信情報が永続化されるわけですね。

Control Flow

ココ最近のアップデートでは大目玉商品ということで話題のControl Flowですが、
Advent Calendarでもやはりみなさん言及されていて、注目度が伺えます。

本サイトでも早速使ってみました。

switch文なんかはかなりシンプルで適切な感じの書き方ができている気持ちになっていいですね。
trackByも非常に書きやすいです。

……ただ、ControlFlowの導入によってhtml内に@記号が使えなくなった点について、
これを解決するための参照文字列を調査するのに少しハマりました。

もともとこの事象自体は知識として知っていたのですが、
「参照文字列」という言葉が頭に出てこなくて
アットマークの参照体(@)が調べられず……。

アットマークはテンプレートに書くとコンパイルエラーが出るのですが、
ブレースの直前に書いてしまい、構文のパースが影響して
次のようなエラー内容になってしまい、適切な対応方法がしばらくわかりませんでした😢。

|6 col 51 error| ngtsc:Error:-995002:Unrecognized block @.
|14 col 6 error| ngtsc:Error:-995002:Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)
|14 col 6 error| ngtsc:Error:-995002:Invalid ICU message. Missing '}'.
|6 col 51 error| ngtsc:Error:-995002:Unclosed block ""

比較的何もない箇所に@を記述した場合は、次のようなエラーが出て対応方法がわかりやすいみたいです。

|1 col 1 error| ngtsc:Error:-995002:Unrecognized block @.
|1 col 1 error| ngtsc:Error:-995002:Incomplete block "". If you meant to write the @ character, you should use the "@" HTML entity instead.

新しい@Inputデコレータのオプション

地味に嬉しいInputのオプション機能、早速使ってみました❗
古いバージョンのAngularを使っていると「新しいInputなら……」と思うことが多々あるんですよね。

単純ですが非常に強力なAPIだと思います。

他の記事であまり言及されていない実装・小技

SVG

今回、イラストみたいなUIを実装するにあたって、SVGを多用することにしました。
こういったサイトの構築だと、
SVGによる実装がDOMのセマンティクスを汚さない気がしててスキなんですよね……。
(「イラストの中のクリスマスツリーの星」を表すタグとかにdivを使いたくない)

ただし、SVGによる実装は基本的に座標の絶対指定になってしまうので、
そこは賢くやらないといけませんね。

現在はコードの中に多くのマジックナンバーがあるので、これを除去していくのは課題です。
Angular Pipeとか使うといいかもしれません

新しいAngularとの相性についてですが、使い心地は昔と変わらずというところでした。
Control Flowなどで問題が起きるかなと不安でしたが、
案外すんなりと進めることができました💮。

GitHub Pagesへのホスティング

筆者は結構GitHub ActionsをつかってGitHub Pagesにホスティングしているのですが、
今回はここで結構詰まってしまいました……。

結論的には、Settings > Actions > General > Workflow permissionsの権限が弱かったことが問題でした。

今までここを触ったことなかったんで、最近デフォルト設定が弱くなったんですかね。

ちなみに、あまり凝っていないのですがGitHub Pagesにデプロイするワークフローの変更はこんな感じです。

ポイント

  • actions用のymlを書く
    • 今回はpeaceiris/actions-gh-pages@v3を利用
    • publish_dirにはSSGで生成されるビルド結果の場所を指定する
      • Angular CLIで普通に作成した場合.dist/APP_ID/browserのパスを指定してやるといい
  • buildコマンドで--base-hrefを設定してやる
    • ちゃんとやるならenvrionment.tsとかでいい感じにやるのかな?
    • ngSrcの絶対パスには気をつける
  • Settings > Pages > Build and deploymentの設定を適切に変更する
    • Source: Deployment from a branch
    • Branch: gh-pages / (root)

Signal API

一部ですが、Signal APIによる実装を頑張ってみました……❗

案外、今回はSignal APIを主軸としたAdvent Calendarの記事はありませんでしたので、
@lacolacoさんの次の記事にあるSimple PDSパターンを参考にして組んでみてます。

実際に実装してみると、なるほどしっくりくるカモ…… いい感じです🚥。
この辺はコメントも厚めに書いてるので、ぜひコードの方をご覧ください❗

時間がなくて実装が間に合わなかったけど盛り込みたかったやつ

ルーティング(View Transitions API)

当初は記事の詳細表示をダイアログではなく、ルーティングを利用して表示しようとしていました。

この時の遷移にView Transitions APIを利用したかったのですが……。
UI的に遷移を踏まえたアイディアがパパっと出てこず、工数的に見送りました😢。

Deferrable views

クライアントでの動的な取得が行えれば@deferとかの出番がありそうなので使用するつもりだったのですが、
いざ実装してみると、本アプリでは基本的に通信にリアルタイム性が求められません。

SSGが勝手に通信をキャッシュするため遅延読み込みの必要がありませんでした😽。

テスト/CI周り

npm run testは通るようにしていますが、カバレッジはほぼ0みたいなもんなので、もう少し何かしら書いてあげたい。
あと、とりあえずテストの自動化とprettier/eslintのチェックをCIで動かしたいですね。

CSP_NONCEによるCSSインジェクション対策

ウオオこれ完全に知りませんでした……。
非常に簡単なので、基本的には意識して有効にするようにしたいですね。

あとがき

Advent Calendarに登録してすぐに「SSGを利用したブツを作って、他の人の記事を全部読んで関連してそうなやつをリファレンスしていく」という指針をたてたのですが、
実装の着手を先送りにしまくった結果、24日当日に泣きながら全部実装することになりました……。

しかしながら……
逆に言えば1日でそれっぽいアプリがほぼフルスクラッチでできたのはなかなかの成果ではないでしょうか❓

しかも工数のうち半分以上はWebデザインとSVGの作成に費やしているわけですから、Angularの生産力は驚かされますね💪

キリの良いところまでは進めましたが、時間がなくて実装が間に合わなかったけど盛り込みたかったやつがたくさんあるように、まだ色々課題を残しています。
Issueなどは整備していませんが、どこかで改修していけたらいいなと思います。(PRも歓迎)

それではみなさま、𝓗𝓪𝓹𝓹𝔂 𝓜𝓮𝓻𝓻𝔂 𝓒𝓱𝓻𝓲𝓼𝓽𝓶𝓪𝓼...💫

16
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
1