GhostからPayloadへの移行

ブログのCMSをGhostからPayloadに移行した。セルフホスティングしていたGhostの出来自体に不満があったわけではない。機能としては十分であったがVPSの管理が面倒であった。VPSも、もはやブログのためだけに存在しているものであり、更新頻度の低いブログのためだけに維持しているのが勿体なかった。

Payloadでは管理画面やAPIがNext.jsで構成されているが、OpenNextを噛ますことでCloudflareでホスティングできる(公式のテンプレートがそうなっている)。このCMSではコレクションと呼ばれる単位でスキーマを定義・管理する。それらの定義はソースコードを編集して反映するというコードファーストな設計だ。ものとしてはより知られているであろうStrapiに近い。Strapiも一時期別の用途で運用を考えたこともあったが、Ghost同様VPSなどでのセルフホスティングが必要なため結局使わずじまいで終わってしまった。そういった管理の手間から逃れられるのが採用した理由の一つ。もう一つは単に興味。

コードファースト設計である以上、立ち上げが手間であることは避けられないが今はAI時代なのでその辺はどうとでもなった。今回はGhostからの移行ということもあったのでベースのスキーマはそちらに倣いつつ不要な部分は削り、よりシンプルな形に仕上げた。

とはいえCloudflareでのPayload運用も完璧ではない。

例えばアップロードした画像のリサイズ処理などを走らせたい場合はsharpというパッケージが必要で、これがCloudflareだとネイティブバイナリ依存の関係上うまく動かすことができない。なので画像のリサイズや最適化処理といったものはCloudflare Imagesなどを使う必要がある。このブログでは必要ないと判断して省いた。

また、サーバーレス環境である関係上、常駐プロセスを持てないのでジョブキューを実行する契機がなく、予約投稿のような処理は別途なんとかする必要があったりなどする。これに関してはPayload側が外部からキューを消化するためのエンドポイントを持っている。このブログではCloudflare WorkersのCronを使ってポーリング処理することで常駐スケジューラを擬似的に再現する手法を採用した。

他にも、そもそもPayloadのバンドルをWorker上に展開しようにもサイズが大きすぎて無料枠の上限を超えてしまうのでWorkers Paidプランを契約する必要があるなどなど…。

DBについてはGhost時代はVPS上にDBサーバーを立てていたが、今回Payloadを使うにあたってTursoと呼ばれるSQLiteベースのSaaSを使うことにした。速さについては遅くなければよく、趣味では十分すぎるレベルの範囲を無料で使えるというのが理由だ。この構成でサーバーの管理からは完全に逃れられる。

料金的にはVPS代(660円/月)がWorkers Paid($5.00, 800円ちょい/月)に移った形。Cloudflare Workersで動かせるものは限られるが、とはいえVPSで何か展開するよりかはよほど楽なので他所でも有料枠を有効活用していきたいところだ。

VPSの管理に比べたらはるかに楽で今のところ感触が良い。

フロントエンドに関してはVercel上のNext.jsからCloudflare WorkersのHono/HonoXに移行した。SSGしたものをWorkersの静的アセットを使って展開している。HonoXを使ったのは技術的興味という部分も大いにあるが、単にNext.jsに飽きたというのと、ブログ程度にNext.jsを使うのが大げさだからという理由もある(とはいえ結局PayloadがNext.jsではあるが)。

最近はブログごときにあまりゴテゴテとした成果物を作りたくない・Next.jsの暗黙的な挙動に振り回されたくない・Webの原点に立ち返りたいなどといった理由で、できるだけ透明性の高いフレームワーク下でHTMLを生成するようにしたいという気持ちが強かった。クライアントサイドナビゲーションがなくても純粋なHTMLだけのページであれば十分速いし、View Transitions APIも活用することでページ遷移もクライアントサイドナビゲーションと遜色ない体験ができる。Next.js時代は完全な静的なページでもJSコードとして本文が組み込まれていたのが気になっていたが、それもなくなり、よりクリーンなものが生成されるようになった。

この移行に伴って、ブログのデザインも少し更新した。以前はブログのカバー画像やアイキャッチ画像を上部にデカデカと表示していたが、これをやめ、トップページからはカバー画像をなくし、アイキャッチを設定している記事は記事の幅と同じ幅で表示する程度に留めた。