diff --git a/.changeset/fluffy-peas-promise.md b/.changeset/fluffy-peas-promise.md new file mode 100644 index 00000000000..b873d666ab0 --- /dev/null +++ b/.changeset/fluffy-peas-promise.md @@ -0,0 +1,5 @@ +--- +"@remix-run/server-runtime": patch +--- + +Add a more specific error if a user returns a `defer` response from a resource route diff --git a/integration/resource-routes-test.ts b/integration/resource-routes-test.ts index 11639ffaaed..def0f01e15b 100644 --- a/integration/resource-routes-test.ts +++ b/integration/resource-routes-test.ts @@ -57,6 +57,11 @@ test.describe("loader in an app", async () => { "app/routes/redirect-destination.tsx": js` export default () =>
You made it!
`, + "app/routes/defer.tsx": js` + import { defer } from "@remix-run/node"; + + export let loader = () => defer({ data: 'whatever' }); + `, "app/routes/data[.]json.tsx": js` import { json } from "@remix-run/node"; export let loader = () => json({hello: "world"}); @@ -252,6 +257,18 @@ test.describe("loader in an app", async () => { 'Route "routes/no-action" does not have an action' ); }); + + test("should error if a defer is returned from a resource route", async ({ + page, + }) => { + let app = new PlaywrightFixture(appFixture, page); + let res = await app.goto("/defer"); + expect(res.status()).toBe(500); + expect(await res.text()).toMatch( + "You cannot return a `defer()` response from a Resource Route. " + + 'Did you forget to export a default UI component from the "routes/defer" route?' + ); + }); }); test.describe("Development server", async () => { diff --git a/packages/remix-server-runtime/server.ts b/packages/remix-server-runtime/server.ts index e92933f74b2..ab5683ed784 100644 --- a/packages/remix-server-runtime/server.ts +++ b/packages/remix-server-runtime/server.ts @@ -425,6 +425,11 @@ async function handleResourceRequestRR( routeId, requestContext: loadContext, }); + invariant( + !(DEFERRED_SYMBOL in response), + `You cannot return a \`defer()\` response from a Resource Route. Did you ` + + `forget to export a default UI component from the "${routeId}" route?` + ); // callRouteLoader/callRouteAction always return responses invariant( isResponse(response),