エンジニアが出演する (音楽の) ライブイベントを企画したので、そのためのウェブサイトを作りました。
これで利用したシステム構成が、短時間でそこそこ使いやすいサイトを作るのに使い回しの効きそうなものだと思うので紹介します。
エンジニアライブを支える技術
タイトルのまんまですが、技術スタック的な視点では以下の組み合わせで構築しています。
- React
- Netlify
- GitHub
- GraphQL
- TypeScript
React + Netlify
まずサイトを手早く作るために create-react-app のテンプレートを元に SPA で画面を作っていきました。
- トップページ
- 出演者一覧ページ
- 出演者詳細ページ
- ニュース一覧ページ
- ニュース詳細ページ
というシンプルな画面構成なので React を使えば (デザインは置いといて) 速攻で作れました。最終的にはペライチみたいなサイトでいいかなと思って出演者/ニュース一覧ページは無くしてしまいましたが。
しかしここで特に「支える技術」として伝えたいのは Netlify のお手軽さで、Netlify を使うことで
- GitHub のブランチに更新を push したら CI でデプロイ
- SPA リロード時の404対策
- SPA の OGP 対策のための pre-rendering
などを他の外部ツールに頼ることなく Netlify のみで一瞬で実現することができました。特に最後のものは、今回のエンジニアライブサイトのように各ページを LP としてシェアしてもらいたいようなサイトを SPA で構築するときに頭が痛い点の1つだと思うので、これがお手軽なのはかなりありがたかったです。
そして小規模なウェブサイトであればフリープランで使えますし、うーん、とにかく良い…
GitHub issues as CMS
サイトを更新していく方法は色々ありますが、参加者の大半がソフトウェアエンジニアということで、GitHub の issues に記事などをポストするとそれがサイトのコンテンツに反映されるようにしました。
エンジニアライブのサイトでは、定期的に更新されるコンテンツとして
- ニュース (お知らせや出演者の活動レポートなど)
- 出演者情報
の2つのカテゴリのページがあります。
それぞれ、普通に GitHub の issue として内容を書いたらそれに post
や lineup
のラベルをつけると、対応するカテゴリのページとして実際にサイトに表示される仕組みにしました。フロントエンド側はリアルタイムに情報を GitHub から取得するので、GitHub 側でラベルを付けた issue を作成または更新すると即座にサイトにも反映されます。
例えばニュースカテゴリのページを作りたかったら以下のように post
ラベルをつけます。
GitHub を CMS として使うことで、普段使っているものと全く同じ感覚で markdown でコンテンツを入稿できて、ユーザー管理なども GitHub のものをそのまま使うことができるのが楽なところです。
例えば「出演者情報ページでは写真が欲しい」といった理由から内容に一部レギュレーションを規定する必要はありましたが (必ず画像を入れてねみたいな) 、基本的には issue から取得した HTML をそのまま埋め込むだけなので markdown で表現可能などんな内容でも書くことができます。
ただし、YouTube 動画を埋め込みたい要件があり、それがどうしても実現できなかったためにショートコード機能を追加しています。ショートコードというのは Hugo や WordPress にある機能で、特定の文法規則にしたがって記載しておくとそれが決まった形の HTML に展開されます。
具体的には、issue 本文に
youtube xxxxxxx
と書いておくと (xxxxxxx
は YouTube の動画 ID) 、それがサイト上では iframe の埋め込み動画として表示されるというものです。多少強引ですが、これはフロントエンド側で直接取得した HTML 文字列を変換することで対処しました。
GraphQL
GitHub issues からのコンテンツデータの取得には GraphQL を使いました。
REST API でも同じことはできますが、GraphQL を使うことで、シンプルな GET だけならほとんど API リファレンスなどを見なくても「必要な情報を必要なだけ得る」ためのクエリがすぐに書けるのはサッサと作りたい場面ではかなりありがたいです。今回のような「post
ラベルがついた issue だけ取得したい」といった仕様を満たすのも簡単です。
また、特筆すべき点として、GitHub は GraphQL Explorer という GraphQL フロントエンド (GraphiQL) を用意してくれています。GraphiQL を使ったことがある方はわかると思うのですが、これが IDE 的な補完やドキュメント参照もその場でできる大変素晴らしく便利なやつです。
前述した「ほとんど API リファレンスを見なくても…」というのにはこの GraphQL Explorer の存在が大きいです。
GraphQL のクライアントには Apollo を使いました。今回、実は最初に JavaScript で開発していたのを後から一気に TypeScript に書き換えたのですが、そのときも react-apollo を使っていると型定義の追加が簡単にできて型付けのための書き変えを難なく完了することができました。
TypeScript
前節でも書いた通り、最初は JavaScript で開発をスタートしました。理由は単純で「JS をそのまま使う方が開発速度はきっと速いだろう」というものでした。
が、最終的にはすべてを TypeScript で書き直しました。確かに JS の方がコード量は少なくなるのですが、開発中に結局 props を意識しないといけなくてそれがすぐにわからなくて悩むことや、静的型付けの方が結果的に細かいバグが減って開発効率も良かったためです。
特に VSCode などの IDE 的なサポートが強いエディタで開発する場合には、TS の導入に大きな障害がないのであれば、ごく小規模なサイトを高速開発したいような場面でも最初から TS を使った方が良いかもしれません。
まとめ
実は、一番最初はこのサイトの作るのに自分の趣味を優先して Swift の Web Application Framework である Vapor を使ってフルスタックで作っていたのですが、やっぱり色々時間がかかってしまったので、実益を取って React SPA + バックエンド CMS に切り替えた背景があります。React を用いて静的サイトになったことで Netlify を利用することもできたため、結果的には CI などの開発フローも含めて全体的な開発効率を大きく高めることができて正解でした。
ただ、今回のようなシンプルな構成の場合に柔軟で高速な開発を行うには、どちらかというとバックエンドにこだわるよりはフロントエンドをデータ層と分離できていることが大事で、その上で適切に抽象化されたバックエンドとのインターフェースがあって楽に取り替えがきくことが重要であると感じています。
そういう点で、コンテンツを更新していく仕組みは別になんでもいいと考えていて、GitHub じゃなくても NetlifyCMS や Contentful などのマネージドな Headless CMS を使ってもよいし、別にプレーンテキストのファイルでもクラウドストレージでも、手軽に更新できるものならなんでもよいでしょう。この辺りを突き詰めていくとプラガブルにデータソースを選択できる GatsbyJS を使うのが思想的にはマッチする気がしてきますが、記事更新のたびに静的サイトをビルドするのがちょっと面倒で今回は使いませんでした。
まあ、今回高速開発が求められた理由というのが、単純にイベントそのものの準備もあってあんまり周りのシステムに時間をかけたくなかったことがありますので、もし次回があればせっかくの機会なのでもっと趣味を全開にして作ってみたいなと思います。とはいえ、躊躇なく CSS Grid Layout を使ったりできたのでストレス解消にはなりましたが…
Lighthouse のスコアも、Web フォント使ってるところでパフォーマンスだけ満点取れなかったけどまあ十分かな。
最後に宣伝になりますが、エンジニアライブは **11/25 (日) に「真昼の月・夜の太陽」**で開催します。僕は band.rb というグループで出演します。他にもエンジニアとして活躍中の方が多数出演するので、興味のある方は以下のページより参加をご登録ください!