Skip to content

Commit d2b98c5

Browse files
committed
tanstack start example
1 parent 6c79901 commit d2b98c5

30 files changed

Lines changed: 18199 additions & 0 deletions

examples/tanstack-start/.cta.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"projectName": "tanstack-start",
3+
"mode": "file-router",
4+
"typescript": true,
5+
"packageManager": "bun",
6+
"includeExamples": true,
7+
"tailwind": true,
8+
"addOnOptions": {},
9+
"envVarValues": {},
10+
"git": false,
11+
"routerOnly": false,
12+
"version": 1,
13+
"framework": "react",
14+
"chosenAddOns": []
15+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# This env file uses @env-spec - see https://varlock.dev/env-spec for more info
2+
#
3+
# @defaultRequired=infer @defaultSensitive=false
4+
# @generateTypes(lang=ts, path=env.d.ts)
5+
# ----------
6+
7+
# @sensitive
8+
SENSITIVE_VAR=ffshhh-im-secret
9+
10+
# @sensitive
11+
ANOTHER_SECRET=another-secret-val
12+
13+
PUBLIC_ITEM=not-a-secret
14+
15+
PUBLIC_OTHER=also-public
16+
17+
VITE_PREFIXED_ITEM=vite-prefixed-val

examples/tanstack-start/.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
.env
7+
.nitro
8+
.tanstack
9+
.wrangler
10+
.output
11+
.vinxi
12+
__unconfig*
13+
todos.json
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"files.watcherExclude": {
3+
"**/routeTree.gen.ts": true
4+
},
5+
"search.exclude": {
6+
"**/routeTree.gen.ts": true
7+
},
8+
"files.readonlyInclude": {
9+
"**/routeTree.gen.ts": true
10+
}
11+
}

