diff --git a/README.md b/README.md index 749f804..e5210be 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,88 @@ export const onRequest = handle(build, server, { getLoadContext }) This way is almost the same as [Remix](https://remix.run/docs/en/main/guides/vite#augmenting-load-context). +### Getting Hono context + +You can get the Hono context in Remix routes. For example, you can pass the value with `c.set()` from your Hono instance in the `server/index.ts`: + +```ts +// server/index.ts +import { Hono } from 'hono' + +const app = new Hono<{ + Variables: { + message: string + } +}>() + +app.use(async (c, next) => { + c.set('message', 'Hi from Hono') + await next() +}) + +export default app +``` + +In the Remix route, you can get the context from `args.context.hono.context`: + +```ts +// app/routes/_index.tsx +import type { LoaderFunctionArgs } from '@remix-run/cloudflare' +import { useLoaderData } from '@remix-run/react' + +export const loader = ({ context }) => { + const message = args.context.hono.context.get('message') + return { message } +} + +export default function Index() { + const { message } = useLoaderData() + return

Message is {message}

+} +``` + +To enable type inference, config the `load-context.ts` like follows: + +```ts +// load-context.ts +import type { AppLoadContext } from '@remix-run/cloudflare' +import type { Context } from 'hono' +import type { PlatformProxy } from 'wrangler' + +type Env = { + Variables: { + message: string + } +} + +type Cloudflare = Omit + +declare module '@remix-run/cloudflare' { + interface AppLoadContext { + cloudflare: Cloudflare + hono: { + context: Context + } + extra: string + } +} + +type GetLoadContext = (args: { + request: Request + context: { + cloudflare: Cloudflare + hono: { context: Context } + } +}) => AppLoadContext + +export const getLoadContext: GetLoadContext = ({ context }) => { + return { + ...context, + extra: 'stuff', + } +} +``` + ## Auth middleware for Remix routes If you want to add Auth Middleware, e.g. Basic Auth middleware, please be careful that users can access the protected pages with SPA tradition. To prevent this, add a `loader` to the page: diff --git a/examples/cloudflare-pages/app/routes/_index.tsx b/examples/cloudflare-pages/app/routes/_index.tsx index 840dafe..287c6de 100644 --- a/examples/cloudflare-pages/app/routes/_index.tsx +++ b/examples/cloudflare-pages/app/routes/_index.tsx @@ -4,11 +4,12 @@ import { useLoaderData } from '@remix-run/react' export const loader = (args: LoaderFunctionArgs) => { const extra = args.context.extra const cloudflare = args.context.cloudflare - return { cloudflare, extra } + const myVarInVariables = args.context.hono.context.get('MY_VAR_IN_VARIABLES') + return { cloudflare, extra, myVarInVariables } } export default function Index() { - const { cloudflare, extra } = useLoaderData() + const { cloudflare, extra, myVarInVariables } = useLoaderData() return (

Remix and Hono

@@ -19,6 +20,7 @@ export default function Index() { {cloudflare.caches ? 'caches are available' : ''}

Extra is {extra}

+
Var in Variables is {myVarInVariables}
) } diff --git a/examples/cloudflare-pages/e2e.test.ts b/examples/cloudflare-pages/e2e.test.ts index 045b0cd..1af16bd 100644 --- a/examples/cloudflare-pages/e2e.test.ts +++ b/examples/cloudflare-pages/e2e.test.ts @@ -18,6 +18,9 @@ test('Should return 200 response - /', async ({ page }) => { const contentH4 = await page.textContent('h4') expect(contentH4).toBe('Extra is stuff') + + const contentH5 = await page.textContent('h5') + expect(contentH5).toBe('Var in Variables is My variable set in c.set') }) test('Should return 200 response - /api', async ({ page }) => { diff --git a/examples/cloudflare-pages/load-context.ts b/examples/cloudflare-pages/load-context.ts index 58c6da1..1fa1b23 100644 --- a/examples/cloudflare-pages/load-context.ts +++ b/examples/cloudflare-pages/load-context.ts @@ -1,22 +1,34 @@ import type { AppLoadContext } from '@remix-run/cloudflare' +import type { Context } from 'hono' import type { PlatformProxy } from 'wrangler' -interface Env { - MY_VAR: string +type Env = { + Bindings: { + MY_VAR: string + } + Variables: { + MY_VAR_IN_VARIABLES: string + } } -type Cloudflare = Omit, 'dispose'> +type Cloudflare = Omit, 'dispose'> declare module '@remix-run/cloudflare' { interface AppLoadContext { cloudflare: Cloudflare extra: string + hono: { + context: Context + } } } type GetLoadContext = (args: { request: Request - context: { cloudflare: Cloudflare } + context: { + cloudflare: Cloudflare + hono: { context: Context } + } }) => AppLoadContext // Shared implementation compatible with Vite, Wrangler, and Cloudflare Pages diff --git a/examples/cloudflare-pages/server/index.ts b/examples/cloudflare-pages/server/index.ts index 740577e..3c1df33 100644 --- a/examples/cloudflare-pages/server/index.ts +++ b/examples/cloudflare-pages/server/index.ts @@ -5,9 +5,13 @@ const app = new Hono<{ Bindings: { MY_VAR: string } + Variables: { + MY_VAR_IN_VARIABLES: string + } }>() -app.use(async(c, next) => { +app.use(async (c, next) => { + c.set('MY_VAR_IN_VARIABLES', 'My variable set in c.set') await next() c.header('X-Powered-By', 'Remix and Hono') }) @@ -15,9 +19,8 @@ app.use(async(c, next) => { app.get('/api', (c) => { return c.json({ message: 'Hello', - var: c.env.MY_VAR + var: c.env.MY_VAR, }) }) - export default app diff --git a/src/remix.ts b/src/remix.ts index 6d9ffb5..f47f844 100644 --- a/src/remix.ts +++ b/src/remix.ts @@ -1,14 +1,19 @@ import type { AppLoadContext } from '@remix-run/cloudflare' import type { Context } from 'hono' -export type GetLoadContext = (args: { +type GetLoadContextArgs = { request: Request context: { // Relaxing the type definition // eslint-disable-next-line @typescript-eslint/no-explicit-any cloudflare: any + hono: { + context: Context + } } -}) => AppLoadContext | Promise +} + +export type GetLoadContext = (args: GetLoadContextArgs) => AppLoadContext | Promise // eslint-disable-next-line @typescript-eslint/no-explicit-any export const defaultGetLoadContext = ({ context }: any): AppLoadContext => { @@ -17,7 +22,7 @@ export const defaultGetLoadContext = ({ context }: any): AppLoadContext => { } } -export const createGetLoadContextArgs = (c: Context) => { +export const createGetLoadContextArgs = (c: Context): GetLoadContextArgs => { return { context: { cloudflare: { @@ -29,6 +34,9 @@ export const createGetLoadContextArgs = (c: Context) => { // @ts-expect-error globalThis.caches is not typed caches: globalThis.caches ? caches : undefined, }, + hono: { + context: c, + }, }, request: c.req.raw, }