From 16146caec3e748f512d4b69e8b2ac7392b8b0718 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 13 Feb 2024 16:38:48 -0500 Subject: [PATCH 1/3] Handle scenario where there is only a root route in SPA mode --- packages/remix-react/routes.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/remix-react/routes.tsx b/packages/remix-react/routes.tsx index 22671a29f01..8975c093a27 100644 --- a/packages/remix-react/routes.tsx +++ b/packages/remix-react/routes.tsx @@ -148,11 +148,11 @@ export function createServerRoutes( index: route.index, path: route.path, handle: routeModule.handle, - // For SPA Mode, all routes are lazy except root. We don't need a full - // implementation here though - just need a `lazy` prop to tell the RR - // rendering where to stop - lazy: - isSpaMode && route.id !== "root" ? () => spaModeLazyPromise : undefined, + // For SPA Mode, all routes are lazy except root. However we tell the + // router root is also lazy here too since we don't need a full + // implementation - we just need a `lazy` prop to tell the RR rendering + // where to stop which is always at the root route in SPA mode + lazy: isSpaMode ? () => spaModeLazyPromise : undefined, // For partial hydration rendering, we need to indicate when the route // has a loader/clientLoader, but it won't ever be called during the static // render, so just give it a no-op function so we can render down to the From a90823ca231e2520acf48a2cf8cd69db797f0761 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 13 Feb 2024 17:22:10 -0500 Subject: [PATCH 2/3] Add integration test --- integration/spa-mode-test.ts | 84 ++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/integration/spa-mode-test.ts b/integration/spa-mode-test.ts index f71a84d32cd..afcd7bc3205 100644 --- a/integration/spa-mode-test.ts +++ b/integration/spa-mode-test.ts @@ -431,6 +431,90 @@ test.describe("SPA Mode", () => { "Index Loader Data" ); }); + + test("works for migration apps with only a root route and no loader", async ({ + page, + }) => { + fixture = await createFixture({ + compiler: "vite", + spaMode: true, + files: { + "vite.config.ts": js` + import { defineConfig } from "vite"; + import { vitePlugin as remix } from "@remix-run/dev"; + + export default defineConfig({ + plugins: [remix({ + // We don't want to pick up the app/routes/_index.tsx file from + // the template and instead want to use only the src/root.tsx + // file below + appDirectory: "src", + ssr: false, + })], + }); + `, + "src/root.tsx": js` + import { + Meta, + Links, + Outlet, + Routes, + Route, + Scripts, + ScrollRestoration, + } from "@remix-run/react"; + + export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + {children} + + + + + ); + } + + export default function Root() { + return ( + <> +

Root

+ + Index} /> + + + ); + } + + export function HydrateFallback() { + return

Loading SPA...

; + } + `, + }, + }); + appFixture = await createAppFixture(fixture); + + let res = await fixture.requestDocument("/"); + let html = await res.text(); + expect(html).toMatch('

Loading SPA...

'); + + let logs: string[] = []; + page.on("console", (msg) => logs.push(msg.text())); + + let app = new PlaywrightFixture(appFixture, page); + await app.goto("/"); + await page.waitForSelector("[data-root]"); + expect(await page.locator("[data-root]").textContent()).toBe("Root"); + expect(await page.locator("[data-index]").textContent()).toBe("Index"); + + // Hydrates without issues + expect(logs).toEqual([]); + }); }); test.describe("normal apps", () => { From 1e20ee4055ff4eb3b2e37be6fc32e304db72c90a Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 13 Feb 2024 17:27:44 -0500 Subject: [PATCH 3/3] Add changeset --- .changeset/proud-paws-hope.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/proud-paws-hope.md diff --git a/.changeset/proud-paws-hope.md b/.changeset/proud-paws-hope.md new file mode 100644 index 00000000000..ed1fd80180d --- /dev/null +++ b/.changeset/proud-paws-hope.md @@ -0,0 +1,5 @@ +--- +"@remix-run/react": patch +--- + +Fix a bug with SPA mode when the root route had no children