Skip to content

Commit 26e97be

Browse files
authored
ssr support for tanstack router (#1840)
1 parent cceb4ed commit 26e97be

File tree

11 files changed

+96
-47
lines changed

11 files changed

+96
-47
lines changed

.changeset/shy-rivers-punch.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@solidjs/start": patch
3+
---
4+
5+
get ssr working for tanstack router example

examples/with-tanstack-router/app.config.ts

-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { defineConfig } from "@solidjs/start/config";
22
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
33

44
export default defineConfig({
5-
ssr: false,
65
vite: {
76
plugins: [TanStackRouterVite({ target: "solid" })]
87
}
+2-17
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
1-
import { RouterProvider, createRouter } from "@tanstack/solid-router";
2-
import { routeTree } from "./routeTree.gen";
1+
import { router } from "./router";
2+
import { RouterProvider } from "@tanstack/solid-router";
33

44
import "./app.css";
55

6-
const router = createRouter({
7-
defaultErrorComponent: (err) => <div>{err.error.stack}</div>,
8-
routeTree,
9-
defaultPreload: "intent",
10-
defaultStaleTime: 5000,
11-
scrollRestoration: true
12-
});
13-
14-
// Register things for typesafety
15-
declare module "@tanstack/solid-router" {
16-
interface Register {
17-
router: typeof router;
18-
}
19-
}
20-
216
export default function App() {
227
return <RouterProvider router={router} />;
238
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
// @refresh reload
2-
import { mount, StartClient } from "@solidjs/start/client";
2+
import { mount, StartClientTanstack } from "@solidjs/start/client";
33

4-
mount(() => <StartClient />, document.getElementById("app")!);
4+
mount(() => <StartClientTanstack />, document.getElementById("app")!);
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,40 @@
11
// @refresh reload
2-
import { createHandler, StartServer } from "@solidjs/start/server";
2+
import { createHandler, FetchEvent, StartServer } from "@solidjs/start/server";
3+
import { createMemoryHistory } from "@tanstack/solid-router";
4+
import { router } from "./router";
35

4-
export default createHandler(() => (
5-
<StartServer
6-
document={({ assets, children, scripts }) => (
7-
<html lang="en">
8-
<head>
9-
<meta charset="utf-8" />
10-
<meta name="viewport" content="width=device-width, initial-scale=1" />
11-
<link rel="icon" href="/favicon.ico" />
12-
{assets}
13-
</head>
14-
<body>
15-
<div id="app">{children}</div>
16-
{scripts}
17-
</body>
18-
</html>
19-
)}
20-
/>
21-
));
6+
const routerLoad = async (event: FetchEvent) => {
7+
const url = new URL(event.request.url);
8+
const path = url.href.replace(url.origin, "");
9+
10+
router.update({
11+
history: createMemoryHistory({
12+
initialEntries: [path]
13+
})
14+
});
15+
16+
await router.load();
17+
};
18+
19+
export default createHandler(
20+
() => (
21+
<StartServer
22+
document={({ assets, children, scripts }) => (
23+
<html lang="en">
24+
<head>
25+
<meta charset="utf-8" />
26+
<meta name="viewport" content="width=device-width, initial-scale=1" />
27+
<link rel="icon" href="/favicon.ico" />
28+
{assets}
29+
</head>
30+
<body>
31+
<div id="app">{children}</div>
32+
{scripts}
33+
</body>
34+
</html>
35+
)}
36+
/>
37+
),
38+
undefined,
39+
routerLoad
40+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { createRouter as createTanstackSolidRouter } from "@tanstack/solid-router";
2+
import { routeTree } from "./routeTree.gen";
3+
4+
export function createRouter() {
5+
const router = createTanstackSolidRouter({
6+
defaultErrorComponent: err => <div>{err.error.stack}</div>,
7+
routeTree,
8+
defaultPreload: "intent",
9+
defaultStaleTime: 5000,
10+
scrollRestoration: true
11+
});
12+
return router;
13+
}
14+
15+
export const router = createRouter();
16+
17+
// Register things for typesafety
18+
declare module "@tanstack/solid-router" {
19+
interface Register {
20+
router: ReturnType<typeof createRouter>;
21+
}
22+
}

packages/start/src/client/StartClient.tsx

+10
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,13 @@ export function StartClient() {
2424
</Dummy>
2525
);
2626
}
27+
28+
export function StartClientTanstack() {
29+
return (
30+
<Dummy>
31+
<ErrorBoundary>
32+
<App />
33+
</ErrorBoundary>
34+
</Dummy>
35+
);
36+
}

packages/start/src/client/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// @refresh skip
22
import "vinxi/client";
3-
export { StartClient } from "./StartClient";
3+
export { StartClient, StartClientTanstack } from "./StartClient";
44
export { mount } from "./mount";
55

packages/start/src/client/spa/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ export function mount(fn: () => JSX.Element, el: MountableElement) {
77
render(fn, el);
88
}
99

10-
export { StartClient } from "../StartClient";
10+
export { StartClient, StartClientTanstack } from "../StartClient";

packages/start/src/server/handler.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,24 @@ export function getExpectedRedirectStatus(response: ResponseStub): number {
3131
export function createBaseHandler(
3232
fn: (context: PageEvent) => unknown,
3333
createPageEvent: (event: FetchEvent) => Promise<PageEvent>,
34-
options: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {}
34+
options: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>) = {},
35+
routerLoad?: (event: FetchEvent) => Promise<void>
3536
) {
3637
return eventHandler({
3738
handler: (e: HTTPEvent) => {
3839
const event = getFetchEvent(e);
3940

4041
return provideRequestEvent(event, async () => {
42+
if (routerLoad) {
43+
await routerLoad(event);
44+
}
45+
4146
// api
4247
const match = matchAPIRoute(new URL(event.request.url).pathname, event.request.method);
4348
if (match) {
4449
const mod = await match.handler.import();
45-
const fn = event.request.method === "HEAD" ? mod["HEAD"] || mod["GET"] : mod[event.request.method];
50+
const fn =
51+
event.request.method === "HEAD" ? mod["HEAD"] || mod["GET"] : mod[event.request.method];
4652
(event as APIEvent).params = match.params || {};
4753
// @ts-ignore
4854
sharedConfig.context = { event };
@@ -62,6 +68,7 @@ export function createBaseHandler(
6268
const mode = resolvedOptions.mode || "stream";
6369
// @ts-ignore
6470
if (resolvedOptions.nonce) context.nonce = resolvedOptions.nonce;
71+
6572
if (mode === "sync" || !import.meta.env.START_SSR) {
6673
const html = renderToString(() => {
6774
(sharedConfig.context as any).event = context;
@@ -130,7 +137,8 @@ function handleStreamCompleteRedirect(context: PageEvent) {
130137
*/
131138
export function createHandler(
132139
fn: (context: PageEvent) => unknown,
133-
options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>)
140+
options?: HandlerOptions | ((context: PageEvent) => HandlerOptions | Promise<HandlerOptions>),
141+
routerLoad?: (event: FetchEvent) => Promise<void>
134142
) {
135-
return createBaseHandler(fn, createPageEvent, options);
143+
return createBaseHandler(fn, createPageEvent, options, routerLoad);
136144
}

packages/start/src/server/spa/handler.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import { FetchEvent, HandlerOptions, PageEvent } from "../types";
77
*/
88
export function createHandler(
99
fn: (context: PageEvent) => unknown,
10-
options?: HandlerOptions | ((context: PageEvent) => HandlerOptions)
10+
options?: HandlerOptions | ((context: PageEvent) => HandlerOptions),
11+
routerLoad?: (event: FetchEvent) => Promise<void>
1112
) {
12-
return createBaseHandler(fn, createPageEvent, options);
13+
return createBaseHandler(fn, createPageEvent, options, routerLoad);
1314
}
1415

1516
export async function createPageEvent(ctx: FetchEvent) {

0 commit comments

Comments
 (0)