Node.js, Vite, Cloud Runで動かす個人開発用小規模アプリテンプレート
はじめに
最近自分用のアプリを作るのに以下のテンプレートを使っているのでその解説です。
このテンプレートで作ったものたち
- 自分だけが見るActivityPubサーバー(壁打ち用Twitter)
- 自分用の家計簿のアプリ
- 自分が所属するGitHub Teams内で作られたPRを集めて解析して週ごとにレポートみたいなのを出してくれるやつ
- Reactで画像のアップロードをいい感じにやるみたいなコードを書きたくてPoC的なものをシュッと生やしたやつ
ということで基本的にユーザーがごく少なく、スケールする必要のないようなアプリを作るのに適したテンプレートです。
コンセプト
安い
運用コストが低い
雑にアプリを生やせる
Cloud Run(とlitestream)はいいぞ
ということで、このテンプレートで作ったアプリはCloud Runを使っていてしかもそれ単体(Cloud Runのインスタンス1つ)で全て完結しています。
Cloud Runはアクセスがなければ勝手にインスタンスを落とす機能があるため、頻繁に使うようなものがなければ放置しておいても課金されません。これは素晴らしい機能ですね。
DB部分はSQLite + Litestreamにして、定期的にGCSにSQLiteのファイルをバックアップしつつCloud Runの中に全て抱えることにしています。また、バックエンドもフロントエンドもJSで1プロセスでまとめてしまうので、ビルドした成果物をDockerにいれてCloud Runにおいて終了です。消したくなったらCloud Run潰すだけです。簡単。
バックエンドの話
フロントとバックを両方JS(TS)でかけると嬉しいということでNode.jsを採用しています。
expressがなんとなく面白みに欠けるなあという気持ちでKoa使ってますが、そんなに変わらないですね。
ORMはまあなんでもいいと思いますが私はTypeORMを使うことが多いです。
注意としてはreflect-metadataを利用するライブラリを使う場合、esbuildだと動かないです。そのためtsxを使いたい気持ちを抑えてts-nodeを入れています。
テストはなんでもいいと思いますがmochaとか使ったりします(Jestはあまり好きではない)。vitestも気になってるけど、バックエンドはviteじゃないしな…どうだろみたいな(使ったことはないです)
フロントエンドの話
早いのでViteです。
CSSはemotionを使っています。
eslintとprettierは個人的にしっくりくる設定を入れてあります。
PWAはvite-plugin-pwa入れれば一発なので簡単で良いです。
また、認証は主に楽なのでFirebase Authを使っています。AuthのためだけにFirebaseを使っていると言っても過言ではないですね。
Firebase Authは便利ですが、外部公開する時はサービスアカウントをそれ用のやつを発行してちゃんとAPIを制限するなどやった方が良いですね。
Routingが意外とめんどくさい (開発環境と本番環境が違うとつらい)
本番用にstatic serveするやつを入れてますが開発時にはViteのproxy機能を使うのが良いかも。
想定としては、APIは /api
にいれて /
はvite側に渡すのが一番簡単です。逆に /
をバックエンドで制御して /web
をviteに渡す場合、静的アセットの設定とかserveの設定を真面目にやらないといけない上にdevとprodで話が変わる(正確には、devはdevServerの都合があるのでその辺がややこしい)ので結構しんどいと思います。
以前ActivityPubのサーバーを立てる時にAPIの都合上これをやって結構面倒でした。
この辺のつらさはやはり開発環境と本番環境の差異に起因するつらさなのであまり良い解決方法はないと思います。
バンドラーどうしよう問題 (開発環境と本番環境が違うとつらいその2)
また、少し違いますが開発環境は即時リロードしたいなどの関係でts-node、本番環境はtscでコンパイルしていますが、その関係で例えば何かpathの解決に影響を与えるようなツールを入れたくなった時にts-nodeとtscの両方で動くものを探さないといけないという問題があります。
この辺は適当にバンドラーを入れてそれに全て任せるが正解だと思いますが、あまりテンプレートを複雑怪奇にしたくなく、薄いバンドラーで何かいいのないのかな〜と思いながら決めあぐねています。
(皆さんはそういう場合はおとなしくwebpackを使ってください)
その他やってみたいこと
最近はdenoが気になっているのでバックエンドをdenoにしたバージョンも作ってみようかななどと思っています
あと、せっかくフロントとバックエンドを一つのプロセスに入れるならSSR対応とかやっても面白そうとか思っています。
とはいえ上記の個人開発でごく少人数しか使わないという要件からくるモチベではないので完全にやりたいだけですが…
スケールはしません(それはそう)
Cloud Runの1プロセスに全てを埋め込む思想なので、全くスケールしません。インスタンスを2台にしたいのであれば最低限SQLiteはインスタンス内部に抱えずに剥がす必要があります。(これやるならSQLiteのメリットはあまりなさそう)
DBを剥がしたら、とりあえずアプリサーバー部分はインスタンスを増やせますがロードバランサーを前に建てる必要が出てきます。
また、ある程度アクセスがありそうならフロントの部分はCDN込みのホスティングサービス(VercelとかNetlifyとか)にのせて切り離した方がいいですね。
こういうフレームワーク?Scaffoldingツール?が欲しい
CLIでぽちぽち言語とかフレームワークとかライブラリとかどこのクラウドに載せるかとかそういうのを選ぶと上記のようなテンプレートが展開されるツールが欲しすぎるよなという感情になっています
(実際に作ろうとしたけどテンプレートを用意するの結構しんどそうだったので諦めてしまった)
終わりに
特にPRなどは歓迎していませんが、人々もぜひこういうopinionatedなテンプレートを作って発表するなどしてくれたら嬉しいなと思っています
Discussion