examples/tanstack-start/README.md

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
Welcome to your new TanStack Start app!
2+
3+
# Getting Started
4+
5+
To run this application:
6+
7+
```bash
8+
bun install
9+
bun --bun run dev
10+
```
11+
12+
# Building For Production
13+
14+
To build this application for production:
15+
16+
```bash
17+
bun --bun run build
18+
```
19+
20+
## Testing
21+
22+
This project uses [Vitest](https://vitest.dev/) for testing. You can run the tests with:
23+
24+
```bash
25+
bun --bun run test
26+
```
27+
28+
## Styling
29+
30+
This project uses [Tailwind CSS](https://tailwindcss.com/) for styling.
31+
32+
### Removing Tailwind CSS
33+
34+
If you prefer not to use Tailwind CSS:
35+
36+
1. Remove the demo pages in `src/routes/demo/`
37+
2. Replace the Tailwind import in `src/styles.css` with your own styles
38+
3. Remove `tailwindcss()` from the plugins array in `vite.config.ts`
39+
4. Uninstall the packages: `bun install @tailwindcss/vite tailwindcss -D`
40+
41+
42+
43+
## Routing
44+
45+
This project uses [TanStack Router](https://tanstack.com/router) with file-based routing. Routes are managed as files in `src/routes`.
46+
47+
### Adding A Route
48+
49+
To add a new route to your application just add a new file in the `./src/routes` directory.
50+
51+
TanStack will automatically generate the content of the route file for you.
52+
53+
Now that you have two routes you can use a `Link` component to navigate between them.
54+
55+
### Adding Links
56+
57+
To use SPA (Single Page Application) navigation you will need to import the `Link` component from `@tanstack/react-router`.
58+
59+
```tsx
60+
import { Link } from "@tanstack/react-router";
61+
```
62+
63+
Then anywhere in your JSX you can use it like so:
64+
65+
```tsx
66+
<Link to="/about">About</Link>
67+
```
68+
69+
This will create a link that will navigate to the `/about` route.
70+
71+
More information on the `Link` component can be found in the [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent).
72+
73+
### Using A Layout
74+
75+
In the File Based Routing setup the layout is located in `src/routes/__root.tsx`. Anything you add to the root route will appear in all the routes. The route content will appear in the JSX where you render `{children}` in the `shellComponent`.
76+
77+
Here is an example layout that includes a header:
78+
79+
```tsx
80+
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
81+
82+
export const Route = createRootRoute({
83+
head: () => ({
84+
meta: [
85+
{ charSet: 'utf-8' },
86+
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
87+
{ title: 'My App' },
88+
],
89+
}),
90+
shellComponent: ({ children }) => (
91+
<html lang="en">
92+
<head>
93+
<HeadContent />
94+
</head>
95+
<body>
96+
<header>
97+
<nav>
98+
<Link to="/">Home</Link>
99+
<Link to="/about">About</Link>
100+
</nav>
101+
</header>
102+
{children}
103+
<Scripts />
104+
</body>
105+
</html>
106+
),
107+
})
108+
```
109+
110+
More information on layouts can be found in the [Layouts documentation](https://tanstack.com/router/latest/docs/framework/react/guide/routing-concepts#layouts).
111+
112+
## Server Functions
113+
114+
TanStack Start provides server functions that allow you to write server-side code that seamlessly integrates with your client components.
115+
116+
```tsx
117+
import { createServerFn } from '@tanstack/react-start'
118+
119+
const getServerTime = createServerFn({
120+
method: 'GET',
121+
}).handler(async () => {
122+
return new Date().toISOString()
123+
})
124+
125+
// Use in a component
126+
function MyComponent() {
127+
const [time, setTime] = useState('')
128+
129+
useEffect(() => {
130+
getServerTime().then(setTime)
131+
}, [])
132+
133+
return <div>Server time: {time}</div>
134+
}
135+
```
136+
137+
## API Routes
138+
139+
You can create API routes by using the `server` property in your route definitions:
140+
141+
```tsx
142+
import { createFileRoute } from '@tanstack/react-router'
143+
import { json } from '@tanstack/react-start'
144+
145+
export const Route = createFileRoute('/api/hello')({
146+
server: {
147+
handlers: {
148+
GET: () => json({ message: 'Hello, World!' }),
149+
},
150+
},
151+
})
152+
```
153+
154+
## Data Fetching
155+
156+
There are multiple ways to fetch data in your application. You can use TanStack Query to fetch data from a server. But you can also use the `loader` functionality built into TanStack Router to load the data for a route before it's rendered.
157+
158+
For example:
159+
160+
```tsx
161+
import { createFileRoute } from '@tanstack/react-router'
162+
163+
export const Route = createFileRoute('/people')({
164+
loader: async () => {
165+
const response = await fetch('https://swapi.dev/api/people')
166+
return response.json()
167+
},
168+
component: PeopleComponent,
169+
})
170+
171+
function PeopleComponent() {
172+
const data = Route.useLoaderData()
173+
return (
174+
<ul>
175+
{data.results.map((person) => (
176+
<li key={person.name}>{person.name}</li>
177+
))}
178+
</ul>
179+
)
180+
}
181+
```
182+
183+
Loaders simplify your data fetching logic dramatically. Check out more information in the [Loader documentation](https://tanstack.com/router/latest/docs/framework/react/guide/data-loading#loader-parameters).
184+
185+
# Demo files
186+
187+
Files prefixed with `demo` can be safely deleted. They are there to provide a starting point for you to play around with the features you've installed.
188+
189+
# Learn More
190+
191+
You can learn more about all of the offerings from TanStack in the [TanStack documentation](https://tanstack.com).
192+
193+
For TanStack Start specific documentation, visit [TanStack Start](https://tanstack.com/start).
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
env = false

examples/tanstack-start/env.d.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
2+
// 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑
3+
// 🛑 THIS IS AN AUTOGENERATED FILE - DO NOT EDIT DIRECTLY 🛑
4+
// 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑 🛑
5+
6+
// @ts-nocheck
7+
/* eslint-disable */
8+
export type CoercedEnvSchema = {
9+
/**
10+
* **SENSITIVE_VAR** 🔐 _sensitive_
11+
* ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M29%2022h-5a2.003%202.003%200%200%201-2-2v-6a2%202%200%200%201%202-2h5v2h-5v6h5ZM18%2012h-4V8h-2v14h6a2.003%202.003%200%200%200%202-2v-6a2%202%200%200%200-2-2m-4%208v-6h4v6Zm-6-8H3v2h5v2H4a2%202%200%200%200-2%202v2a2%202%200%200%200%202%202h6v-8a2%202%200%200%200-2-2m0%208H4v-2h4Z%22%2F%3E%3C%2Fsvg%3E)
12+
*/
13+
SENSITIVE_VAR: string;
14+
15+
/**
16+
* **ANOTHER_SECRET** 🔐 _sensitive_
17+
* ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M29%2022h-5a2.003%202.003%200%200%201-2-2v-6a2%202%200%200%201%202-2h5v2h-5v6h5ZM18%2012h-4V8h-2v14h6a2.003%202.003%200%200%200%202-2v-6a2%202%200%200%200-2-2m-4%208v-6h4v6Zm-6-8H3v2h5v2H4a2%202%200%200%200-2%202v2a2%202%200%200%200%202%202h6v-8a2%202%200%200%200-2-2m0%208H4v-2h4Z%22%2F%3E%3C%2Fsvg%3E)
18+
*/
19+
ANOTHER_SECRET: string;
20+
21+
/**
22+
* **PUBLIC_ITEM**
23+
* ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M29%2022h-5a2.003%202.003%200%200%201-2-2v-6a2%202%200%200%201%202-2h5v2h-5v6h5ZM18%2012h-4V8h-2v14h6a2.003%202.003%200%200%200%202-2v-6a2%202%200%200%200-2-2m-4%208v-6h4v6Zm-6-8H3v2h5v2H4a2%202%200%200%200-2%202v2a2%202%200%200%200%202%202h6v-8a2%202%200%200%200-2-2m0%208H4v-2h4Z%22%2F%3E%3C%2Fsvg%3E)
24+
*/
25+
PUBLIC_ITEM: string;
26+
27+
/**
28+
* **PUBLIC_OTHER**
29+
* ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M29%2022h-5a2.003%202.003%200%200%201-2-2v-6a2%202%200%200%201%202-2h5v2h-5v6h5ZM18%2012h-4V8h-2v14h6a2.003%202.003%200%200%200%202-2v-6a2%202%200%200%200-2-2m-4%208v-6h4v6Zm-6-8H3v2h5v2H4a2%202%200%200%200-2%202v2a2%202%200%200%200%202%202h6v-8a2%202%200%200%200-2-2m0%208H4v-2h4Z%22%2F%3E%3C%2Fsvg%3E)
30+
*/
31+
PUBLIC_OTHER: string;
32+
33+
/**
34+
* **VITE_PREFIXED_ITEM**
35+
* ![icon](data:image/svg+xml;utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2220%22%20height%3D%2220%22%20viewBox%3D%220%200%2032%2032%22%3E%3Cpath%20fill%3D%22%23808080%22%20d%3D%22M29%2022h-5a2.003%202.003%200%200%201-2-2v-6a2%202%200%200%201%202-2h5v2h-5v6h5ZM18%2012h-4V8h-2v14h6a2.003%202.003%200%200%200%202-2v-6a2%202%200%200%200-2-2m-4%208v-6h4v6Zm-6-8H3v2h5v2H4a2%202%200%200%200-2%202v2a2%202%200%200%200%202%202h6v-8a2%202%200%200%200-2-2m0%208H4v-2h4Z%22%2F%3E%3C%2Fsvg%3E)
36+
*/
37+
VITE_PREFIXED_ITEM: string;
38+
39+
};
40+
41+
type _CoercedEnvSchema_850ba09a = CoercedEnvSchema;
42+
43+
declare module 'varlock/env' {
44+
export interface TypedEnvSchema extends Readonly<_CoercedEnvSchema_850ba09a> {}
45+
export interface PublicTypedEnvSchema extends Readonly<Pick<_CoercedEnvSchema_850ba09a, 'PUBLIC_ITEM' | 'PUBLIC_OTHER' | 'VITE_PREFIXED_ITEM'>> {}
46+
}
47+
48+
49+
export type EnvSchemaAsStrings = {
50+
[Property in keyof CoercedEnvSchema]:
51+
CoercedEnvSchema[Property] extends string ? CoercedEnvSchema[Property]
52+
: (CoercedEnvSchema[Property] extends boolean ? ('true' | 'false') : string)
53+
};
54+
55+
type _EnvSchemaAsStrings_850ba09a = EnvSchemaAsStrings;
56+
declare global {
57+
58+
// add types for global import.meta.env
59+
interface ImportMetaEnv extends _EnvSchemaAsStrings_850ba09a {}
60+
interface ImportMeta {
61+
readonly env: ImportMetaEnv;
62+
}
63+
64+
// add types for global process.env
65+
namespace NodeJS {
66+
interface ProcessEnv extends _EnvSchemaAsStrings_850ba09a {}
67+
}
68+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
{
2+
"name": "tanstack-start",
3+
"private": true,
4+
"type": "module",
5+
"imports": {
6+
"#/*": "./src/*"
7+
},
8+
"scripts": {
9+
"dev": "vite dev --port 3000",
10+
"build": "vite build",
11+
"preview": "vite preview",
12+
"test": "vitest run",
13+
"deploy": "npm run build && varlock-wrangler deploy",
14+
"cf-typegen": "varlock-wrangler types"
15+
},
16+
"dependencies": {
17+
"@cloudflare/vite-plugin": "^1.30.0",
18+
"@tailwindcss/vite": "^4.1.18",
19+
"@tanstack/react-devtools": "^0.10.0",
20+
"@tanstack/react-router": "^1.168.2",
21+
"@tanstack/react-router-devtools": "^1.166.11",
22+
"@tanstack/react-router-ssr-query": "^1.166.10",
23+
"@tanstack/react-start": "^1.167.3",
24+
"@tanstack/router-plugin": "^1.167.3",
25+
"@varlock/cloudflare-integration": "link:../../../varlock/packages/integrations/cloudflare",
26+
"react": "^19.2.0",
27+
"react-dom": "^19.2.0",
28+
"tailwindcss": "^4.1.18",
29+
"varlock": "link:../../../varlock/packages/varlock",
30+
"wrangler": "^4.76.0"
31+
},
32+
"devDependencies": {
33+
"@tailwindcss/typography": "^0.5.16",
34+
"@tanstack/devtools-vite": "^0.6.0",
35+
"@testing-library/dom": "^10.4.1",
36+
"@testing-library/react": "^16.3.0",
37+
"@types/node": "^22.10.2",
38+
"@types/react": "^19.2.0",
39+
"@types/react-dom": "^19.2.0",
40+
"@vitejs/plugin-react": "^5.1.4",
41+
"jsdom": "^28.1.0",
42+
"typescript": "^5.7.2",
43+
"vite": "^7.3.1",
44+
"vite-tsconfig-paths": "^5.1.4",
45+
"vitest": "^3.0.5"
46+
},
47+
"pnpm": {
48+
"onlyBuiltDependencies": [
49+
"esbuild",
50+
"lightningcss"
51+
]
52+
}
53+
}

0 commit comments

Comments
 (0)