↔️

スケーラビリティ皆無の自作ゲーム公開サイトをスケーラブルにする話

2024/12/21に公開

はじめに

先月「春日部つくし[1]という VTuber のファンメイドゲームとそれを公開するためのウェブサイトを作った。

https://saitube-saitama.web.app/

最近、また新しいファンゲームのアイデアを思いついたのだが、問題はこのウェブサイトが静的サイトであり、またルーティングすらもやっていないため、新しいゲームを置こうにも置けない。
それ以外にもスケーラビリティにおいて色々問題があるため、改修することにした。

その上でやったことをいくつかの技術記事に分けて書いたが、本記事はそれらを一つに繋げるモチベーション(とこぼれ話)を語るためのものである。個人開発のため、企業レベルで通用する構成や技術かは保証できないが、参考程度に読んでくれれば幸いである。

スケーラビリティ皆無という問題

最初にデプロイしたものはただ一つのゲームをホスティングする単純な静的サイトである。それゆえにさまざまな問題が出てきた。

ルーティングが実装されてない

React で構築されたサイトであり、Single Page Application (SPA) である。なのでルーティング用のライブラリを導入していなければ、そもそも複数のページを用意するのは難しい。新しいゲームをサイト内に置こうにも置けない。

Unity のビルドとサイトのデプロイが同じ

静的サイトなのですべて一緒にデプロイする必要がある。Unity のビルドが変わっても全てのコンテンツをデプロイするし、サイトの内容が変わっても全てのコンテンツをデプロイする。

ちょっとした変更が面倒

サイトを見ていただければわかるのだが、サイトは YouTube のような構成になっており、投稿者コメント欄のようなものがある。こういった要素は React のコンポーネントに対して直書きだったので、文言を修正するたびにサイト自体のビルド・デプロイが必要になっていた。

ホスティングサービスのデータ転送量の無料枠を超過する

ホスティングする場所として選んだのは、とりあえずクレジットカード登録もなしで始められる Firebase の Firebase Hosting というサービスである。[2]
Firebase Hosting の無料枠(Spark プラン)はストレージとデータ転送量に上限が与えられており、以下のようになっている。(※2024年12月時点)

項目 無料枠
ストレージ 10 GB
データ転送量 360 MB/日 (※約10 GB/月)

https://firebase.google.com/pricing?hl=ja

これは個人の普通のサイトであればそこまで気にする必要のない上限値だと思うが、今回のサイトは Unity のビルドファイルたちもホストしていることが問題になる。
Unity からビルドされて出てきた成果物はだいたい 80 MB ほどあり、ストレージはともかくデータ転送量がかなり厳しい。一日 5 人サイトに訪れただけで無料枠を突き破ることになる。[3]

サイトのリリース日当日は普通に無料枠上限を突破した。これを見越して事前に従量課金制(Blaze プラン)に移行し、Google Cloud の無料トライアルを利用して実際の課金までは至らなかったものの、それでもすぐに無料枠上限を超過することがわかった。

一つの Unity アプリのリリース(しかも知名度ほぼゼロ!)でこの上限を突破するのだから、複数のアプリを配信しようと思ったらこのままの運用は厳しそうである。また、今後新たにゲームを追加するときは必ず発生するということがわかる。

今回サイトを改修しようと思った大きな理由の一つはこの問題の解決であり、結果としてスケーラブルになった、が正しい理解かもしれない。

攻撃の対策が難しい

別に知名度はないのでサイトを攻撃される心配はあまりしていないが、上記の無料枠超過がしやすい状況において、仮に何度も(機械的に)サイトを更新されまくると簡単に課金額が膨れ上がる。
また、Firebase Hosting 自体にはどうやらファイアウォールが存在しないようである。まあ、サイト自体の HTML や JavaScript 等はまだしも Unity アプリはさすがに保護しなければならない。

https://zenn.dev/singularity/articles/firebase-security

解決するためにやったこと

こういったさまざまな問題を解決するために、具体的には以下のようなことを行なった。

  1. TanStack Router を使ってサイトにルーティングを導入した。
  2. Cloud Storage や Firestore を利用して、制作したゲームとウェブサイトのデプロイを分離した。
  3. Cloud Storage から Unity のビルドファイルを獲得・表示した。

それぞれの内容を含んだ技術的な話はそれぞれ別の記事として書いているので、各セクションに入ったら記事を紹介する。

ちなみに、これらは説明上順序立てているが、実際にはほぼ同時並行して作業している。それぞれの仕様や使い方を決定するのに、他の要素が絡み合っているからである。

1. TanStack Router の導入

まず、根本的な問題としてルーティングの実装がなければ、拡大可能なサイトとして運用するのは難しい。手始めに TanStack Router を導入することにした。
選定理由は単に触ってみたかったからである。もともと React Router を使ったことがあるのだが、もうちょっとシンプルなルーティングを求めて使ってみたかった。

https://zenn.dev/aishift/articles/f5469d88ea1c53

ただ、2024年12月時点であまり TanStack Router についての記事が多くみられなかったこと、そしてすでに静的サイトとして作られたものがあるところに TanStack Router を導入するような記事はなかったので以下の記事を書いた。

https://zenn.dev/huyu_kotori/articles/2024-12-12-1-tanstack-router

