kaddidlehopper 0.1.0
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/CONTEXT.md +139 -0
- package/README.md +47 -0
- package/add-ons/ai/README.md +34 -0
- package/add-ons/ai/assets/_dot_env.local.append +13 -0
- package/add-ons/ai/assets/src/components/AIAssistant.tsx +149 -0
- package/add-ons/ai/assets/src/lib/ai-hook.ts +21 -0
- package/add-ons/ai/assets/src/lib/weather-tools.ts +30 -0
- package/add-ons/ai/assets/src/routes/api.chat.ts +94 -0
- package/add-ons/ai/assets/src/routes/chat.css +175 -0
- package/add-ons/ai/assets/src/routes/chat.tsx +141 -0
- package/add-ons/ai/info.json +27 -0
- package/add-ons/ai/package.json +17 -0
- package/add-ons/ai/small-logo.svg +8 -0
- package/dist/cli.js +251 -0
- package/dist/index.js +33 -0
- package/dist/types/cli.d.ts +8 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/types.d.ts +14 -0
- package/dist/types.js +1 -0
- package/examples/blog/README.md +60 -0
- package/examples/blog/assets/content/posts/beach.md +12 -0
- package/examples/blog/assets/content/posts/jungle.md.ejs +12 -0
- package/examples/blog/assets/content/posts/mountains.md.ejs +12 -0
- package/examples/blog/assets/content/posts/snorkeling.md.ejs +12 -0
- package/examples/blog/assets/content/posts/waterfall.md.ejs +12 -0
- package/examples/blog/assets/content-collections.ts +30 -0
- package/examples/blog/assets/public/beach.jpg +0 -0
- package/examples/blog/assets/public/jungle.jpg +0 -0
- package/examples/blog/assets/public/mountains.jpg +0 -0
- package/examples/blog/assets/public/snorkeling.jpg +0 -0
- package/examples/blog/assets/public/waterfall.jpg +0 -0
- package/examples/blog/assets/src/components/Header.tsx +52 -0
- package/examples/blog/assets/src/components/VacayAssistant.tsx +205 -0
- package/examples/blog/assets/src/components/blog-posts.tsx +78 -0
- package/examples/blog/assets/src/components/ui/card.tsx +92 -0
- package/examples/blog/assets/src/lib/blog-ai-hook.ts +25 -0
- package/examples/blog/assets/src/lib/blog-tools.ts +111 -0
- package/examples/blog/assets/src/lib/utils.ts +6 -0
- package/examples/blog/assets/src/routes/__root.tsx +57 -0
- package/examples/blog/assets/src/routes/api.blog-chat.ts +117 -0
- package/examples/blog/assets/src/routes/category.$category.tsx +19 -0
- package/examples/blog/assets/src/routes/index.tsx +19 -0
- package/examples/blog/assets/src/routes/posts.$slug.tsx +63 -0
- package/examples/blog/assets/src/styles.css +138 -0
- package/examples/blog/info.json +43 -0
- package/examples/blog/package.json +23 -0
- package/examples/events/README.md +110 -0
- package/examples/events/assets/content/speakers/andre-costa.md +22 -0
- package/examples/events/assets/content/speakers/hans-mueller.md.ejs +22 -0
- package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +22 -0
- package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +22 -0
- package/examples/events/assets/content/speakers/marie-dubois.md.ejs +20 -0
- package/examples/events/assets/content/speakers/priya-sharma.md.ejs +22 -0
- package/examples/events/assets/content/talks/croissant-lamination-secrets.md +39 -0
- package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +39 -0
- package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +39 -0
- package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +39 -0
- package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +36 -0
- package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +32 -0
- package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +39 -0
- package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +39 -0
- package/examples/events/assets/content-collections.ts +56 -0
- package/examples/events/assets/public/background-1.jpg +0 -0
- package/examples/events/assets/public/background-2.jpg +0 -0
- package/examples/events/assets/public/background-3.jpg +0 -0
- package/examples/events/assets/public/background-4.jpg +0 -0
- package/examples/events/assets/public/conference-logo.png +0 -0
- package/examples/events/assets/public/favicon.ico +0 -0
- package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
- package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
- package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
- package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
- package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
- package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
- package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
- package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
- package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
- package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
- package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
- package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
- package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
- package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
- package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
- package/examples/events/assets/public/tanstack-word-logo-white.svg +1 -0
- package/examples/events/assets/src/components/Header.tsx +59 -0
- package/examples/events/assets/src/components/HeaderNav.tsx +67 -0
- package/examples/events/assets/src/components/HeroCarousel.tsx +61 -0
- package/examples/events/assets/src/components/RemyAssistant.tsx +207 -0
- package/examples/events/assets/src/components/SpeakerCard.tsx +67 -0
- package/examples/events/assets/src/components/TalkCard.tsx +77 -0
- package/examples/events/assets/src/components/ui/card.tsx +92 -0
- package/examples/events/assets/src/lib/conference-ai-hook.ts +26 -0
- package/examples/events/assets/src/lib/conference-tools.ts +210 -0
- package/examples/events/assets/src/lib/model-selection.ts +1 -0
- package/examples/events/assets/src/lib/utils.ts +6 -0
- package/examples/events/assets/src/routes/__root.tsx +70 -0
- package/examples/events/assets/src/routes/api.remy-chat.ts +119 -0
- package/examples/events/assets/src/routes/index.tsx +192 -0
- package/examples/events/assets/src/routes/schedule.index.tsx +274 -0
- package/examples/events/assets/src/routes/speakers.$slug.tsx +122 -0
- package/examples/events/assets/src/routes/speakers.index.tsx +40 -0
- package/examples/events/assets/src/routes/talks.$slug.tsx +116 -0
- package/examples/events/assets/src/routes/talks.index.tsx +40 -0
- package/examples/events/assets/src/styles.css +182 -0
- package/examples/events/info.json +74 -0
- package/examples/events/package.json +23 -0
- package/examples/marketing/README.md +60 -0
- package/examples/marketing/assets/public/logo.png +0 -0
- package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
- package/examples/marketing/assets/src/components/Header.tsx +36 -0
- package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +162 -0
- package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +53 -0
- package/examples/marketing/assets/src/data/motorcycles.ts.ejs +77 -0
- package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +24 -0
- package/examples/marketing/assets/src/lib/motorcycle-tools.ts +42 -0
- package/examples/marketing/assets/src/routes/__root.tsx +57 -0
- package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +78 -0
- package/examples/marketing/assets/src/routes/index.tsx +72 -0
- package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +56 -0
- package/examples/marketing/assets/src/store/motorcycle-assistant.ts +3 -0
- package/examples/marketing/assets/src/styles.css +212 -0
- package/examples/marketing/info.json +38 -0
- package/examples/marketing/package.json +14 -0
- package/examples/resume/README.md +82 -0
- package/examples/resume/assets/content/education/code-school.md +17 -0
- package/examples/resume/assets/content/jobs/freelance.md.ejs +13 -0
- package/examples/resume/assets/content/jobs/initech-junior.md +20 -0
- package/examples/resume/assets/content/jobs/initech-lead.md.ejs +29 -0
- package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +28 -0
- package/examples/resume/assets/content-collections.ts +36 -0
- package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
- package/examples/resume/assets/src/components/Header.tsx +33 -0
- package/examples/resume/assets/src/components/ResumeAssistant.tsx +193 -0
- package/examples/resume/assets/src/components/ui/badge.tsx +46 -0
- package/examples/resume/assets/src/components/ui/card.tsx +92 -0
- package/examples/resume/assets/src/components/ui/checkbox.tsx +30 -0
- package/examples/resume/assets/src/components/ui/hover-card.tsx +44 -0
- package/examples/resume/assets/src/components/ui/separator.tsx +26 -0
- package/examples/resume/assets/src/lib/resume-ai-hook.ts +21 -0
- package/examples/resume/assets/src/lib/resume-tools.ts +165 -0
- package/examples/resume/assets/src/lib/utils.ts +6 -0
- package/examples/resume/assets/src/routes/api.resume-chat.ts +110 -0
- package/examples/resume/assets/src/routes/index.tsx +220 -0
- package/examples/resume/assets/src/styles.css +138 -0
- package/examples/resume/info.json +25 -0
- package/examples/resume/package.json +26 -0
- package/package.json +39 -0
- package/project/base/_dot_claude/skills/content-collections/SKILL.md +505 -0
- package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +410 -0
- package/project/base/_dot_claude/skills/netlify-db/SKILL.md +424 -0
- package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +419 -0
- package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +243 -0
- package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +372 -0
- package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +421 -0
- package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +426 -0
- package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +493 -0
- package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +430 -0
- package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +445 -0
- package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +494 -0
- package/project/base/_dot_gitignore +8 -0
- package/project/base/netlify.toml +7 -0
- package/project/base/package.json +33 -0
- package/project/base/public/favicon.ico +0 -0
- package/project/base/public/tanstack-circle-logo.png +0 -0
- package/project/base/public/tanstack-word-logo-white.svg +1 -0
- package/project/base/src/components/Header.tsx +17 -0
- package/project/base/src/components/HeaderNav.tsx.ejs +179 -0
- package/project/base/src/router.tsx +15 -0
- package/project/base/src/routes/__root.tsx +57 -0
- package/project/base/src/routes/index.tsx +48 -0
- package/project/base/src/styles.css +15 -0
- package/project/base/tsconfig.json +28 -0
- package/project/base/vite.config.ts.ejs +25 -0
- package/project/packages.json +22 -0
- package/scripts/check-outdated-packages.js +421 -0
- package/src/cli.ts +343 -0
- package/src/index.ts +49 -0
- package/src/types.ts +15 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tanstack-start-project-setup
|
|
3
|
+
description: Set up and configure TanStack Start projects. Use when creating new projects, configuring the router, setting up TanStack Query integration, or configuring build settings.
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
metadata:
|
|
6
|
+
author: tanstack
|
|
7
|
+
version: "1.0"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TanStack Start Project Setup
|
|
11
|
+
|
|
12
|
+
TanStack Start is a full-stack React framework built on TanStack Router, Vinxi, and Vite.
|
|
13
|
+
|
|
14
|
+
## When to Use
|
|
15
|
+
|
|
16
|
+
- Creating a new TanStack Start project
|
|
17
|
+
- Configuring router settings
|
|
18
|
+
- Setting up TanStack Query
|
|
19
|
+
- Adding TypeScript configuration
|
|
20
|
+
- Configuring for Netlify deployment
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Create new project
|
|
26
|
+
npx create-tanstack-start@latest my-app
|
|
27
|
+
|
|
28
|
+
# Or with specific template
|
|
29
|
+
npx create-tanstack-start@latest my-app --template basic
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Project Structure
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
my-app/
|
|
36
|
+
├── src/
|
|
37
|
+
│ ├── routes/
|
|
38
|
+
│ │ ├── __root.tsx # Root layout
|
|
39
|
+
│ │ ├── index.tsx # Home page (/)
|
|
40
|
+
│ │ └── ...
|
|
41
|
+
│ ├── server/
|
|
42
|
+
│ │ └── *.functions.ts # Server functions
|
|
43
|
+
│ ├── components/
|
|
44
|
+
│ ├── lib/
|
|
45
|
+
│ ├── router.tsx # Router configuration
|
|
46
|
+
│ └── routeTree.gen.ts # Auto-generated
|
|
47
|
+
├── public/
|
|
48
|
+
├── app.config.ts # TanStack Start config
|
|
49
|
+
├── package.json
|
|
50
|
+
├── tsconfig.json
|
|
51
|
+
└── netlify.toml # Netlify deployment
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Essential Files
|
|
55
|
+
|
|
56
|
+
### app.config.ts
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// app.config.ts
|
|
60
|
+
import { defineConfig } from '@tanstack/react-start/config';
|
|
61
|
+
|
|
62
|
+
export default defineConfig({
|
|
63
|
+
// Vite configuration
|
|
64
|
+
vite: {
|
|
65
|
+
// Add Vite plugins here
|
|
66
|
+
plugins: [],
|
|
67
|
+
},
|
|
68
|
+
|
|
69
|
+
// Server configuration
|
|
70
|
+
server: {
|
|
71
|
+
// Server preset (netlify, vercel, node, etc.)
|
|
72
|
+
preset: 'netlify',
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
// Router configuration
|
|
76
|
+
tsr: {
|
|
77
|
+
// Route file location
|
|
78
|
+
routesDirectory: './src/routes',
|
|
79
|
+
|
|
80
|
+
// Generated route tree location
|
|
81
|
+
generatedRouteTree: './src/routeTree.gen.ts',
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### router.tsx
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// src/router.tsx
|
|
90
|
+
import { createRouter } from '@tanstack/react-router';
|
|
91
|
+
import { routeTree } from './routeTree.gen';
|
|
92
|
+
|
|
93
|
+
export function getRouter() {
|
|
94
|
+
const router = createRouter({
|
|
95
|
+
routeTree,
|
|
96
|
+
|
|
97
|
+
// Enable scroll restoration
|
|
98
|
+
scrollRestoration: true,
|
|
99
|
+
|
|
100
|
+
// Preload on hover
|
|
101
|
+
defaultPreload: 'intent',
|
|
102
|
+
|
|
103
|
+
// Preload stale time
|
|
104
|
+
defaultPreloadStaleTime: 0,
|
|
105
|
+
|
|
106
|
+
// Default error component
|
|
107
|
+
defaultErrorComponent: ({ error }) => (
|
|
108
|
+
<div>Error: {error.message}</div>
|
|
109
|
+
),
|
|
110
|
+
|
|
111
|
+
// Default pending component
|
|
112
|
+
defaultPendingComponent: () => <div>Loading...</div>,
|
|
113
|
+
|
|
114
|
+
// Default not found component
|
|
115
|
+
defaultNotFoundComponent: () => <div>Not Found</div>,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return router;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Type registration for full type safety
|
|
122
|
+
declare module '@tanstack/react-router' {
|
|
123
|
+
interface Register {
|
|
124
|
+
router: ReturnType<typeof getRouter>;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Root Route (__root.tsx)
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// src/routes/__root.tsx
|
|
133
|
+
import {
|
|
134
|
+
Outlet,
|
|
135
|
+
createRootRoute,
|
|
136
|
+
HeadContent,
|
|
137
|
+
Scripts,
|
|
138
|
+
} from '@tanstack/react-router';
|
|
139
|
+
import type { ReactNode } from 'react';
|
|
140
|
+
|
|
141
|
+
export const Route = createRootRoute({
|
|
142
|
+
head: () => ({
|
|
143
|
+
meta: [
|
|
144
|
+
{ charSet: 'utf-8' },
|
|
145
|
+
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
|
146
|
+
{ title: 'My TanStack Start App' },
|
|
147
|
+
{ name: 'description', content: 'Built with TanStack Start' },
|
|
148
|
+
],
|
|
149
|
+
links: [
|
|
150
|
+
{ rel: 'stylesheet', href: '/styles.css' },
|
|
151
|
+
{ rel: 'icon', href: '/favicon.ico' },
|
|
152
|
+
],
|
|
153
|
+
}),
|
|
154
|
+
component: RootComponent,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
function RootComponent() {
|
|
158
|
+
return (
|
|
159
|
+
<html lang="en">
|
|
160
|
+
<head>
|
|
161
|
+
<HeadContent />
|
|
162
|
+
</head>
|
|
163
|
+
<body>
|
|
164
|
+
<Outlet />
|
|
165
|
+
<Scripts />
|
|
166
|
+
</body>
|
|
167
|
+
</html>
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## TanStack Query Integration
|
|
173
|
+
|
|
174
|
+
### Installation
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
npm install @tanstack/react-query
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Setup
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
// src/router.tsx
|
|
184
|
+
import { createRouter } from '@tanstack/react-router';
|
|
185
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
186
|
+
import { routeTree } from './routeTree.gen';
|
|
187
|
+
|
|
188
|
+
export function getRouter() {
|
|
189
|
+
const queryClient = new QueryClient({
|
|
190
|
+
defaultOptions: {
|
|
191
|
+
queries: {
|
|
192
|
+
staleTime: 1000 * 60, // 1 minute
|
|
193
|
+
gcTime: 1000 * 60 * 5, // 5 minutes
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const router = createRouter({
|
|
199
|
+
routeTree,
|
|
200
|
+
context: {
|
|
201
|
+
queryClient,
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return router;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
declare module '@tanstack/react-router' {
|
|
209
|
+
interface Register {
|
|
210
|
+
router: ReturnType<typeof getRouter>;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Root with Query Provider
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
// src/routes/__root.tsx
|
|
219
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
220
|
+
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
|
221
|
+
|
|
222
|
+
export const Route = createRootRouteWithContext<{
|
|
223
|
+
queryClient: QueryClient;
|
|
224
|
+
}>()({
|
|
225
|
+
component: RootComponent,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
function RootComponent() {
|
|
229
|
+
const { queryClient } = Route.useRouteContext();
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<QueryClientProvider client={queryClient}>
|
|
233
|
+
<html lang="en">
|
|
234
|
+
<head>
|
|
235
|
+
<HeadContent />
|
|
236
|
+
</head>
|
|
237
|
+
<body>
|
|
238
|
+
<Outlet />
|
|
239
|
+
<Scripts />
|
|
240
|
+
<ReactQueryDevtools />
|
|
241
|
+
</body>
|
|
242
|
+
</html>
|
|
243
|
+
</QueryClientProvider>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## TypeScript Configuration
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
// tsconfig.json
|
|
252
|
+
{
|
|
253
|
+
"compilerOptions": {
|
|
254
|
+
"target": "ES2022",
|
|
255
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
256
|
+
"module": "ESNext",
|
|
257
|
+
"moduleResolution": "bundler",
|
|
258
|
+
"jsx": "react-jsx",
|
|
259
|
+
"strict": true,
|
|
260
|
+
"noEmit": true,
|
|
261
|
+
"isolatedModules": true,
|
|
262
|
+
"esModuleInterop": true,
|
|
263
|
+
"skipLibCheck": true,
|
|
264
|
+
"paths": {
|
|
265
|
+
"~/*": ["./src/*"]
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
"include": ["src/**/*", "app.config.ts"],
|
|
269
|
+
"exclude": ["node_modules"]
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Netlify Deployment
|
|
274
|
+
|
|
275
|
+
### netlify.toml
|
|
276
|
+
|
|
277
|
+
```toml
|
|
278
|
+
[build]
|
|
279
|
+
command = "npm run build"
|
|
280
|
+
publish = ".output/public"
|
|
281
|
+
|
|
282
|
+
[build.environment]
|
|
283
|
+
NODE_VERSION = "20"
|
|
284
|
+
|
|
285
|
+
# Functions directory (auto-configured by TanStack Start)
|
|
286
|
+
[functions]
|
|
287
|
+
directory = ".output/server"
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### app.config.ts for Netlify
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
// app.config.ts
|
|
294
|
+
import { defineConfig } from '@tanstack/react-start/config';
|
|
295
|
+
|
|
296
|
+
export default defineConfig({
|
|
297
|
+
server: {
|
|
298
|
+
preset: 'netlify',
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Environment Variables
|
|
304
|
+
|
|
305
|
+
### .env Files
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
# .env (local development)
|
|
309
|
+
DATABASE_URL=postgres://localhost:5432/mydb
|
|
310
|
+
VITE_APP_NAME=My App
|
|
311
|
+
|
|
312
|
+
# .env.production (production)
|
|
313
|
+
DATABASE_URL=postgres://prod-server:5432/mydb
|
|
314
|
+
VITE_APP_NAME=My App
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Accessing Variables
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
// Server-side (server functions, loaders on server)
|
|
321
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
322
|
+
|
|
323
|
+
// Client-side (must be prefixed with VITE_)
|
|
324
|
+
const appName = import.meta.env.VITE_APP_NAME;
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## CSS/Styling Setup
|
|
328
|
+
|
|
329
|
+
### Tailwind CSS
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
npm install tailwindcss @tailwindcss/vite
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
// app.config.ts
|
|
337
|
+
import { defineConfig } from '@tanstack/react-start/config';
|
|
338
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
339
|
+
|
|
340
|
+
export default defineConfig({
|
|
341
|
+
vite: {
|
|
342
|
+
plugins: [tailwindcss()],
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
```css
|
|
348
|
+
/* src/styles.css */
|
|
349
|
+
@import 'tailwindcss';
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### CSS Modules
|
|
353
|
+
|
|
354
|
+
```tsx
|
|
355
|
+
// Component.tsx
|
|
356
|
+
import styles from './Component.module.css';
|
|
357
|
+
|
|
358
|
+
export function Component() {
|
|
359
|
+
return <div className={styles.container}>Hello</div>;
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Development Scripts
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
// package.json
|
|
367
|
+
{
|
|
368
|
+
"scripts": {
|
|
369
|
+
"dev": "vinxi dev",
|
|
370
|
+
"build": "vinxi build",
|
|
371
|
+
"start": "vinxi start",
|
|
372
|
+
"lint": "eslint src/",
|
|
373
|
+
"typecheck": "tsc --noEmit"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Recommended Package.json
|
|
379
|
+
|
|
380
|
+
```json
|
|
381
|
+
{
|
|
382
|
+
"name": "my-tanstack-app",
|
|
383
|
+
"type": "module",
|
|
384
|
+
"scripts": {
|
|
385
|
+
"dev": "vinxi dev",
|
|
386
|
+
"build": "vinxi build",
|
|
387
|
+
"start": "vinxi start"
|
|
388
|
+
},
|
|
389
|
+
"dependencies": {
|
|
390
|
+
"@tanstack/react-query": "^5.0.0",
|
|
391
|
+
"@tanstack/react-router": "^1.0.0",
|
|
392
|
+
"@tanstack/react-start": "^1.0.0",
|
|
393
|
+
"react": "^19.0.0",
|
|
394
|
+
"react-dom": "^19.0.0",
|
|
395
|
+
"vinxi": "^0.5.0",
|
|
396
|
+
"zod": "^3.23.0"
|
|
397
|
+
},
|
|
398
|
+
"devDependencies": {
|
|
399
|
+
"@types/react": "^19.0.0",
|
|
400
|
+
"@types/react-dom": "^19.0.0",
|
|
401
|
+
"typescript": "^5.6.0"
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
## Database Setup (Drizzle)
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
npm install drizzle-orm @neondatabase/serverless
|
|
410
|
+
npm install -D drizzle-kit
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
// drizzle.config.ts
|
|
415
|
+
import { defineConfig } from 'drizzle-kit';
|
|
416
|
+
|
|
417
|
+
export default defineConfig({
|
|
418
|
+
schema: './src/db/schema.ts',
|
|
419
|
+
out: './drizzle',
|
|
420
|
+
dialect: 'postgresql',
|
|
421
|
+
dbCredentials: {
|
|
422
|
+
url: process.env.DATABASE_URL!,
|
|
423
|
+
},
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
// src/db/index.ts
|
|
429
|
+
import { drizzle } from 'drizzle-orm/neon-http';
|
|
430
|
+
import { neon } from '@neondatabase/serverless';
|
|
431
|
+
import * as schema from './schema';
|
|
432
|
+
|
|
433
|
+
const sql = neon(process.env.DATABASE_URL!);
|
|
434
|
+
export const db = drizzle(sql, { schema });
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
## Common Configurations
|
|
438
|
+
|
|
439
|
+
### Custom 404 Page
|
|
440
|
+
|
|
441
|
+
```tsx
|
|
442
|
+
// src/routes/__root.tsx
|
|
443
|
+
export const Route = createRootRoute({
|
|
444
|
+
notFoundComponent: () => (
|
|
445
|
+
<div className="not-found">
|
|
446
|
+
<h1>404 - Page Not Found</h1>
|
|
447
|
+
<Link to="/">Go Home</Link>
|
|
448
|
+
</div>
|
|
449
|
+
),
|
|
450
|
+
});
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Global Error Boundary
|
|
454
|
+
|
|
455
|
+
```tsx
|
|
456
|
+
// src/routes/__root.tsx
|
|
457
|
+
export const Route = createRootRoute({
|
|
458
|
+
errorComponent: ({ error, reset }) => (
|
|
459
|
+
<div className="error-page">
|
|
460
|
+
<h1>Something went wrong</h1>
|
|
461
|
+
<p>{error.message}</p>
|
|
462
|
+
<button onClick={reset}>Try Again</button>
|
|
463
|
+
</div>
|
|
464
|
+
),
|
|
465
|
+
});
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### Loading States
|
|
469
|
+
|
|
470
|
+
```tsx
|
|
471
|
+
// src/routes/__root.tsx
|
|
472
|
+
export const Route = createRootRoute({
|
|
473
|
+
pendingComponent: () => (
|
|
474
|
+
<div className="loading">
|
|
475
|
+
<span className="spinner" />
|
|
476
|
+
Loading...
|
|
477
|
+
</div>
|
|
478
|
+
),
|
|
479
|
+
});
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
## Checklist for New Projects
|
|
483
|
+
|
|
484
|
+
- [ ] Create project with `create-tanstack-start`
|
|
485
|
+
- [ ] Configure `app.config.ts` with Netlify preset
|
|
486
|
+
- [ ] Set up TypeScript paths (`~/`)
|
|
487
|
+
- [ ] Configure TanStack Query if needed
|
|
488
|
+
- [ ] Set up CSS solution (Tailwind recommended)
|
|
489
|
+
- [ ] Create `.env` for local development
|
|
490
|
+
- [ ] Configure `netlify.toml` for deployment
|
|
491
|
+
- [ ] Set up database if needed (Drizzle + Neon)
|
|
492
|
+
- [ ] Add ESLint configuration
|
|
493
|
+
- [ ] Set environment variables in Netlify dashboard
|