既存 Sinatra → Cloudflare Workers 移行
homura 本体(app/app.rb + app/routes/canonical_all.rb)が実際に踏んでいるパターンに基づきます。誇張せず、このスタックで動作確認済みの範囲だけを書きます。
対象と非対象
向いているもの
- Sinatra 4.2 系で、ルートが DSL(
get/post等)中心のアプリ。 - DB を D1 + Sequel に寄せられる(または API のみで D1 不要)。
- テンプレートを ERB のままビルド時プリコンパイルできる。
厳しいもの(早期に見送り判断)
- ActiveRecord 前提の複雑なモデル層、多数の Rack ミドルウェア、サーバー側
File.read前提のテンプレート運用。 - Puma / Unicorn 専用に深く依存した起動フック。
6 ステップ(推奨順)
- Gemfile:
opal-homura(require: 'opal')、homura-runtime、sinatra-homuraを追加。D1 を使うならsequel-d1も追加します。 - エントリ:
app.rb(またはメイン定義ファイル)のrequire 'sinatra'(classic)またはrequire 'sinatra/base'(modular)はそのまま。Cloudflare 専用のrequireに差し替える必要はありません —sinatra-homuraが Sinatra のエントリポイント上で Workers ランタイムを自動配線します。Cloudflare binding 由来の async 境界はhomura buildの auto-await が吸収します。 - ルート: 既存の
get/postを可能な限りそのまま移植。Sinatra の DSL は互換パッチ側で吸収。 - DB:
Sequel.connect(adapter: :d1, d1: d1)の形へ。ORM なしならdb.execute/db.execute_insertを使います。マイグレーションはbundle exec homura db:migrate:compile db/migrations→homura db:migrate:apply(sequel-d1README 参照)。 - ビュー:
bundle exec homura erb:compile --input views --output build/templates.rb --namespace …(プロジェクトの Rake / npm に合わせる)。 - Workers 向けビルド:
bundle exec homura build(または--standalone)でbuild/worker.entrypoint.mjsを生成し、wrangler.tomlのmainと一致させてwrangler deploy。
よくあるハマりポイント
- async 境界: dynamic dispatch や Hash 経由で binding を隠すと auto-await が推論しにくくなります。
db/kv/ai/durable_objectのような helper か、型が見える local 変数に出してください。 - 同期 FS: Workers ではリクエスト処理中の
File.readは使えません。ERB/アセットはビルド時に埋め込み。 - require パス:
vendor/や gemlibを Opal の-Iに載せる順序が重要(sequel-d1README のとおりgems/sequel-d1/libをvendorより前)。 - direct eval: Opal の制約へはビルド後
patch-opal-evals.mjsが自動適用(homura buildパイプライン)。 - 起動 CPU: 重い定数初期化はリクエストをまたぐとタイムアウトしやすい。homura では分割・遅延初期化で対処済みの箇所あり(具体値は本番計測に依存)。
- Cookie セッション: 本リポジトリの
/loginは署名クッキー方式。JWT も別ルートで利用可能。
既存アプリを backend だけ Cloudflare 化するなら
- まず API 面だけ切り出す: 既存フロントはそのままにして、
/api/*や webhook など「境界が明確な backend 仕事」から Workers に移します。最初から SSR 全面移行を狙わないほうが安全です。 - Rack / Sinatra の入口は維持: route 定義、params 処理、認証、service object はなるべく残し、Puma/Unicorn 前提の起動や filesystem 依存だけを先に剥がします。
- Rake を先に生やす: 既存 app でも generated app と同じく
bundle exec rake build/dev/deployを先に作り、その内部でhomuraやwranglerを呼ぶ形に寄せると、移行後の運用が崩れません。 - HTML より JSON を先に通す: backend-only 移行なら ERB を急いで載せなくてよいので、まず JSON API / 認証 / queue / cron / webhook を通し、必要になった時だけ template compile を足すのが筋です。
- DB 境界は最後に決める: 既存 DB を温存するなら Workers から HTTP/Service Binding 経由で寄せる、D1 に寄せられるならその時点で
sequel-d1と migration compile を入れる、の二段で考えるのが現実的です。
動かない・優先度を下げる例
- リクエスト中にローカルファイルキャッシュへ何度も読みに行く設計。
- 巨大な gem をそのまま
requireし、Opal 未対応のネイティブ拡張に依存している。 - WebSocket やストリーミングが必須だが、Workers 側の制約と握れていない(別途検証が必要)。