先日の学園祭で友人のオタク達とやきそばを焼いて原価ギリギリで売ったところ予想以上の盛況でした*1。色々と工夫点はあったのですが、その一つとして売上杯数を Web 上で登録してリアルタイムで雑に public internet に公開するという試みをしてみところちょっと盛り上がったため、その経緯を書いていきたいと思います*2。
つくったもの
会計を登録するシステムとその集計結果を表示する Web サイト(+付随する簡単な API)を作りました。フロントエンド側のコードは GitHub 上に公開しています*3。
github.comサイトは以下のページから構成されます。フロントエンドはすべて public になっているため、簡易的な認証として API 側で Authorization ヘッダ内のトークンの有無を検証し、不正なトークンが送付された場合は 401 を返す設計としました*4。
- トークン登録ページ
https://kyogaku.yokohama.dev/admin/token?token=foo - 売上登録ページ
https://kyogaku.yokohama.dev/admin/ - 「現在の売上」ページ
https://kyogaku.yokohama.dev/realtime/
構成としては、みんな大好き Cloudflare(Pages/Workers/D1)上にすべてを載せることでサーバレスで完結します。エッジ上で動くため読み込みも高速で、当日システムが落ちるなんて心配もない……はずだったのですが。
得られた知見等
素の HTML を書くとデプロイが 10 秒で終わる
1990 年の Web 1.0 風サイトを志向していたためフレームワーク等を一切採用しなかったところ、デプロイが超高速に終わるという恩恵にあずかることができました。
最近は Next.js に慣れすぎて、ミニマムなアプリケーションであってもデプロイに数分を要することが必然と考えていましたが、素の HTML + CSS + JS を用いるとビルドという工程が不要になり、なんとデプロイが 10 秒以内に終わります*6! 感動できる! これが真の DX*7です。
北米が停電すればやきそばが売れなくなる
前日から当日に掛けてまさかの Cloudflare の大規模障害に巻き込まれ*8、危うくやきそばが売れなくなるところでした。幸いにも当日朝の時点で Cloudflare Pages のデプロイは動いていたため、即席の API 鯖を Express で建て、Vercel Serverless Functions + Supabase 上で動かすことで事なきを得ました。
操作はボタン 1 つで完結すると便利
当日はどうせ忙しくなることが予見されたため、なるべく簡便な操作で売上登録が完了するようにしました。150 円のやきそばを 1 杯売った場合は、単に「送信(連打禁止)」のボタンをタップするだけです。杯数を誤って登録した場合は、☑打ち消し にチェックを入れて再度送信することでミスがなかったことになります。
複雑なスプレッドシートやどこまで書いたかがわからなくなる正の字とはこれでおさらばです!
遠くからでも見栄えする画像を生成する
「現在の売上」ページでは Canvas で画像を生成しています(ソースコード)。
今回の場合は、「驚額の殿堂 現在の売上」「損益分岐点まで残り 杯」といった部分を予めテンプレートとして用意しておき、その上から装飾済みの数字画像を重畳して出力する仕組みです。Web フォントを使用すると結構読み込みが重くなってしまう傾向にあるため、割り切って画像として用意しておくのも手だと思います*9。
CSS 芸をする手も考えられましたが、1. レスポンシブに対応する気力(と必要性)がなかったこと、2. CSS だとフォント等に制約が掛かってしまうこと、3. 画像をシュッと Twitter 等で共有したかったこと などを理由に画像をクライアント側で合成して掲示することとしました。
おかげさまでよい雙峰祭になりました!ご協力いただいたみなさんありがとうございました。今年も残り 2 ヶ月ですが、どうぞよいお年を〜!
*1:一時は 4 列並びとかになっていてどこの壁サー?という感じだった
*2:最近は学園祭での IT を Zenn 等に書くことが流行っているっぽい
*3:当日の朝に PR が飛んできて胸熱だった
*4:穴だらけですが 2 日間しか使わないので許してほしい
*5:単に Supabase 標準のそれ
*6:CDN のキャッシュは適切に消して上げる必要があります
*7:開発者体験のほう;実際、大抵の場合システムは当日にバグるので hotfix が飛ばしやすくて助かる
*8:D1 とかかなり挙動が怪しかった
*9:それでもまだ重かったため本当は Workers 側で画像を生成して KV 等に突っ込んでおくとよさそう cf. Cloudflare Workers で画像生成