Skip to content

Commit

Permalink
Merge branch 'dev' into markdalgleish/sync-routes-usage
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish committed Feb 15, 2024
2 parents 86ca484 + d8e0e97 commit 0e4404f
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 6 deletions.
5 changes: 5 additions & 0 deletions .changeset/proud-paws-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@remix-run/react": patch
---

Fix a bug with SPA mode when the root route had no children
2 changes: 1 addition & 1 deletion docs/file-conventions/root.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default function App() {
return <Outlet />;
}

export default function ErrorBoundary() {
export function ErrorBoundary() {
const error = useRouteError();

if (isRouteErrorResponse(error)) {
Expand Down
84 changes: 84 additions & 0 deletions integration/spa-mode-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<html>
<head>
<Meta />
<Links />
</head>
<body>
{children}
<ScrollRestoration />
<Scripts />
</body>
</html>
);
}
export default function Root() {
return (
<>
<h1 data-root>Root</h1>
<Routes>
<Route path="/" element={<h2 data-index>Index</h2>} />
</Routes>
</>
);
}
export function HydrateFallback() {
return <h1 data-loading>Loading SPA...</h1>;
}
`,
},
});
appFixture = await createAppFixture(fixture);

let res = await fixture.requestDocument("/");
let html = await res.text();
expect(html).toMatch('<h1 data-loading="true">Loading SPA...</h1>');

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", () => {
Expand Down
10 changes: 5 additions & 5 deletions packages/remix-react/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 0e4404f

Please sign in to comment.