既存 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(またはメイン定義ファイル)の先頭付近に# await:マジックコメントを付与(JWT / D1 / fetch など非同期が混ざるファイルは必須。Phase 15-C 教訓)。続けてrequire 'sinatra/cloudflare_workers'。 - ルート: 既存の
get/postを可能な限りそのまま移植。Sinatra の DSL は互換パッチ側で吸収。 - DB:
Sequel.connect(adapter: :d1, d1: env['cloudflare.env'].DB)の形へ。マイグレーションはbundle exec cloudflare-workers-migrate compile db/migrations→apply(sequel-d1README 参照)。 - ビュー:
bundle exec cloudflare-workers-erb-compile --input views --output build/templates.rb --namespace …(プロジェクトの Rake / npm に合わせる)。 - Workers 向けビルド:
bundle exec cloudflare-workers-build(または--standalone)でbuild/worker.entrypoint.mjsを生成し、wrangler.tomlのmainと一致させてwrangler deploy。
よくあるハマりポイント
# await:: ルート内で__await__が必要なのにマジックコメントが無いと、Promise がそのまま残って 1101 等で落ちます。- 同期 FS: Workers ではリクエスト処理中の
File.readは使えません。ERB/アセットはビルド時に埋め込み。 - require パス:
vendor/や gemlibを Opal の-Iに載せる順序が重要(sequel-d1README のとおりgems/sequel-d1/libをvendorより前)。 - direct eval: Opal の制約へはビルド後
patch-opal-evals.mjsが自動適用(cloudflare-workers-buildパイプライン)。 - 起動 CPU: 重い定数初期化はリクエストをまたぐとタイムアウトしやすい。homura では分割・遅延初期化で対処済みの箇所あり(具体値は本番計測に依存)。
- Cookie セッション: 本リポジトリの
/loginは署名クッキー方式。JWT も別ルートで利用可能。
動かない・優先度を下げる例
- リクエスト中にローカルファイルキャッシュへ何度も読みに行く設計。
- 巨大な gem をそのまま
requireし、Opal 未対応のネイティブ拡張に依存している。 - WebSocket やストリーミングが必須だが、Workers 側の制約と握れていない(別途検証が必要)。