next-on-pages README 上的告知

Cloudflare 九月底把 next-on-pages 專案封存,issue 全關,npm package 棄用,不再維護了,建議大家改用 OpenNext 的 Cloudflare adapter

太無情了吧,哪有這樣說換就換的…… 只能搬家了。

轉換提要

原本 next-on-pages 是把 Next.js 的產出轉換成可以在 Cloudflare Pages 平台上跑的東西,改用 @opennextjs/cloudflare 的話,主要就是改成轉給 Cloudflare Workers 而已。

文件參考:

基本開發環境不變

因為開發時仍然是用 Next.js 自己的 next dev,所以受 pages 或 workers 影響較小。

程式變更

  • 不再使用 edge runtime

    現在反而是只支援 node.js runtime,還不支援 edge,幸好 edge 是比較弱的,問題相對少。

    我是單純移除所有的 export const runtime = 'edge'; 即可。

  • 套件當然要換掉

    安裝 @opennextjs/cloudflare@latest 取代 @cloudflare/next-on-pageseslint-plugin-next-on-pages(相關的東西也都刪掉)。

  • 取得開發環境的 Cloudflare binding 資源

    開發時必須取得 local 的 CF 資源(D1 資料庫、R2 儲存空間等),在 next.config.mjs 裡面,以前是用:

    import { setupDevPlatform } from '@cloudflare/next-on-pages/next-dev';
    要改成:
    import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";

  • DB 要在每個請求中動態取得

    參考 Db - OpenNext。 有些 ORM 會受影響,像我是用 drizzle-orm,以前可以直接設一個 global db,現在要改成 getDb(),幸好改起來還算單純。

設定檔變更: .open-next.config.ts

第一次跑 opennextjs-cloudflare build 會建立這個設定檔,內容如下:

// default open-next.config.ts file created by @opennextjs/cloudflare
import { defineCloudflareConfig } from "@opennextjs/cloudflare/config";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";

export default defineCloudflareConfig({
  incrementalCache: r2IncrementalCache,
});

那個 r2IncrementalCache 是 Next.js 快取會用到的,參考文件,視情況可能還有 DO和 D1 的 binding 會跑出來?

設定檔變更: wrangler.jsonc

原本的 "pages_build_output_dir": "./dist" 要拿掉,然後我增加的部分如下:

"main": ".open-next/worker.js",
"assets": {
  "directory": ".open-next/assets",
  "binding": "ASSETS"
},
"r2_buckets": [
  {
    "binding": "(原本在用的 binding 名,這桶是原本就有的)",
    "bucket_name": "(原本在用的 bucket 名,原本就有)"
  },
  {
    "binding": "NEXT_INC_CACHE_R2_BUCKET",
    "bucket_name": "feeders-next-inc-cache(自己命名,這個只是舉例)"
  }
],
"preview_urls": true,
"observability": {
  "enabled": true,
  "head_sampling_rate": 1
},
"workers_dev": true,

其中 mainassets 是必要的。

NEXT_INC_CACHE_R2_BUCKET 是跟前述 build 出來的 .open-next.config.ts 對應,這個 bucket 要另外手動開出來。

build、預覽和部署

以前用 pnpm next-on-pages --outdir=dist build 到 dist 目錄, 現在換成 pnpm opennextjs-cloudflare build,會 build 到 .open-next 目錄,可以觀察一下生成的檔案內容。

原本用 wrangler pages 開頭的指令都要換掉,改成例如 wrangler deploy 等。

Production 的環境變數

以前我是將 production 的環境變數通通當成 secret 上傳到 Cloudflare,不然要維護本地的 .dev.vars、Next.js 的 .env.*、寫在 wrangler config 中的變數、…… 等等有點麻煩。

現在雖然建議管理方式仍是在 CF 後台設定變數或 secret, 但我發現 opennextjs build 會直接把所有環境的 .env.* 都包進去: opennextjs-cloudflare/packages/cloudflare/src/cli/build/open-next/compile-env-files.ts#L4

所以除非 build 的時候有隔離這些 .env 檔案,不然其實 worker 是吃得到變數的。 實測確實如此,且這些變數在 CF 後台也看不見。

參考文件: Env Vars - OpenNext

網址 xxx.pages.dev 沒了

沒救,可憐,現在附送的網址是 xxx.workers.dev,還是買個自己的網域吧。

實際 commits

這次轉換的是 feeders 專案,相關 commit 可以看: Commits 10/2 ~ 10/5 · bootleq/feeders