@tanstack/cta-framework-react-cra 0.32.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/add-ons/start/assets/src/routes/demo/api.names.ts +2 -7
- package/add-ons/start/assets/src/routes/demo/start.server-funcs.tsx.ejs +15 -3
- package/package.json +2 -2
- package/tests/snapshots/react-cra/cr-ts-start-npm.json +2 -2
- package/tests/snapshots/react-cra/cr-ts-start-tanstack-query-npm.json +2 -2
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
+
import { json } from '@tanstack/react-start'
|
|
2
3
|
|
|
3
4
|
export const Route = createFileRoute('/demo/api/names')({
|
|
4
5
|
server: {
|
|
5
6
|
handlers: {
|
|
6
|
-
GET: () =>
|
|
7
|
-
return new Response(JSON.stringify(['Alice', 'Bob', 'Charlie']), {
|
|
8
|
-
headers: {
|
|
9
|
-
'Content-Type': 'application/json',
|
|
10
|
-
},
|
|
11
|
-
})
|
|
12
|
-
},
|
|
7
|
+
GET: () => json(['Alice', 'Bob', 'Charlie']),
|
|
13
8
|
},
|
|
14
9
|
},
|
|
15
10
|
})
|
|
@@ -44,11 +44,23 @@ import { useCallback, useState } from 'react'
|
|
|
44
44
|
import { createFileRoute, useRouter } from '@tanstack/react-router'
|
|
45
45
|
import { createServerFn } from '@tanstack/react-start'
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
/*
|
|
48
|
+
const loggingMiddleware = createMiddleware().server(
|
|
49
|
+
async ({ next, request }) => {
|
|
50
|
+
console.log("Request:", request.url);
|
|
51
|
+
return next();
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
const loggedServerFunction = createServerFn({ method: "GET" }).middleware([
|
|
55
|
+
loggingMiddleware,
|
|
56
|
+
]);
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
const TODOS_FILE = 'todos.json'
|
|
48
60
|
|
|
49
61
|
async function readTodos() {
|
|
50
62
|
return JSON.parse(
|
|
51
|
-
await fs.promises.readFile(
|
|
63
|
+
await fs.promises.readFile(TODOS_FILE, 'utf-8').catch(() =>
|
|
52
64
|
JSON.stringify(
|
|
53
65
|
[
|
|
54
66
|
{ id: 1, name: 'Get groceries' },
|
|
@@ -70,7 +82,7 @@ const addTodo = createServerFn({ method: 'POST' })
|
|
|
70
82
|
.handler(async ({ data }) => {
|
|
71
83
|
const todos = await readTodos()
|
|
72
84
|
todos.push({ id: todos.length + 1, name: data })
|
|
73
|
-
await fs.promises.writeFile(
|
|
85
|
+
await fs.promises.writeFile(TODOS_FILE, JSON.stringify(todos, null, 2))
|
|
74
86
|
return todos
|
|
75
87
|
})
|
|
76
88
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/cta-framework-react-cra",
|
|
3
|
-
"version": "0.32.
|
|
3
|
+
"version": "0.32.1",
|
|
4
4
|
"description": "CTA Framework for React (Create React App)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"author": "Jack Herrington <jherr@pobox.com>",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@tanstack/cta-engine": "0.32.
|
|
26
|
+
"@tanstack/cta-engine": "0.32.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^24.6.0",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"/src/data/demo.punk-songs.ts": "import { createServerFn } from '@tanstack/react-start'\n\nexport const getPunkSongs = createServerFn({\n method: 'GET',\n}).handler(async () => [\n { id: 1, name: 'Teenage Dirtbag', artist: 'Wheatus' },\n { id: 2, name: 'Smells Like Teen Spirit', artist: 'Nirvana' },\n { id: 3, name: 'The Middle', artist: 'Jimmy Eat World' },\n { id: 4, name: 'My Own Worst Enemy', artist: 'Lit' },\n { id: 5, name: 'Fat Lip', artist: 'Sum 41' },\n { id: 6, name: 'All the Small Things', artist: 'blink-182' },\n { id: 7, name: 'Beverly Hills', artist: 'Weezer' },\n])\n",
|
|
10
10
|
"/src/router.tsx": "import { createRouter } from '@tanstack/react-router'\n\n// Import the generated route tree\nimport { routeTree } from './routeTree.gen'\n\n// Create a new router instance\nexport const getRouter = () => {\n return createRouter({\n routeTree,\n scrollRestoration: true,\n defaultPreloadStaleTime: 0,\n })\n}\n",
|
|
11
11
|
"/src/routes/__root.tsx": "import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'\nimport { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'\nimport { TanStackDevtools } from '@tanstack/react-devtools'\n\nimport Header from '../components/Header'\n\nimport appCss from '../styles.css?url'\n\nexport const Route = createRootRoute({\n head: () => ({\n meta: [\n {\n charSet: 'utf-8',\n },\n {\n name: 'viewport',\n content: 'width=device-width, initial-scale=1',\n },\n {\n title: 'TanStack Start Starter',\n },\n ],\n links: [\n {\n rel: 'stylesheet',\n href: appCss,\n },\n ],\n }),\n\n shellComponent: RootDocument,\n})\n\nfunction RootDocument({ children }: { children: React.ReactNode }) {\n return (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n <Header />\n {children}\n <TanStackDevtools\n config={{\n position: 'bottom-right',\n }}\n plugins={[\n {\n name: 'Tanstack Router',\n render: <TanStackRouterDevtoolsPanel />,\n },\n ]}\n />\n <Scripts />\n </body>\n </html>\n )\n}\n",
|
|
12
|
-
"/src/routes/demo/api.names.ts": "import { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/demo/api/names')({\n server: {\n handlers: {\n GET: () =>
|
|
12
|
+
"/src/routes/demo/api.names.ts": "import { createFileRoute } from '@tanstack/react-router'\nimport { json } from '@tanstack/react-start'\n\nexport const Route = createFileRoute('/demo/api/names')({\n server: {\n handlers: {\n GET: () => json(['Alice', 'Bob', 'Charlie']),\n },\n },\n})\n",
|
|
13
13
|
"/src/routes/demo/start.api-request.tsx": "import { useEffect, useState } from 'react'\n\nimport { createFileRoute } from '@tanstack/react-router'\n\nfunction getNames() {\n return fetch('/demo/api/names').then((res) => res.json())\n}\n\nexport const Route = createFileRoute('/demo/start/api-request')({\n component: Home,\n})\n\nfunction Home() {\n const [names, setNames] = useState<Array<string>>([])\n\n useEffect(() => {\n getNames().then(setNames)\n }, [])\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen p-4 text-white\"\n style={{\n backgroundColor: '#000',\n backgroundImage:\n 'radial-gradient(ellipse 60% 60% at 0% 100%, #444 0%, #222 60%, #000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-2xl mb-4\">Start API Request Demo - Names List</h1>\n <ul className=\"mb-4 space-y-2\">\n {names.map((name) => (\n <li\n key={name}\n className=\"bg-white/10 border border-white/20 rounded-lg p-3 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white\">{name}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
14
|
-
"/src/routes/demo/start.server-funcs.tsx": "import fs from 'node:fs'\nimport { useCallback, useState } from 'react'\nimport { createFileRoute, useRouter } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\n\nconst
|
|
14
|
+
"/src/routes/demo/start.server-funcs.tsx": "import fs from 'node:fs'\nimport { useCallback, useState } from 'react'\nimport { createFileRoute, useRouter } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\n\n/*\nconst loggingMiddleware = createMiddleware().server(\n async ({ next, request }) => {\n console.log(\"Request:\", request.url);\n return next();\n }\n);\nconst loggedServerFunction = createServerFn({ method: \"GET\" }).middleware([\n loggingMiddleware,\n]);\n*/\n\nconst TODOS_FILE = 'todos.json'\n\nasync function readTodos() {\n return JSON.parse(\n await fs.promises.readFile(TODOS_FILE, 'utf-8').catch(() =>\n JSON.stringify(\n [\n { id: 1, name: 'Get groceries' },\n { id: 2, name: 'Buy a new phone' },\n ],\n null,\n 2,\n ),\n ),\n )\n}\n\nconst getTodos = createServerFn({\n method: 'GET',\n}).handler(async () => await readTodos())\n\nconst addTodo = createServerFn({ method: 'POST' })\n .inputValidator((d: string) => d)\n .handler(async ({ data }) => {\n const todos = await readTodos()\n todos.push({ id: todos.length + 1, name: data })\n await fs.promises.writeFile(TODOS_FILE, JSON.stringify(todos, null, 2))\n return todos\n })\n\nexport const Route = createFileRoute('/demo/start/server-funcs')({\n component: Home,\n loader: async () => await getTodos(),\n})\n\nfunction Home() {\n const router = useRouter()\n let todos = Route.useLoaderData()\n\n const [todo, setTodo] = useState('')\n\n const submitTodo = useCallback(async () => {\n todos = await addTodo({ data: todo })\n setTodo('')\n router.invalidate()\n }, [addTodo, todo])\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #23272a 0%, #18181b 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-2xl mb-4\">Start Server Functions - Todo Example</h1>\n <ul className=\"mb-4 space-y-2\">\n {todos?.map((t) => (\n <li\n key={t.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-3 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white\">{t.name}</span>\n </li>\n ))}\n </ul>\n <div className=\"flex flex-col gap-2\">\n <input\n type=\"text\"\n value={todo}\n onChange={(e) => setTodo(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n submitTodo()\n }\n }}\n placeholder=\"Enter a new todo...\"\n className=\"w-full px-4 py-3 rounded-lg border border-white/20 bg-white/10 backdrop-blur-sm text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent\"\n />\n <button\n disabled={todo.trim().length === 0}\n onClick={submitTodo}\n className=\"bg-blue-500 hover:bg-blue-600 disabled:bg-blue-500/50 disabled:cursor-not-allowed text-white font-bold py-3 px-4 rounded-lg transition-colors\"\n >\n Add todo\n </button>\n </div>\n </div>\n </div>\n )\n}\n",
|
|
15
15
|
"/src/routes/demo/start.ssr.data-only.tsx": "import { createFileRoute } from '@tanstack/react-router'\nimport { getPunkSongs } from '@/data/demo.punk-songs'\n\nexport const Route = createFileRoute('/demo/start/ssr/data-only')({\n ssr: 'data-only',\n component: RouteComponent,\n loader: async () => await getPunkSongs(),\n})\n\nfunction RouteComponent() {\n const punkSongs = Route.useLoaderData()\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-3xl font-bold mb-6 text-pink-400\">\n Data Only SSR - Punk Songs\n </h1>\n <ul className=\"space-y-3\">\n {punkSongs.map((song) => (\n <li\n key={song.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-4 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white font-medium\">\n {song.name}\n </span>\n <span className=\"text-white/60\"> - {song.artist}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
16
16
|
"/src/routes/demo/start.ssr.full-ssr.tsx": "import { createFileRoute } from '@tanstack/react-router'\nimport { getPunkSongs } from '@/data/demo.punk-songs'\n\nexport const Route = createFileRoute('/demo/start/ssr/full-ssr')({\n component: RouteComponent,\n loader: async () => await getPunkSongs(),\n})\n\nfunction RouteComponent() {\n const punkSongs = Route.useLoaderData()\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-3xl font-bold mb-6 text-purple-400\">\n Full SSR - Punk Songs\n </h1>\n <ul className=\"space-y-3\">\n {punkSongs.map((song) => (\n <li\n key={song.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-4 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white font-medium\">\n {song.name}\n </span>\n <span className=\"text-white/60\"> - {song.artist}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
17
17
|
"/src/routes/demo/start.ssr.index.tsx": "import { createFileRoute, Link } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/demo/start/ssr/')({\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-900 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-4xl font-bold mb-8 text-center bg-gradient-to-r from-pink-500 via-purple-500 to-green-400 bg-clip-text text-transparent\">\n SSR Demos\n </h1>\n <div className=\"flex flex-col gap-4\">\n <Link\n to=\"/demo/start/ssr/spa-mode\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-pink-600 to-pink-500 hover:from-pink-700 hover:to-pink-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-pink-500/50 border-2 border-pink-400\"\n >\n SPA Mode\n </Link>\n <Link\n to=\"/demo/start/ssr/full-ssr\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-purple-600 to-purple-500 hover:from-purple-700 hover:to-purple-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-purple-500/50 border-2 border-purple-400\"\n >\n Full SSR\n </Link>\n <Link\n to=\"/demo/start/ssr/data-only\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-green-500/50 border-2 border-green-400\"\n >\n Data Only\n </Link>\n </div>\n </div>\n </div>\n )\n}\n",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
"/src/integrations/tanstack-query/root-provider.tsx": "import { QueryClient, QueryClientProvider } from '@tanstack/react-query'\n\nexport function getContext() {\n const queryClient = new QueryClient()\n return {\n queryClient,\n }\n}\n\nexport function Provider({\n children,\n queryClient,\n}: {\n children: React.ReactNode\n queryClient: QueryClient\n}) {\n return (\n <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>\n )\n}\n",
|
|
12
12
|
"/src/router.tsx": "import { createRouter } from '@tanstack/react-router'\nimport { setupRouterSsrQueryIntegration } from '@tanstack/react-router-ssr-query'\nimport * as TanstackQuery from './integrations/tanstack-query/root-provider'\n\n// Import the generated route tree\nimport { routeTree } from './routeTree.gen'\n\n// Create a new router instance\nexport const getRouter = () => {\n const rqContext = TanstackQuery.getContext()\n\n const router = createRouter({\n routeTree,\n context: { ...rqContext },\n defaultPreload: 'intent',\n Wrap: (props: { children: React.ReactNode }) => {\n return (\n <TanstackQuery.Provider {...rqContext}>\n {props.children}\n </TanstackQuery.Provider>\n )\n },\n })\n\n setupRouterSsrQueryIntegration({ router, queryClient: rqContext.queryClient })\n\n return router\n}\n",
|
|
13
13
|
"/src/routes/__root.tsx": "import {\n HeadContent,\n Scripts,\n createRootRouteWithContext,\n} from '@tanstack/react-router'\nimport { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'\nimport { TanStackDevtools } from '@tanstack/react-devtools'\n\nimport Header from '../components/Header'\n\nimport TanStackQueryDevtools from '../integrations/tanstack-query/devtools'\n\nimport appCss from '../styles.css?url'\n\nimport type { QueryClient } from '@tanstack/react-query'\n\ninterface MyRouterContext {\n queryClient: QueryClient\n}\n\nexport const Route = createRootRouteWithContext<MyRouterContext>()({\n head: () => ({\n meta: [\n {\n charSet: 'utf-8',\n },\n {\n name: 'viewport',\n content: 'width=device-width, initial-scale=1',\n },\n {\n title: 'TanStack Start Starter',\n },\n ],\n links: [\n {\n rel: 'stylesheet',\n href: appCss,\n },\n ],\n }),\n\n shellComponent: RootDocument,\n})\n\nfunction RootDocument({ children }: { children: React.ReactNode }) {\n return (\n <html lang=\"en\">\n <head>\n <HeadContent />\n </head>\n <body>\n <Header />\n {children}\n <TanStackDevtools\n config={{\n position: 'bottom-right',\n }}\n plugins={[\n {\n name: 'Tanstack Router',\n render: <TanStackRouterDevtoolsPanel />,\n },\n TanStackQueryDevtools,\n ]}\n />\n <Scripts />\n </body>\n </html>\n )\n}\n",
|
|
14
|
-
"/src/routes/demo/api.names.ts": "import { createFileRoute } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/demo/api/names')({\n server: {\n handlers: {\n GET: () =>
|
|
14
|
+
"/src/routes/demo/api.names.ts": "import { createFileRoute } from '@tanstack/react-router'\nimport { json } from '@tanstack/react-start'\n\nexport const Route = createFileRoute('/demo/api/names')({\n server: {\n handlers: {\n GET: () => json(['Alice', 'Bob', 'Charlie']),\n },\n },\n})\n",
|
|
15
15
|
"/src/routes/demo/api.tq-todos.ts": "import { createFileRoute } from '@tanstack/react-router'\n\nconst todos = [\n {\n id: 1,\n name: 'Buy groceries',\n },\n {\n id: 2,\n name: 'Buy mobile phone',\n },\n {\n id: 3,\n name: 'Buy laptop',\n },\n]\n\nexport const Route = createFileRoute('/demo/api/tq-todos')({\n server: {\n handlers: {\n GET: () => {\n return Response.json(todos)\n },\n POST: async ({ request }) => {\n const name = await request.json()\n const todo = {\n id: todos.length + 1,\n name,\n }\n todos.push(todo)\n return Response.json(todo)\n },\n },\n },\n})\n",
|
|
16
16
|
"/src/routes/demo/start.api-request.tsx": "import { useQuery } from '@tanstack/react-query'\n\nimport { createFileRoute } from '@tanstack/react-router'\n\nfunction getNames() {\n return fetch('/demo/api/names').then((res) => res.json())\n}\n\nexport const Route = createFileRoute('/demo/start/api-request')({\n component: Home,\n})\n\nfunction Home() {\n const { data: names = [] } = useQuery({\n queryKey: ['names'],\n queryFn: getNames,\n })\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen p-4 text-white\"\n style={{\n backgroundColor: '#000',\n backgroundImage:\n 'radial-gradient(ellipse 60% 60% at 0% 100%, #444 0%, #222 60%, #000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-2xl mb-4\">Start API Request Demo - Names List</h1>\n <ul className=\"mb-4 space-y-2\">\n {names.map((name) => (\n <li\n key={name}\n className=\"bg-white/10 border border-white/20 rounded-lg p-3 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white\">{name}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
17
|
-
"/src/routes/demo/start.server-funcs.tsx": "import fs from 'node:fs'\nimport { useCallback, useState } from 'react'\nimport { createFileRoute, useRouter } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\n\nconst
|
|
17
|
+
"/src/routes/demo/start.server-funcs.tsx": "import fs from 'node:fs'\nimport { useCallback, useState } from 'react'\nimport { createFileRoute, useRouter } from '@tanstack/react-router'\nimport { createServerFn } from '@tanstack/react-start'\n\n/*\nconst loggingMiddleware = createMiddleware().server(\n async ({ next, request }) => {\n console.log(\"Request:\", request.url);\n return next();\n }\n);\nconst loggedServerFunction = createServerFn({ method: \"GET\" }).middleware([\n loggingMiddleware,\n]);\n*/\n\nconst TODOS_FILE = 'todos.json'\n\nasync function readTodos() {\n return JSON.parse(\n await fs.promises.readFile(TODOS_FILE, 'utf-8').catch(() =>\n JSON.stringify(\n [\n { id: 1, name: 'Get groceries' },\n { id: 2, name: 'Buy a new phone' },\n ],\n null,\n 2,\n ),\n ),\n )\n}\n\nconst getTodos = createServerFn({\n method: 'GET',\n}).handler(async () => await readTodos())\n\nconst addTodo = createServerFn({ method: 'POST' })\n .inputValidator((d: string) => d)\n .handler(async ({ data }) => {\n const todos = await readTodos()\n todos.push({ id: todos.length + 1, name: data })\n await fs.promises.writeFile(TODOS_FILE, JSON.stringify(todos, null, 2))\n return todos\n })\n\nexport const Route = createFileRoute('/demo/start/server-funcs')({\n component: Home,\n loader: async () => await getTodos(),\n})\n\nfunction Home() {\n const router = useRouter()\n let todos = Route.useLoaderData()\n\n const [todo, setTodo] = useState('')\n\n const submitTodo = useCallback(async () => {\n todos = await addTodo({ data: todo })\n setTodo('')\n router.invalidate()\n }, [addTodo, todo])\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #23272a 0%, #18181b 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-2xl mb-4\">Start Server Functions - Todo Example</h1>\n <ul className=\"mb-4 space-y-2\">\n {todos?.map((t) => (\n <li\n key={t.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-3 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white\">{t.name}</span>\n </li>\n ))}\n </ul>\n <div className=\"flex flex-col gap-2\">\n <input\n type=\"text\"\n value={todo}\n onChange={(e) => setTodo(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n submitTodo()\n }\n }}\n placeholder=\"Enter a new todo...\"\n className=\"w-full px-4 py-3 rounded-lg border border-white/20 bg-white/10 backdrop-blur-sm text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:border-transparent\"\n />\n <button\n disabled={todo.trim().length === 0}\n onClick={submitTodo}\n className=\"bg-blue-500 hover:bg-blue-600 disabled:bg-blue-500/50 disabled:cursor-not-allowed text-white font-bold py-3 px-4 rounded-lg transition-colors\"\n >\n Add todo\n </button>\n </div>\n </div>\n </div>\n )\n}\n",
|
|
18
18
|
"/src/routes/demo/start.ssr.data-only.tsx": "import { createFileRoute } from '@tanstack/react-router'\nimport { getPunkSongs } from '@/data/demo.punk-songs'\n\nexport const Route = createFileRoute('/demo/start/ssr/data-only')({\n ssr: 'data-only',\n component: RouteComponent,\n loader: async () => await getPunkSongs(),\n})\n\nfunction RouteComponent() {\n const punkSongs = Route.useLoaderData()\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-3xl font-bold mb-6 text-pink-400\">\n Data Only SSR - Punk Songs\n </h1>\n <ul className=\"space-y-3\">\n {punkSongs.map((song) => (\n <li\n key={song.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-4 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white font-medium\">\n {song.name}\n </span>\n <span className=\"text-white/60\"> - {song.artist}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
19
19
|
"/src/routes/demo/start.ssr.full-ssr.tsx": "import { createFileRoute } from '@tanstack/react-router'\nimport { getPunkSongs } from '@/data/demo.punk-songs'\n\nexport const Route = createFileRoute('/demo/start/ssr/full-ssr')({\n component: RouteComponent,\n loader: async () => await getPunkSongs(),\n})\n\nfunction RouteComponent() {\n const punkSongs = Route.useLoaderData()\n\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-800 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-3xl font-bold mb-6 text-purple-400\">\n Full SSR - Punk Songs\n </h1>\n <ul className=\"space-y-3\">\n {punkSongs.map((song) => (\n <li\n key={song.id}\n className=\"bg-white/10 border border-white/20 rounded-lg p-4 backdrop-blur-sm shadow-md\"\n >\n <span className=\"text-lg text-white font-medium\">\n {song.name}\n </span>\n <span className=\"text-white/60\"> - {song.artist}</span>\n </li>\n ))}\n </ul>\n </div>\n </div>\n )\n}\n",
|
|
20
20
|
"/src/routes/demo/start.ssr.index.tsx": "import { createFileRoute, Link } from '@tanstack/react-router'\n\nexport const Route = createFileRoute('/demo/start/ssr/')({\n component: RouteComponent,\n})\n\nfunction RouteComponent() {\n return (\n <div\n className=\"flex items-center justify-center min-h-screen bg-gradient-to-br from-zinc-900 to-black p-4 text-white\"\n style={{\n backgroundImage:\n 'radial-gradient(50% 50% at 20% 60%, #1a1a1a 0%, #0a0a0a 50%, #000000 100%)',\n }}\n >\n <div className=\"w-full max-w-2xl p-8 rounded-xl backdrop-blur-md bg-black/50 shadow-xl border-8 border-black/10\">\n <h1 className=\"text-4xl font-bold mb-8 text-center bg-gradient-to-r from-pink-500 via-purple-500 to-green-400 bg-clip-text text-transparent\">\n SSR Demos\n </h1>\n <div className=\"flex flex-col gap-4\">\n <Link\n to=\"/demo/start/ssr/spa-mode\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-pink-600 to-pink-500 hover:from-pink-700 hover:to-pink-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-pink-500/50 border-2 border-pink-400\"\n >\n SPA Mode\n </Link>\n <Link\n to=\"/demo/start/ssr/full-ssr\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-purple-600 to-purple-500 hover:from-purple-700 hover:to-purple-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-purple-500/50 border-2 border-purple-400\"\n >\n Full SSR\n </Link>\n <Link\n to=\"/demo/start/ssr/data-only\"\n className=\"text-2xl font-bold py-6 px-8 rounded-lg bg-gradient-to-r from-green-500 to-emerald-500 hover:from-green-600 hover:to-emerald-600 text-white text-center shadow-lg transform transition-all hover:scale-105 hover:shadow-green-500/50 border-2 border-green-400\"\n >\n Data Only\n </Link>\n </div>\n </div>\n </div>\n )\n}\n",
|