最終的に手順さえわかれば難しくも何ともないわけだが、この手順も仕様もわからない中で TanStack Router を途中から導入するのはちょっと大変だった。どれを変えて、どれを変えなくて良いのかわからないのがしんどかった。

2. Cloud Storage や Firestore を利用して、制作したゲームとウェブサイトのデプロイを分離

Unity のビルド成果物を静的な場所(publicディレクトリなど)に置かずに管理するためには、そもそも Cloud Storage (for Firebase) 上に成果物を置く必要があった。
Cloud Storage で管理する方がメリットが大きく、データ転送に関する無料枠上限[4]が Firebase Hosting よりも以下のようにかなり緩和される。

項目 無料枠
ストレージ 5 GB
データ転送量 100 GB/月
アップロード回数 5,000 回/月
ダウンロード回数 50,000 回/月

回数にも無料枠上限が指定されているものの、そこまで発生しない or 発生しても従量課金のペースはそこまで大きくないと思われたので、少なくとも静的にホストするよりかはだいぶマシである。

じゃあ Cloud Storage に Unity のビルド成果物をどうやって配置するの、という話になり、その結果フロントエンドの開発環境から Cloud Storage にアップロードするようなスクリプトを書くことになった。具体的な実装方法は以下の記事にまとめた。

https://zenn.dev/huyu_kotori/articles/2024-12-12-2-cli-with-firebase-admin-sdk

ここまでくると、そもそもゲームに関連する情報(投稿者コメントとか)もサイトと分離しておきたくなる。そういった情報を Firestore とかにデータとして置いておけば、サイトと Unity アプリで完全にデプロイを分離することができる。こうして動的サイトの道筋が見えてきた。

余談

このあたりでコンテンツのキャッシュ(CDN)はどうするのかを考えだした。こういったことを考え始めると、ホスティングするだけなら Firebase でいいが、初めからそういった構成を求められる AWS とかが結構合理的なんだなと思い始めた。(※ S3 + Cloud Front が、AWS でサイトをホスティングする最低限の構成という個人的な認識。)

ちなみに、CDN の利用は今回の改修では見送った。

3. Cloud Storage から Unity のビルドファイルを獲得・表示

以前に Unity のアプリをどうやって React で表示するかという記事を書いたことがある。

https://zenn.dev/takanari_dev/articles/2024-01-14-deploy-unity-webgl

そのため、そのコンポーネントを使い回して静的サイトを構築していた。しかし、上の記事では静的なところに Unity のビルドファイルが置かれる想定なので、Cloud Storage 上からどうやって取ってくるかがわからなかった。
また App Check を通した時にどうなるのかもわからない状態だった。

ここが今回の改修の最難関である。
これをやるためには以下の点についてしっかり整理・理解する必要があった。

1. ウェブに対する理解

  • CORS ポリシーとは何か。

2. Firebase のサービスに対する理解

  • App Check は何者か。
  • App Check を通して Cloud Storage からどのようにコンテンツをダウンロードするか。
  • Firebase SDK のgetDownloadURLが何をやっていて、どういう URL を取得するのか。
  • セキュリティルールとは何か。

3. react-unity-webglに対する理解

  • 結局何をやっているのか。
  • そもそも Unity のビルド成果物たちは何者なのか。

4. React に対する理解

  • コンポーネントの外にどうやって関数や値を出すのか。
  • useImperativeHandle, forwardRef, useEffectは何者か。
  • どういった場面でこれらを使って良いのか。
  • React v19 リリースによる変更内容。

特に Cloud Storage から「ファイルの獲得可能な URL」を発行してもらう必要があり、ファイルへの URL が存在しない待機時間があることで React のコンポーネント構成に大きな改変が求められた。
これについては技術記事としてまとめたので、気になる場合は以下の記事を読んでほしい。

https://zenn.dev/huyu_kotori/articles/2024-12-12-3-unity-with-cloud-storage

なお、Cloud Storage for Firebase や App Check を利用するまででも大変で、結構調べながらやったので、これも別の記事にまとめられたらなと思っている。

終わりに

とりあえず何とか改修作業が終わり、一安心である。執筆時点ではたった 1 ページしかないので無駄に動的サイトになっているが、この改修が無駄にならないように、今後コンテンツを増やしていきたい。

それと、この改修作業を進めていく上で ChatGPT を結構活用した。しかし、例えば Firebase CLI でできることを聞くと、間違ったことを教えてきたりして困ることも多々あった。便利だが、ちゃんと理解することもやっぱり必要だなと思った。

脚注
  1. 埼玉バーチャル観光大使であり、3Dモデルも自作する技術つよつよ埼玉ギャル VTuber。VOICEVOX春日部つむぎの声をやっている。 ↩︎

  2. 選定理由はすでに使ったことがあるのと、ただホスティングするだけなら手軽にできること。 ↩︎

  3. もちろんそれ以上訪れているようだが、それは Unity のロードが重くて去っていった人・一度サイトに訪れたことがありキャッシュ済みの人とかがいるためである。 ↩︎

  4. Spark プランでは利用できず、Blaze プランでないと使えないと思われるが、無料枠は存在する。 ↩︎

不遊小鳥

Discussion