diff --git a/contributors.yml b/contributors.yml
index 9f0d1ef1b0e..cc104637fdc 100644
--- a/contributors.yml
+++ b/contributors.yml
@@ -140,6 +140,7 @@
- F3n67u
- federicoestevez
- fergusmeiklejohn
+- fernandojbf
- fgiuliani
- fishel-feng
- francisudeji
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);