diff --git a/docs/file-conventions/entry.server.md b/docs/file-conventions/entry.server.md index a043e82da72..747f5a411b1 100644 --- a/docs/file-conventions/entry.server.md +++ b/docs/file-conventions/entry.server.md @@ -16,6 +16,7 @@ Here's a basic example: ```tsx import { renderToString } from "react-dom/server"; import type { + AppLoadContext, EntryContext, HandleDataRequestFunction, } from "@remix-run/node"; // or cloudflare/deno @@ -25,7 +26,8 @@ export default function handleRequest( request: Request, responseStatusCode: number, responseHeaders: Headers, - remixContext: EntryContext + remixContext: EntryContext, + loadContext: AppLoadContext ) { const markup = renderToString( diff --git a/packages/remix-server-runtime/__tests__/server-test.ts b/packages/remix-server-runtime/__tests__/server-test.ts index 51b3a0353fb..0832256315a 100644 --- a/packages/remix-server-runtime/__tests__/server-test.ts +++ b/packages/remix-server-runtime/__tests__/server-test.ts @@ -1721,5 +1721,47 @@ describe("shared server runtime", () => { expect(calls.length).toBe(2 * DATA_CALL_MULTIPIER); expect(spy.console.mock.calls.length).toBe(1 * DATA_CALL_MULTIPIER); }); + + test("provides load context to server entrypoint", async () => { + let rootLoader = jest.fn(() => { + return "root"; + }); + let indexLoader = jest.fn(() => { + return "index"; + }); + let build = mockServerBuild({ + root: { + default: {}, + loader: rootLoader, + ErrorBoundary: {}, + }, + "routes/index": { + parentId: "root", + default: {}, + loader: indexLoader, + }, + }); + + build.entry.module.default = jest.fn( + async ( + request, + responseStatusCode, + responseHeaders, + entryContext, + loadContext + ) => + new Response(JSON.stringify(loadContext), { + status: responseStatusCode, + headers: responseHeaders, + }) + ); + + let handler = createRequestHandler(build, ServerMode.Development); + let request = new Request(`${baseUrl}/`, { method: "get" }); + let loadContext = { "load-context": "load-value" }; + + let result = await handler(request, loadContext); + expect(await result.text()).toBe(JSON.stringify(loadContext)); + }); }); }); diff --git a/packages/remix-server-runtime/__tests__/utils.ts b/packages/remix-server-runtime/__tests__/utils.ts index 806b189fd39..a9585d54fd5 100644 --- a/packages/remix-server-runtime/__tests__/utils.ts +++ b/packages/remix-server-runtime/__tests__/utils.ts @@ -48,7 +48,13 @@ export function mockServerBuild( entry: { module: { default: jest.fn( - async (request, responseStatusCode, responseHeaders, entryContext) => + async ( + request, + responseStatusCode, + responseHeaders, + entryContext, + loadContext + ) => new Response(null, { status: responseStatusCode, headers: responseHeaders, diff --git a/packages/remix-server-runtime/build.ts b/packages/remix-server-runtime/build.ts index 0c87b7c07ff..72518d33cef 100644 --- a/packages/remix-server-runtime/build.ts +++ b/packages/remix-server-runtime/build.ts @@ -1,6 +1,7 @@ import type { DataFunctionArgs } from "./routeModules"; import type { AssetsManifest, EntryContext, FutureConfig } from "./entry"; import type { ServerRouteManifest } from "./routes"; +import type { AppLoadContext } from "./data"; /** * The output of the compiler for the server build. @@ -22,7 +23,8 @@ export interface HandleDocumentRequestFunction { request: Request, responseStatusCode: number, responseHeaders: Headers, - context: EntryContext + context: EntryContext, + loadContext: AppLoadContext ): Promise | Response; } diff --git a/packages/remix-server-runtime/server.ts b/packages/remix-server-runtime/server.ts index 67817d3cd7b..174078e36ad 100644 --- a/packages/remix-server-runtime/server.ts +++ b/packages/remix-server-runtime/server.ts @@ -294,7 +294,8 @@ async function handleDocumentRequestRR( request, context.statusCode, headers, - entryContext + entryContext, + loadContext ); } catch (error: unknown) { // Get a new StaticHandlerContext that contains the error at the right boundary @@ -328,7 +329,8 @@ async function handleDocumentRequestRR( request, context.statusCode, headers, - entryContext + entryContext, + loadContext ); } catch (error: any) { logServerErrorIfNotAborted(error, request, serverMode);