Cloudflare D1+ Next.jsを試してるがうまく動かない
事前準備
code:sh
$ node -v
v16.13.0
$ npm install -g wrangler
Next.jsをCloudflare Pagesで動かす
Cloudflare PagesはNext.js 12までしか対応してなかった記憶だったけどいつの間にかNext.js 13対応が終わっていた。 code:ts
import type { NextRequest } from "next/server";
export const config = {
runtime: "experimental-edge",
};
export default async function (req: NextRequest) {
return new Response(JSON.stringify({ name: "John Doe" }), {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}
次にnext.config.jsも変更する。
code:ts
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
runtime: "experimental-edge",
},
reactStrictMode: true,
swcMinify: true,
};
module.exports = nextConfig;
次にCloudflareのダッシュボードのPages > Create a project > Connect GitHubに移動し、FrameworkとしてNext.jsを選択(static exportではない方)。Environment Variables(advanced)へNODE_VERSIONにv14以上を設定。これでデプロイを行う。 デプロイが完了したらSettingsへ移動。Next.jsのStreams APIを有効にするためにFunctionsのCompatibility flagsにてstreams_enable_constructorsとtransformstream_enable_standard_constructorを設定する。ちなみにこのフラグは2022-11-30には不要になるとのこと。
これでhttps://YOUR-PROJECT-NAME.pages.dev/api/helloを叩くとレスポンスが帰ってくるはず。
D1を導入する
Next.jsからWorkersのD1にどうやってアクセスしたら良いかが鍵っぽい。
そもそもNext.jsのサーバーサイド処理がPages+Workersで動くざっくりとした仕組みについて。
next-on-pagesでnext.jsアプリをビルドした結果、.vercel/outputに生成される
これがPagesにデプロイされる
実はnext-on-pagesはビルド時に.vercel/output/static/_worker.jsというのを生成してる
pages/apiやSSRの処理などを解析してnext-on-pages/templates/_worker.jsを元に_worker.jsを生成する仕組み
Pagesでは_worker.jsがある場合はその内容を元に飛んできたリクエストをWorkersへ丸っと投げることができる
とりあえず使えるかどうかわからないが、npm install @cloudflare/d1をしてNext.jsからenv.DBでWorkersへアクセスできるか試す。
先のpages/api/hello.tsを以下のように変更する。envを受け取ってみるようにしただけ。
code:ts
import type { NextRequest } from "next/server";
import type { Database } from "@cloudflare/d1";
export const config = {
runtime: "experimental-edge",
};
export interface Env {
DB: Database;
}
export default async function (req: NextRequest, env: Env) {
return new Response(
JSON.stringify({ name: "John Doe", env: JSON.stringify(env) }),
{
status: 200,
headers: {
"Content-Type": "application/json",
},
}
);
}
これで一旦GitHubへPushしてPagesへ反映する。
Pagesの設定でD1にアクセスできるようService Bindingを設定する。ダッシュボードのPages > your project > Settings > Functions > D1 database bindings にVariable nameをDBにしてD1 databaseをSAMPLE_DBにする。
https://YOUR-PROJECT-NAME.pages.dev/api/helloへアクセスしてみる。
code:json
{
name: "John Doe",
env: "{"u":[],"h":false,"sourcePage":"/api/hello"}"
}
ダメっぽい。
next-on-pagesのtemplate/_worker.jsのtype EdgeFunctionにenvを追加し、fetchのenvを差し込むように手を加えればNext.js側のfunctionの第二引数にenvが渡ってきそうな気がする。
ということは下記の流れでいけるか?
envを差し込むように手を入れたカスタムnext-on-pagesを作成
Next.jsのタスクにカスタムしたnext-on-pagesを使うpackage.jsonに定義
CloudflareのPagesのビルドでそのタスクコマンドを使うようにする
next-on-pagesのカスタムについて。
まずローカルにフォークしたnext-on-pagesをクローンしてきて適当にnpm buildする。生成されたCLIを使い、適当なNext.jsプロジェクトのディレクトリでnode ../../../next-on-pages/dist/index.js --experimental-minifyを実行する。すると.vercel/outputにEdgeへビルドされるための結果が生成される。次にtemplates/_worker.jsのfetch(request, env, context)で__FUNCTIONS__に手を入れてるところでdefaultの引数にenvも渡すようにする。これでNext.jsのapiにenvも渡せるか?
Next.jsのタスクにカスタムしたnext-on-pagesを使うpackage.jsonに定義について。
Next.jsのpackage.jsonにてnpm run custom-bulidでnext-on-pagesでビルドが走るようにした。
CloudflareのPagesのビルドでそのタスクコマンドを使うようにするについて。
ダッシュボードからPagesのビルド設定でnpm run custom-buildを使うように設定。
envを引数として差し込んだけどランタイム側ではシグネチャエラーになってるのかも。引数を増やす方向で拡張するのではなく、req引数にenvを追加する形で解決できないか試す。
templates/_worker.jsにCfRequestというRequest & {env: ...}な型を定義てreq引数にenvを加えて再度挑戦。
だめだ...。エラーは発生しないけどreq引数にenvが渡されない。もしかしてreq中身がどこかでfilteringされている?
templates/_worker.jsでentrypoint.defaultに渡しているcontextをenvに変えて試してみたがこれも1101エラーが発生してダメ。_worker.jsのfetchのシグネチャはfetch(req, context)でないとダメっぽい。
request/contextの拡張もだめだしシグネチャを変更するのもだめということでもしかするとexperimental-edgeなランタイムでは何か制限されているのかもしれない。
追記: 2023/1/26
下記isssueに公式のコメントがついた。
・@cloudflare/next-on-pages@0.3.0 will be released soon — follow along here: Version Packages #60. ・process.env will contain the environment object you're used to seeing in Cloudflare Workers, populated with the bindings of your project.
・D1 bindings won't work immediately, but you can expect them to follow soon.
・Node.js compatibility, including async_hooks's AsyncLocalStorage can tested in workerd today, and it will be coming to Cloudflare Workers.
要は、
v0.3.0からprocess.env経由にはなるが各種bindingsにアクセスできるようになる
D1だけはwranglerの方もいじらないといけないから少し遅れる。
ってことらしい。
D1も使えるようになったらNext.js on Workersが結構実用的になると思うから楽しみ
追記: 2023/3/10
このPRがCloseになり遂にNext.js on WorkersでD1へアクセスできるようになった🎉
お試しAPI
リソース