Next.jsをCloudflare Workersへ|OpenNextで詰まった3つ

9月3日、自作のデモ2本をVercelからCloudflare Workersへ移した日の話です。最後の確認で、検証スクリプトが「AIの要約は動いとる」とOKを出しました。けど、その時点でAIの鍵はまだ入れてへん。動くはずがない。検収を受け持つ別のAIがURLを叩き直したら、返ってきたのは鍵が無い時に出す代わりの文でした。

Next.jsのアプリは、OpenNext(@opennextjs/cloudflare)を使えばCloudflare Workersに載ります。うちの2本は、アプリ本体(src の中)のコードを1行も変えずに動きました。詰まったのは3つ。OpenNextが求めるNext.jsの版が16.3.3以上やった。手元のプレビューを止め忘れて、次の試運転が落ちた。検証スクリプトの日本語の照合が文字コードで外れて、偽のOKを出した。

なんでVercelから引っ越したかは、前にCloudflare WorkersでLP公開|無料枠と商用の話で書きました。あっちは動きの無いLPの話。この記事は、サーバー側で動くNext.jsの話です。

移したのはNext.jsのデモ2本|準備20分と検収・デプロイ25分

移したのは、受託の営業で見せとるデモ2本です。

  • 工程管理アプリ:Next.js 16のApp Router。案件ごとの詳細ページのように、URLの一部が変わるページがある。APIは無し
  • 売上集計デモ:同じくNext.js 16。中にAPIが2本あって、AIに要約とチャットをさせる。AIの鍵は環境変数で読む

同じ日に、動きの無い静的なデモも1本移してます。そっちはLPの時と同じ手順なので、手順はここでは省きます。

作業はAIを2つに分けました。準備役のAIが設定を足して、試運転(dry-run。本番には出さず、出したらどうなるかだけ確かめる実行)まで。本番へのデプロイと検収は、別のAIが受け持つ。準備に20分、検収とデプロイに25分でした。APIの鍵だけは、AIに触らせず自分の手で入れる決まりにしてます。

OpenNextで足したのは設定ファイルだけ

入れたパッケージは2つ。@opennextjs/cloudflare は普通の依存として npm i、wrangler は開発用の依存として npm i -D で入れました。そのうえで足した設定がこれです。

  • open-next.config.ts:公式の最小の形のまま
  • wrangler.jsonc:Workersの設定。main に .open-next/worker.js、assets に .open-next/assets、互換フラグに nodejs_compat と global_fetch_strictly_public
  • package.json:opennextjs-cloudflare の build・preview・deploy を呼ぶスクリプトを3本
  • next.config.ts:末尾に initOpenNextCloudflareForDev() を呼ぶ2行を足す
  • .gitignore:ビルドで出来る .open-next/ を足す

売上集計デモのAPIは、ランタイムを nodejs に指定してあります。そこも変えずに、Workersの上で最後まで動きました。

もう1つ、preview_urls は false にしてます。Workersは既定やと、版ごとのURLが本番と同じ中身で作られる。見せる口が勝手に増えんように、先に閉じとく設定です。

罠1|OpenNextが求めるNext.jsは16.3.3以上やった

最初に止まったのはここです。設計の段階では「Next.js 16なら対応」と書いとりました。入れたOpenNextは1.20.6。このパッケージには「一緒に入っとる相手はこの版以上で」という条件(peer)があって、Next.jsについては next>=16.3.3 でした。手元のデモは16.2.9。条件の外です。

選んだのは、Next.jsを16.3.4に上げるほう。上げたあとでビルドが通って、全部のページが開くのを見てから先へ進めました。まずかった時に戻すのは、変えた3ファイルをgitで戻すだけ。そこまで確かめてから上げてます。

入れる前に確かめるなら、npm view @opennextjs/cloudflare peerDependencies で条件が見られます。

それと、WindowsでOpenNextを動かすと非推奨の警告が出ます。うちはWindowsのまま進めて、ビルドもデプロイも通りました。

罠2|OpenNextのプレビューを止め忘れて、次の試運転が落ちた

Next.jsの2本は、本番に出す前に手元のプレビューで全部のページを開いて確かめてます。opennextjs-cloudflare preview で、Workersの実行環境を自分のパソコンの上で動かす形です。

