概要
Cloudflare WorkersのStatic AssetsやWorkers logsの対応により、Workersで動かしたい事象が増えてきましたね!!
そして素晴らしいタイミングでWorkersとPages両対応のhono-remix-adapterがHono作者様より作成されました!!!
これにより、WorkersでHonoミドルウェアを備えたRemixが簡単に作れて、ログも記録出来るようになりました!!
今回は早速、Remix on Honoを動かしてみます。
hono-remix-adapterの導入
基本はReadmeの通り実施していきます。
成果物はこちらを参照ください!!
https://github.com/sori883/test-hono-remix-adapter
変更したファイル一覧はこちらです
https://github.com/sori883/test-hono-remix-adapter/commit/ffda9ac899b74e4bd0f0d36a1380e2a7d2adaef8
今回は、Cloudflare公式のRemix on Cloudflare Workersのテンプレートに導入していきます。
まずは、テンプレートをインストールします。
pnpm create cloudflare@latest my-remix-app --framework=remix --experimental
合わせて、今回の主題である「hono-remix-adapter」及び、「hono」、「@hono/vite-dev-server」をインストールします。
pnpm add hono-remix-adapter hono @hono/vite-dev-server
vite.config.tsを以下の通り変更しました。
import { defineConfig } from "vite";
import {
vitePlugin as remix,
cloudflareDevProxyVitePlugin,
} from "@remix-run/dev";
import serverAdapter from "hono-remix-adapter/vite"
import adapter from "@hono/vite-dev-server/cloudflare"
import tsconfigPaths from "vite-tsconfig-paths"
import { getLoadContext } from './load-context'
declare module "@remix-run/cloudflare" {
interface Future {
v3_singleFetch: true;
}
}
export default defineConfig({
plugins: [
cloudflareDevProxyVitePlugin(),
remix({
future: {
v3_fetcherPersist: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
v3_singleFetch: true,
v3_lazyRouteDiscovery: true,
},
}),
serverAdapter({
adapter,
getLoadContext,
entry: "server/index.ts",
}),
tsconfigPaths(),
],
ssr: {
resolve: {
conditions: ["workerd", "worker", "browser"],
},
},
resolve: {
mainFields: ["browser", "module", "main"],
},
build: {
minify: true,
},
});
また、load-context.tsは以下の通り変更しました。
ここのEnvはcodegen
で作成された.dev.vars
の型です。
import type { Context } from "hono";
import type { PlatformProxy } from "wrangler";
type GetLoadContextArgs = {
request: Request
context: {
cloudflare: Omit<PlatformProxy<Env>, "dispose" | "caches" | "cf"> & {
caches: PlatformProxy<Env>["caches"] | CacheStorage
cf: Request["cf"]
}
hono: {
context: Context;
}
}
}
declare module "@remix-run/cloudflare" {
interface AppLoadContext extends ReturnType<typeof getLoadContext> {
// This will merge the result of `getLoadContext` into the `AppLoadContext`
extra: string
hono: {
context: Context;
}
}
}
export function getLoadContext({ context }: GetLoadContextArgs) {
return {
...context,
extra: "stuff",
};
}
次に、server/index.tsにHono Appを作成します。
動作確認用にPowered Byのヘッダーをつけておきます。
// server/index.ts
import { Hono } from "hono"
const app = new Hono<{Bindings: Env}>()
app.use(async (c, next) => {
await next()
c.header('X-Powered-By', c.env.EXAMPLE_VARIABLE)
})
export default app
最後にworker.tsを作成します。
import handle from 'hono-remix-adapter/cloudflare-workers'
import * as build from './build/server'
import { getLoadContext } from './load-context'
import app from './server'
export default handle(build, app, { getLoadContext })
また、wrangler.tomlのmainにworker.tsを指定しておきます。
#:schema node_modules/wrangler/config-schema.json
name = "my-remix-app"
compatibility_date = "2024-11-12"
main = "./worker.ts"
assets = { directory = "./build/client" }
# Workers Logs
# Docs: https://developers.cloudflare.com/workers/observability/logs/workers-logs/
# Configuration: https://developers.cloudflare.com/workers/observability/logs/workers-logs/#enable-workers-logs
[observability]
enabled = true
[vars]
EXAMPLE_VARIABLE = "example_valiable"
動作確認
ローカルで確認してみます
X-Powered-Byヘッダーが設定されていて、Remix側も環境変数取れていい感じですね~。
デプロイしてWorkersで確認してみます
ローカルと同様にX-Powered-Byヘッダーが設定されていて、Remix側も環境変数取れていい感じですね~。
完走の感想
load-context.tsはかなり雰囲気で変更したため、もっといい方法がある可能性大です。
折角codegenがあるので利用したい!となった結果上記の通りとなりました。
またextra: "stuff",
が必要な理由もよくわかってません。。。。誰かおしえてください..
hono-remix-adapterのコントリビュータの方が教えてくれました!圧倒的感謝です
でも、WorkersとPagesが切り替えられるのはよいですね!
ログやService Bindingsの呼び出し等、どちらか一方にしか実装されていない状況が発生するので、乗り換えるか。。となった時の対応が取れるのは大変ありがたいですね!!!(特に個人開発をしている様な方とかに!!)