Skip to content

Commit 3db87a4

Browse files
authored
feat: support getLoadContext (#6)
* feat: add remaining Cloudflare values to contexts * support `getLoadContext` * revert `tsup.config.ts` * tweak `cloudflare-pages.ts` * make `getLoadContext` not option for `RemixMiddlewareOptions`
1 parent 9b71ca1 commit 3db87a4

File tree

9 files changed

+134
-25
lines changed

9 files changed

+134
-25
lines changed

example/app/routes/_index.tsx

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
11
import type { LoaderFunctionArgs } from '@remix-run/cloudflare'
22
import { useLoaderData } from '@remix-run/react'
33

4-
export const loader = ({ context }: LoaderFunctionArgs) => {
5-
const { env } = context.cloudflare as { env: { MY_VAR: string} }
6-
return {
7-
var: env.MY_VAR
8-
}
4+
export const loader = (args: LoaderFunctionArgs) => {
5+
const extra = args.context.extra
6+
const cloudflare = args.context.cloudflare
7+
return { cloudflare, extra }
98
}
109

1110
export default function Index() {
12-
const data = useLoaderData<typeof loader>()
11+
const { cloudflare, extra } = useLoaderData<typeof loader>()
1312
return (
1413
<div>
1514
<h1>Remix and Hono</h1>
16-
<h2>Var is {data.var}</h2>
15+
<h2>Var is {cloudflare.env.MY_VAR}</h2>
16+
<h3>
17+
{cloudflare.cf ? 'cf,' : ''}
18+
{cloudflare.ctx ? 'ctx,' : ''}
19+
{cloudflare.caches ? 'caches are available' : ''}
20+
</h3>
21+
<h4>Extra is {extra}</h4>
1722
</div>
1823
)
1924
}

example/e2e.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ test('Should return 200 response - /', async ({ page }) => {
1212

1313
const contentH2 = await page.textContent('h2')
1414
expect(contentH2).toBe('Var is My Value')
15+
16+
const contentH3 = await page.textContent('h3')
17+
expect(contentH3).toBe('cf,ctx,caches are available')
18+
19+
const contentH4 = await page.textContent('h4')
20+
expect(contentH4).toBe('Extra is stuff')
1521
})
1622

1723
test('Should return 200 response - /api', async ({ page }) => {

example/functions/[[path]].ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// functions/[[path]].ts
22
import handle from 'hono-remix-adapter/cloudflare-pages'
3+
import { getLoadContext } from 'load-context'
34
import * as build from '../build/server'
45
import server from '../server'
56

6-
export const onRequest = handle(build, server)
7+
export const onRequest = handle(build, server, { getLoadContext })

example/load-context.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { AppLoadContext } from '@remix-run/cloudflare'
2+
import type { PlatformProxy } from 'wrangler'
3+
4+
interface Env {
5+
MY_VAR: string
6+
}
7+
8+
type Cloudflare = Omit<PlatformProxy<Env>, 'dispose'>
9+
10+
declare module '@remix-run/cloudflare' {
11+
interface AppLoadContext {
12+
cloudflare: Cloudflare
13+
extra: string
14+
}
15+
}
16+
17+
type GetLoadContext = (args: {
18+
request: Request
19+
context: { cloudflare: Cloudflare }
20+
}) => AppLoadContext
21+
22+
// Shared implementation compatible with Vite, Wrangler, and Cloudflare Pages
23+
export const getLoadContext: GetLoadContext = ({ context }) => {
24+
return {
25+
...context,
26+
extra: 'stuff',
27+
}
28+
}

example/vite.config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
import serverAdapter from 'hono-remix-adapter/vite'
88
import { defineConfig } from 'vite'
99
import tsconfigPaths from 'vite-tsconfig-paths'
10+
import { getLoadContext } from './load-context'
1011

1112
export default defineConfig({
1213
plugins: [
@@ -20,6 +21,7 @@ export default defineConfig({
2021
}),
2122
serverAdapter({
2223
adapter,
24+
getLoadContext,
2325
entry: 'server/index.ts',
2426
}),
2527
tsconfigPaths(),

src/cloudflare-pages.ts

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,38 @@
1+
import type { ServerBuild } from '@remix-run/cloudflare'
2+
import { createRequestHandler } from '@remix-run/cloudflare'
13
import { Hono } from 'hono'
24
import { handle } from 'hono/cloudflare-pages'
5+
import { createMiddleware } from 'hono/factory'
36
import { staticAssets } from 'remix-hono/cloudflare'
4-
import { remix } from 'remix-hono/handler'
7+
import { createGetLoadContextArgs, defaultGetLoadContext } from './remix'
8+
import type { GetLoadContext } from './remix'
59

6-
export const handler = (serverBuild: any, userApp?: Hono<any, any, any>) => {
10+
interface RemixMiddlewareOptions {
11+
build: ServerBuild
12+
mode?: 'development' | 'production'
13+
getLoadContext: GetLoadContext
14+
}
15+
16+
function remix({ mode, build, getLoadContext }: RemixMiddlewareOptions) {
17+
return createMiddleware(async (c) => {
18+
const requestHandler = createRequestHandler(build, mode)
19+
const args = createGetLoadContextArgs(c)
20+
21+
const loadContext = getLoadContext(args)
22+
return await requestHandler(
23+
c.req.raw,
24+
loadContext instanceof Promise ? await loadContext : loadContext
25+
)
26+
})
27+
}
28+
29+
type Options = {
30+
getLoadContext: GetLoadContext
31+
}
32+
33+
// Relaxing the type definitions
34+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
35+
export const handler = (serverBuild: any, userApp?: Hono<any, any, any>, options?: Options) => {
736
const app = new Hono()
837

938
if (userApp) {
@@ -18,13 +47,7 @@ export const handler = (serverBuild: any, userApp?: Hono<any, any, any>) => {
1847
return remix({
1948
build: serverBuild,
2049
mode: 'production',
21-
getLoadContext(c) {
22-
return {
23-
cloudflare: {
24-
env: c.env,
25-
},
26-
}
27-
},
50+
getLoadContext: options?.getLoadContext ?? defaultGetLoadContext,
2851
})(c, next)
2952
}
3053
)

src/dev.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
import type { AppLoadContext } from '@remix-run/cloudflare'
21
import { Hono } from 'hono'
2+
import { createGetLoadContextArgs, defaultGetLoadContext } from './remix'
3+
import type { GetLoadContext } from './remix'
34

4-
export const handle = (userApp?: Hono) => {
5+
type Options = {
6+
getLoadContext: GetLoadContext
7+
}
8+
9+
export const handle = (userApp?: Hono, options?: Options) => {
510
const app = new Hono()
611

712
if (userApp) {
@@ -13,13 +18,14 @@ export const handle = (userApp?: Hono) => {
1318
const build = await import('virtual:remix/server-build')
1419
const { createRequestHandler } = await import('@remix-run/cloudflare')
1520
const handler = createRequestHandler(build, 'development')
16-
const remixContext = {
17-
cloudflare: {
18-
env: c.env,
19-
},
20-
} as unknown as AppLoadContext
21+
22+
const getLoadContext = options?.getLoadContext ?? defaultGetLoadContext
23+
const args = createGetLoadContextArgs(c)
24+
25+
const remixContext = getLoadContext(args)
2126
return handler(c.req.raw, remixContext)
2227
})
28+
2329
return app
2430
}
2531

src/remix.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { AppLoadContext } from '@remix-run/cloudflare'
2+
import type { Context } from 'hono'
3+
4+
export type GetLoadContext = (args: {
5+
request: Request
6+
context: {
7+
// Relaxing the type definition
8+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
9+
cloudflare: any
10+
}
11+
}) => AppLoadContext
12+
13+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
14+
export const defaultGetLoadContext = ({ context }: any) => {
15+
return {
16+
...context,
17+
}
18+
}
19+
20+
export const createGetLoadContextArgs = (c: Context) => {
21+
return {
22+
context: {
23+
cloudflare: {
24+
env: c.env,
25+
cf: c.req.raw.cf,
26+
ctx: {
27+
...c.executionCtx,
28+
},
29+
caches,
30+
},
31+
},
32+
request: c.req.raw,
33+
}
34+
}

src/vite-plugin.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type { Plugin } from 'vite'
44
import fs from 'node:fs'
55
import path from 'node:path'
66
import { fileURLToPath } from 'node:url'
7+
import type { GetLoadContext } from './remix'
78

89
interface Adapter {
910
env?: Record<string, unknown> | Promise<Record<string, unknown>>
@@ -17,6 +18,7 @@ interface Adapter {
1718
interface Options {
1819
entry: string
1920
adapter?: () => Adapter | Promise<Adapter>
21+
getLoadContext?: GetLoadContext
2022
}
2123

2224
export default (options: Options): Plugin => {
@@ -51,7 +53,9 @@ export default (options: Options): Plugin => {
5153
}
5254

5355
const devModule = await server.ssrLoadModule(devPath)
54-
return devModule['default'](app)
56+
return devModule['default'](app, {
57+
getLoadContext: options.getLoadContext,
58+
})
5559
},
5660
})
5761
}

0 commit comments

Comments
 (0)