そのあと、3本目(静的なデモ)の試運転を走らせたら落ちました。原因は、立ち上げたプレビューのプロセスが止まらずに5つ残っとって、ビルドの出力フォルダを掴んだままやったこと。止めて走り直したら、すぐ通りました。

Windowsでは、動いとるプロセスが使っとるファイルは、消したり上書きしたりできんことがあります。wrangler dev や serve を立てたまま .open-next や dist を作り直そうとすると、ビルドが落ちる。試運転の前に、立てたプレビューは全部止める。今はAIが毎回読むメモに、そう書いてあります。

罠3|cp932で日本語の照合が外れて、偽のOKが出た

冒頭の場面です。売上集計デモは、AIの鍵が入ってへん時でも落ちんように作ってあります。鍵が無ければ、決まった文で要約の欄を埋めて返す。落ちへんかわりに、外から見たら動いとるように見える作りです。

そこで検証スクリプトには、「返事にこの決まった文が入ってへんかったら、AIの要約が生きとる」と判定させてました。鍵はまだ入れてへんのやから、正解は「AIは動いてへん」。ところが出たのは「AIの要約が生きとる」でした。

原因は文字コードです。スクリプトはPowerShellで、返事を Get-Content -Raw で読んでました。返事はUTF-8。それをcp932(Windowsの日本語の古い文字コード)として読んどった。日本語で探した決まった文は、化けた文字の中からは見つからん。見つからん、だから決まった文は無い、だからOK。こういう流れです。

直し方は2つ。照合する文字を、決まった文の中の、鍵の名前の英字部分 ANTHROPIC_API_KEY にした。読み込みに -Encoding UTF8 を付けた。気づけたのは、検収役のAIがスクリプトのOKをそのまま信じず、curlで叩き直して返事の中身を見たからです。

鍵はそのあと、自分の手で npx wrangler secret put ANTHROPIC_API_KEY を打って入れました。1回目は、端末が「Enter a secret value:」で入力待ちのまま止まっとるのに、入れたつもりになってた。AIに端末を見てもろて気づいて、手順を出し直してもろて入れたら「Uploaded secret」と出て、本番の要約が293字で返ってきました。

Vercelの旧URLは消さずに301で転送した

Vercelから301リダイレクトでCloudflare Workersへ移行し、デモ2本と3つの罠を示した図
VercelからWorkersへ移した全体像と3つの罠

移したあと、Vercel側は消してません。応募の提案文に、VercelのURLを載せて送っとるからです。送った提案文は、あとから書き換えられん。消したら、開いた人の前で404になる。

なので、3つのリポジトリに vercel.json を置いて、旧URLを新しいURLへ301で飛ばす転送板にしました。8月に静的サイトで同じことをした時は、最初 redirects で書いて効かんかった。実在するファイルのほうが先に返るからです。ファイルより前に見られる routes で書き直したら効いた。今回は最初からその形です。

pushしてから3分以内に、3本とも旧URLが301で新しいURLへ飛ぶようになりました。/x/y のようなパスつきのURLも、パスを保ったまま飛びます。置き場の代金は、引っ越す前と同じ0円のままです。

あと1つ、デプロイの直後は数十秒404を返すことがあります。うちの確認は、200が返るまで最大90秒待ってから中身を見る形にしてます。待たずに確かめると、出来とるのに失敗と出るので。

よくある質問

Next.jsはCloudflare Workersで動く?

動きます。うちはOpenNext(@opennextjs/cloudflare)で、Next.js 16のApp Routerのアプリ2本をWorkersに載せました。ランタイムを nodejs にしたAPIも、そのまま動いとります。入れる前に、OpenNextが求めるNext.jsの版だけ確かめてください。うちが入れた1.20.6では16.3.3以上でした。

VercelからCloudflare Workersへ移したら、旧URLはどうなる?

Vercelのプロジェクトを消せば、旧URLは開けんくなります。うちは消さずに、vercel.json の routes で新しいURLへ301転送しました。パスつきのURLも、パスを保ったまま飛びます。人に渡したURLがある時は、転送を残しとくほうが安全です。

Windowsで試運転やビルドが急に落ちる時は?

うちで落ちたのは、手元で立ち上げたプレビューが残ったまま、ビルドの出力フォルダを掴んどった時でした。全部止めて走り直したら通りました。Windowsでは非推奨の警告も出ますが、うちはそのままビルドとデプロイまで通っとります。

あわせて読みたい