sergiodxa / remix-hono

Hono middlewares for Remix
MIT License
425 stars 11 forks source link

How to setup `getLoadContext` both for remix middleware and Vite dev server? (Cloudflare) #190

Closed predaytor closed 5 months ago

predaytor commented 5 months ago

Not sure how to configure getLoadContext for both remix middleware and remixCloudflareDevProxy to simulate Cloudflare environment for Vite dev server.

Current default setup without Hono:

load-context.ts:

import { type PlatformProxy } from 'wrangler';

// When using `wrangler.toml` to configure bindings,
// `wrangler types` will generate types for those bindings
// into the global `Env` interface.

type Cloudflare = Omit<PlatformProxy<Env>, 'dispose'>;

type GetLoadContextArgs = { request: Request; context: { cloudflare: Cloudflare } };

export function getLoadContext({ context }: GetLoadContextArgs) {
    // ...

    return {
        db,
        auth,
    };
}

declare module '@remix-run/cloudflare' {
    interface AppLoadContext extends ReturnType<typeof getLoadContext> {}
}

/functions/[[path]].ts:

import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages';

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - the server build file is generated by `remix vite:build`
// eslint-disable-next-line import/no-unresolved
import * as build from '../build/server';
import { getLoadContext } from '../load-context';

export const onRequest = createPagesFunctionHandler({ build, getLoadContext });

vite.config.ts:

import {
  vitePlugin as remix,
  cloudflareDevProxyVitePlugin as remixCloudflareDevProxy,
} from "@remix-run/dev";
import { defineConfig } from "vite";
import { getLoadContext } from './load-context';

export default defineConfig({
  plugins: [remixCloudflareDevProxy({ getLoadContext }), remix()],
});

From this package source, getLoadContext accepts a Hono Context object, which differs from the interface provided by remixCloudflareDevProxy with additional PlatformProxy bindings:

/src/handler.ts:

export interface RemixMiddlewareOptions {
    build: ServerBuild;
    mode?: "development" | "production";
    getLoadContext?(c: Context): Promise<AppLoadContext> | AppLoadContext;
}

/node_modules/@remix-run/cloudflare-pages/dist/worker.d.ts:

export interface createPagesFunctionHandlerParams<Env = any> {
    build: ServerBuild | (() => ServerBuild | Promise<ServerBuild>);
    mode?: string;
    getLoadContext?: GetLoadContextFunction<Env>;
}
predaytor commented 5 months ago

Found the solution, but still not sure how to run Hono on Vite dev server.

/server/index.ts:

import { logDevReady } from '@remix-run/cloudflare';
import { createPagesFunctionHandler } from '@remix-run/cloudflare-pages';
import { Hono } from 'hono';
import type { EventContext } from 'hono/cloudflare-pages';
import { csrf } from 'hono/csrf';
import { logger } from 'hono/logger';
import { prettyJSON } from 'hono/pretty-json';
import { secureHeaders } from 'hono/secure-headers';
import { staticAssets } from 'remix-hono/cloudflare';
import { trailingSlash } from 'remix-hono/trailing-slash';

import * as build from '../build/server';
import { getLoadContext } from './load-context';

if (process.env.NODE_ENV === 'development') logDevReady(build);

export type ContextEnv = { Bindings: Required<Env> & { eventContext: EventContext } };

const app = new Hono<ContextEnv>({ strict: true });

app.use(csrf());
app.use(logger());
app.use(prettyJSON({ space: 4 }));
app.use(secureHeaders());
app.use(trailingSlash());
app.use(staticAssets({ cache: { public: true, maxAge: '1y', immutable: true } }));

app.use(async c => await createPagesFunctionHandler({ build, getLoadContext })(c.env.eventContext));

export default app;

/functions/[[path]].ts:

import { handle } from 'hono/cloudflare-pages';

import server from '../server/index';

export const onRequest = handle(server);