Diese Anleitung hilft Ihnen, die Grundlagen von TanStack Start zu erlernen, unabhängig davon, wie Sie Ihr Projekt eingerichtet haben.
TanStack Start wird von Vite und TanStack Router angetrieben.
Dies ist die Datei, die das Verhalten des in Start verwendeten TanStack Routers bestimmt. Hier können Sie alles konfigurieren, von der Standard- Preloading-Funktionalität bis zur Staleness von Caches.
// app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})
return router
}
declare module '@tanstack/solid-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
// app/router.tsx
import { createRouter as createTanStackRouter } from '@tanstack/solid-router'
import { routeTree } from './routeTree.gen'
export function createRouter() {
const router = createTanStackRouter({
routeTree,
scrollRestoration: true,
})
return router
}
declare module '@tanstack/solid-router' {
interface Register {
router: ReturnType<typeof createRouter>
}
}
Die Datei routeTree.gen.ts wird generiert, wenn Sie TanStack Start (über npm run dev oder npm run start) zum ersten Mal ausführen. Diese Datei enthält den generierten Routenbaum und einige TS-Utilities, die TanStack Start vollständig typsicher machen.
Hinweis
Der serverseitige Einstiegspunkt ist standardmäßig optional. Wenn er nicht bereitgestellt wird, übernimmt TanStack Start den serverseitigen Einstiegspunkt automatisch für Sie, indem er den folgenden als Standard verwendet.
Dies geschieht über die Datei src/server.ts
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/solid-start/server'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
})(defaultStreamHandler)
// src/server.ts
import {
createStartHandler,
defaultStreamHandler,
} from '@tanstack/solid-start/server'
import { createRouter } from './router'
export default createStartHandler({
createRouter,
})(defaultStreamHandler)
Unabhängig davon, ob wir unsere App statisch generieren oder dynamisch ausliefern, ist die Datei server.ts der Einstiegspunkt für alle SSR-bezogenen Arbeiten.
Hinweis
Der clientseitige Einstiegspunkt ist standardmäßig optional. Wenn er nicht bereitgestellt wird, übernimmt TanStack Start den clientseitigen Einstiegspunkt automatisch für Sie, indem er den folgenden als Standard verwendet.
Unser HTML zum Client zu bringen ist nur die halbe Miete. Sobald es dort ist, müssen wir unser clientseitiges JavaScript hydrieren, sobald die Route zum Client aufgelöst wurde. Dies tun wir, indem wir die Wurzel unserer Anwendung mit der Komponente StartClient hydrieren.
// app/client.tsx
import { hydrate } from 'solid-js/web'
import { StartClient } from '@tanstack/solid-start'
import { createRouter } from './router'
const router = createRouter()
hydrate(() => <StartClient router={router} />, document)
// app/client.tsx
import { hydrate } from 'solid-js/web'
import { StartClient } from '@tanstack/solid-start'
import { createRouter } from './router'
const router = createRouter()
hydrate(() => <StartClient router={router} />, document)
Dies ermöglicht es uns, die clientseitige Weiterleitung zu starten, sobald die anfängliche Serveranfrage des Benutzers abgeschlossen ist.
Abgesehen vom clientseitigen Einstiegspunkt (der standardmäßig optional ist), ist die Route __root Ihrer Anwendung der Einstiegspunkt. Der Code in dieser Datei umschließt alle anderen Routen in der App, einschließlich Ihrer Startseite. Sie verhält sich wie eine pfadlose Layout-Route für Ihre gesamte Anwendung.
Da sie immer gerendert wird, ist sie der perfekte Ort, um Ihre Anwendungsoberfläche zu erstellen und globale Logik zu handhaben.
// app/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return <Outlet />
}
// app/routes/__root.tsx
import {
Outlet,
createRootRoute,
HeadContent,
Scripts,
} from '@tanstack/solid-router'
export const Route = createRootRoute({
head: () => ({
meta: [
{
charSet: 'utf-8',
},
{
name: 'viewport',
content: 'width=device-width, initial-scale=1',
},
{
title: 'TanStack Start Starter',
},
],
}),
component: RootComponent,
})
function RootComponent() {
return <Outlet />
}
Routen sind ein umfangreiches Feature von TanStack Router und werden im Routing-Leitfaden ausführlich behandelt. Zusammenfassend lässt sich sagen:
// app/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.validator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
<button
type="button"
onClick={() => {
updateCount({ data: 1 }).then(() => {
router.invalidate()
})
}}
>
Add 1 to {state}?
</button>
)
}
// app/routes/index.tsx
import * as fs from 'node:fs'
import { createFileRoute, useRouter } from '@tanstack/solid-router'
import { createServerFn } from '@tanstack/solid-start'
const filePath = 'count.txt'
async function readCount() {
return parseInt(
await fs.promises.readFile(filePath, 'utf-8').catch(() => '0'),
)
}
const getCount = createServerFn({
method: 'GET',
}).handler(() => {
return readCount()
})
const updateCount = createServerFn({ method: 'POST' })
.validator((d: number) => d)
.handler(async ({ data }) => {
const count = await readCount()
await fs.promises.writeFile(filePath, `${count + data}`)
})
export const Route = createFileRoute('/')({
component: Home,
loader: async () => await getCount(),
})
function Home() {
const router = useRouter()
const state = Route.useLoaderData()
return (
<button
type="button"
onClick={() => {
updateCount({ data: 1 }).then(() => {
router.invalidate()
})
}}
>
Add 1 to {state}?
</button>
)
}
TanStack Start baut zu 100 % auf TanStack Router auf, sodass Ihnen alle Navigationsfunktionen von TanStack Router zur Verfügung stehen. Zusammenfassend:
Hier ist ein kurzes Beispiel, wie Sie die Komponente Link verwenden können, um zu einer neuen Route zu navigieren.
import { Link } from '@tanstack/solid-router'
function Home() {
return <Link to="/about">About</Link>
}
import { Link } from '@tanstack/solid-router'
function Home() {
return <Link to="/about">About</Link>
}
Weitere detaillierte Informationen zur Navigation finden Sie im Navigationsleitfaden.
Sie haben vielleicht die Serverfunktion bemerkt, die wir oben mit createServerFn erstellt haben. Dies ist eine der leistungsstärksten Funktionen von TanStack, mit der Sie serverseitige Funktionen erstellen können, die sowohl vom Server während SSR als auch vom Client aufgerufen werden können!
Hier ist ein kurzer Überblick, wie Serverfunktionen funktionieren.
Hier ist ein kurzes Beispiel, wie Sie Serverfunktionen verwenden können, um Daten vom Server abzurufen und zurückzugeben.
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import { z } from 'zod'
const getUserById = createServerFn({ method: 'GET' })
// Always validate data sent to the function, here we use Zod
.validator(z.string())
// The handler function is where you perform the server-side logic
.handler(async ({ data }) => {
return db.query.users.findFirst({ where: eq(users.id, data) })
})
// Somewhere else in your application
const user = await getUserById({ data: '1' })
import { createServerFn } from '@tanstack/solid-start'
import * as fs from 'node:fs'
import { z } from 'zod'
const getUserById = createServerFn({ method: 'GET' })
// Always validate data sent to the function, here we use Zod
.validator(z.string())
// The handler function is where you perform the server-side logic
.handler(async ({ data }) => {
return db.query.users.findFirst({ where: eq(users.id, data) })
})
// Somewhere else in your application
const user = await getUserById({ data: '1' })
Um mehr über Serverfunktionen zu erfahren, besuchen Sie den Serverfunktionen-Leitfaden.
Serverfunktionen können auch verwendet werden, um Mutationen auf dem Server durchzuführen. Dies geschieht ebenfalls mit der gleichen Funktion createServerFn, jedoch mit der zusätzlichen Anforderung, dass Sie alle Daten auf dem Client invalidieren, die von der Mutation betroffen waren.
Hier ist ein kurzes Beispiel, wie Sie Serverfunktionen verwenden können, um eine Mutation auf dem Server durchzuführen und die Daten auf dem Client zu invalidieren.
import { createServerFn } from '@tanstack/solid-start'
const UserSchema = z.object({
id: z.string(),
name: z.string(),
})
const updateUser = createServerFn({ method: 'POST' })
.validator(UserSchema)
.handler(async ({ data }) => {
return db
.update(users)
.set({ name: data.name })
.where(eq(users.id, data.id))
})
// Somewhere else in your application
await updateUser({ data: { id: '1', name: 'John' } })
import { createServerFn } from '@tanstack/solid-start'
const UserSchema = z.object({
id: z.string(),
name: z.string(),
})
const updateUser = createServerFn({ method: 'POST' })
.validator(UserSchema)
.handler(async ({ data }) => {
return db
.update(users)
.set({ name: data.name })
.where(eq(users.id, data.id))
})
// Somewhere else in your application
await updateUser({ data: { id: '1', name: 'John' } })
Weitere Informationen zu Mutationen finden Sie im Mutationsleitfaden.
Eine weitere leistungsstarke Funktion von TanStack Router ist das Datenladen. Dies ermöglicht es Ihnen, Daten für SSR abzurufen und Routendaten vor dem Rendern vorab zu laden. Dies geschieht über die Funktion loader einer Route.
Hier ist ein kurzer Überblick, wie das Datenladen funktioniert.
Weitere Informationen zum Datenladen finden Sie im Datenlade-Leitfaden.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.