Switch from Router to Start (Enable SSR!)

A real pain to change mid-road.
This commit is contained in:
2025-03-31 17:41:00 +02:00
parent af080480e4
commit a6df580ff9
11 changed files with 3999 additions and 148 deletions

16
app.config.ts Normal file
View File

@@ -0,0 +1,16 @@
// app.config.ts
import { defineConfig } from '@tanstack/react-start/config'
import tsConfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
tsr: {
appDirectory: 'src',
},
vite: {
plugins: [
tsConfigPaths({
projects: ['./tsconfig.json'],
}),
],
},
})

View File

@@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" href="/favicon.ico"/>
<meta
name="description"
content="TanStack/Router Address Book"
/>
<link rel="apple-touch-icon" href="/logo192.png"/>
<link rel="manifest" href="/manifest.json"/>
<title>Create TanStack App - tsr-address-book</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View File

@@ -3,20 +3,22 @@
"private": true,
"type": "module",
"scripts": {
"start": "vite --port 3000",
"build": "vite build && tsc",
"serve": "vite preview",
"dev": "vinxi dev",
"build": "vinxi build",
"start": "vinxi start",
"test": "vitest run"
},
"dependencies": {
"@tanstack/react-router": "^1.114.3",
"@tanstack/react-router-devtools": "^1.114.3",
"@tanstack/router-plugin": "^1.114.3",
"@tanstack/react-router": "^1.114.29",
"@tanstack/react-router-devtools": "^1.114.29",
"@tanstack/react-start": "^1.114.30",
"@tanstack/router-plugin": "^1.114.30",
"match-sorter": "^8.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"match-sorter": "^8.0.0",
"sort-by": "^1.2.0",
"tiny-invariant": "^1.3.3"
"tiny-invariant": "^1.3.3",
"vinxi": "^0.5.3"
},
"devDependencies": {
"@eslint/js": "^9.23.0",
@@ -33,11 +35,13 @@
"typescript": "^5.8.2",
"typescript-eslint": "^8.28.0",
"vite": "^6.1.0",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.0.5",
"web-vitals": "^4.2.4"
},
"pnpm": {
"onlyBuiltDependencies": [
"@parcel/watcher",
"esbuild"
]
}

3946
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

14
src/client.tsx Normal file
View File

@@ -0,0 +1,14 @@
/// <reference types="vinxi/types/client" />
import { hydrateRoot } from 'react-dom/client';
import { StartClient } from '@tanstack/react-start';
import { createRouter } from './router';
import reportWebVitals from "@/reportWebVitals.ts";
const router = createRouter();
hydrateRoot(document, <StartClient router={router}/>);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

View File

@@ -1,41 +0,0 @@
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { RouterProvider, createRouter } from '@tanstack/react-router';
// Import the generated route tree
import { routeTree } from './routeTree.gen';
import reportWebVitals from './reportWebVitals.ts';
// Create a new router instance
const router = createRouter({
routeTree,
context: {},
defaultPreload: 'intent',
scrollRestoration: true,
defaultStructuralSharing: true,
defaultPreloadStaleTime: 0,
});
// Register the router instance for type safety
declare module '@tanstack/react-router' {
interface Register {
router: typeof router;
}
}
// Render the app
const rootElement = document.getElementById('app');
if (rootElement && !rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<StrictMode>
<RouterProvider router={router}/>
</StrictMode>,
);
}
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

16
src/router.tsx Normal file
View File

@@ -0,0 +1,16 @@
import { createRouter as createTanStackRouter } from '@tanstack/react-router';
import { routeTree } from './routeTree.gen';
export function createRouter() {
return createTanStackRouter({
routeTree,
defaultPreload: 'intent',
scrollRestoration: true,
})
}
declare module '@tanstack/react-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}

View File

@@ -1,6 +1,8 @@
import { Outlet, createRootRoute, Link } from '@tanstack/react-router';
import { Outlet, createRootRoute, Link, HeadContent, Scripts } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
import appCss from '@/App.css?url';
import { getContacts } from "@/data";
import type { ReactNode } from "react";
async function fetchContacts() {
const contacts = await getContacts();
@@ -9,6 +11,24 @@ async function fetchContacts() {
export const Route = createRootRoute({
loader: fetchContacts,
head: () => ({
meta: [{
charSet: 'utf-8',
}, {
name: 'viewport', content: 'width=device-width, initial-scale=1'
}, {
name: 'description', content: 'TanStack/Router Address Book'
}],
links: [{
rel: 'stylesheet', href: appCss
}, {
rel: 'icon', href: '/favicon.ico'
}, {
rel: 'apple-touch-icon', href: '/logo192.png'
}, {
rel: 'manifest', href: '/manifest.json'
}]
}),
component: RootLayout,
notFoundComponent: NotFoundComponent,
});
@@ -17,7 +37,7 @@ function RootLayout() {
const { contacts } = Route.useLoaderData();
return (
<>
<RootDocument>
<div id="sidebar">
<h1>React Router Contacts</h1>
<div>
@@ -66,7 +86,21 @@ function RootLayout() {
<Outlet/>
</div>
<TanStackRouterDevtools/>
</>
</RootDocument>
);
}
function RootDocument({ children }: Readonly<{ children: ReactNode }>) {
return (
<html>
<head>
<HeadContent/>
</head>
<body>
{children}
<Scripts/>
</body>
</html>
);
}

View File

@@ -1,5 +1,4 @@
import { createFileRoute } from '@tanstack/react-router';
import '../App.css';
export const Route = createFileRoute('/')({
component: App,

13
src/ssr.tsx Normal file
View File

@@ -0,0 +1,13 @@
/// <reference types="vinxi/types/server" />
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/react-start/server'
import { getRouterManifest } from '@tanstack/react-start/router-manifest'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
getRouterManifest,
})(defaultStreamHandler)

View File

@@ -1,21 +0,0 @@
// noinspection JSUnresolvedReference
import { defineConfig } from "vite";
import viteReact from "@vitejs/plugin-react";
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
import { resolve } from "node:path";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [TanStackRouterVite({ autoCodeSplitting: true }), viteReact()],
test: {
globals: true,
environment: "jsdom",
},
resolve: {
alias: {
// eslint-disable-next-line no-undef
'@': resolve(__dirname, './src'),
},
}
});