Skip to content

Commit e2ac863

Browse files
birkskyumautofix-ci[bot]brenelzXiNiHa
authored
SolidJS driver for TanStack Start (#3522)
This PR introduce support for Solid to be used with TanStack Start. There are several ongoing refactors that can influence the timing of when it's most feasible to merge this. ### Status (build and run e2e/solid-start/basic) - [X] SSR - [x] API Routes - [x] Server Functions - [x] HMR - [x] Streaming (/stream route) - [X] Timely hydration ### Ongoing refactors Refactor to make router packages (aka. client-only features) more agnostic: - #3552 - #3540 - #3538 - #3171 Refactor to make start packages (aka. server features) more agnostic: - #3546 - #3563 - #3565 ### Upstream changes to solid-router - #3592 - #3591 - #3589 - #3616 ### Passing E2E test suites - [x] basic - [x] website - [x] scroll-restoration - [x] server-functions --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Brenley Dueck <[email protected]> Co-authored-by: Iha Shin <[email protected]> Co-authored-by: Brenley Dueck <[email protected]>
1 parent 6df662d commit e2ac863

File tree

360 files changed

+19875
-94
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

360 files changed

+19875
-94
lines changed

.github/workflows/pr.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,4 @@ jobs:
4848
- name: Build Packages
4949
run: pnpm run build:all
5050
- name: Publish Previews
51-
run: pnpx pkg-pr-new publish --pnpm --compact './packages/*' --template './examples/*/*'
51+
run: pnpx pkg-pr-new publish --pnpm './packages/*' --template './examples/*/*'

e2e/solid-start/basic/.gitignore

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
node_modules
2+
package-lock.json
3+
yarn.lock
4+
5+
.DS_Store
6+
.cache
7+
.env
8+
.vercel
9+
.output
10+
.vinxi
11+
12+
/build/
13+
/api/
14+
/server/build
15+
/public/build
16+
.vinxi
17+
# Sentry Config File
18+
.env.sentry-build-plugin
19+
/test-results/
20+
/playwright-report/
21+
/blob-report/
22+
/playwright/.cache/

e2e/solid-start/basic/.prettierignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
**/build
2+
**/public
3+
pnpm-lock.yaml
4+
routeTree.gen.ts

e2e/solid-start/basic/app.config.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineConfig } from '@tanstack/solid-start/config'
2+
import tsConfigPaths from 'vite-tsconfig-paths'
3+
4+
export default defineConfig({
5+
vite: {
6+
plugins: [
7+
tsConfigPaths({
8+
projects: ['./tsconfig.json'],
9+
}),
10+
],
11+
},
12+
})

e2e/solid-start/basic/app/api.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {
2+
createStartAPIHandler,
3+
defaultAPIFileRouteHandler,
4+
} from '@tanstack/solid-start/api'
5+
6+
export default createStartAPIHandler(defaultAPIFileRouteHandler)

e2e/solid-start/basic/app/client.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/// <reference types="vinxi/types/client" />
2+
import { hydrate } from 'solid-js/web'
3+
import { StartClient } from '@tanstack/solid-start'
4+
import { createRouter } from './router'
5+
6+
const router = createRouter()
7+
8+
hydrate(() => <StartClient router={router} />, document.body)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function CustomMessage({ message }: { message: string }) {
2+
return (
3+
<div class="py-2">
4+
<div class="italic">This is a custom message:</div>
5+
<p>{message}</p>
6+
</div>
7+
)
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import {
2+
ErrorComponent,
3+
Link,
4+
rootRouteId,
5+
useMatch,
6+
useRouter,
7+
} from '@tanstack/solid-router'
8+
import type { ErrorComponentProps } from '@tanstack/solid-router'
9+
10+
export function DefaultCatchBoundary({ error }: ErrorComponentProps) {
11+
const router = useRouter()
12+
const isRoot = useMatch({
13+
strict: false,
14+
select: (state) => state.id === rootRouteId,
15+
})
16+
17+
console.error(error)
18+
19+
return (
20+
<div class="min-w-0 flex-1 p-4 flex flex-col items-center justify-center gap-6">
21+
<ErrorComponent error={error} />
22+
<div class="flex gap-2 items-center flex-wrap">
23+
<button
24+
onClick={() => {
25+
router.invalidate()
26+
}}
27+
class={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
28+
>
29+
Try Again
30+
</button>
31+
{isRoot() ? (
32+
<Link
33+
to="/"
34+
class={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
35+
>
36+
Home
37+
</Link>
38+
) : (
39+
<Link
40+
to="/"
41+
class={`px-2 py-1 bg-gray-600 dark:bg-gray-700 rounded text-white uppercase font-extrabold`}
42+
onClick={(e) => {
43+
e.preventDefault()
44+
window.history.back()
45+
}}
46+
>
47+
Go Back
48+
</Link>
49+
)}
50+
</div>
51+
</div>
52+
)
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { Link } from '@tanstack/solid-router'
2+
3+
export function NotFound({ children }: { children?: any }) {
4+
return (
5+
<div class="space-y-2 p-2" data-testid="default-not-found-component">
6+
<div class="text-gray-600 dark:text-gray-400">
7+
{children || <p>The page you are looking for does not exist.</p>}
8+
</div>
9+
<p class="flex items-center gap-2 flex-wrap">
10+
<button
11+
onClick={() => window.history.back()}
12+
class="bg-emerald-500 text-white px-2 py-1 rounded uppercase font-black text-sm"
13+
>
14+
Go back
15+
</button>
16+
<Link
17+
to="/"
18+
class="bg-cyan-600 text-white px-2 py-1 rounded uppercase font-black text-sm"
19+
>
20+
Start Over
21+
</Link>
22+
</p>
23+
</div>
24+
)
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { ErrorComponent, ErrorComponentProps } from '@tanstack/solid-router'
2+
3+
export function PostErrorComponent({ error }: ErrorComponentProps) {
4+
return <ErrorComponent error={error} />
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { useServerFn } from '@tanstack/solid-start'
2+
import { throwRedirect } from './throwRedirect'
3+
4+
interface RedirectOnClickProps {
5+
target: 'internal' | 'external'
6+
reloadDocument?: boolean
7+
externalHost?: string
8+
}
9+
10+
export function RedirectOnClick({
11+
target,
12+
reloadDocument,
13+
externalHost,
14+
}: RedirectOnClickProps) {
15+
const execute = useServerFn(throwRedirect)
16+
return (
17+
<button
18+
data-testid="redirect-on-click"
19+
onClick={() =>
20+
execute({ data: { target, reloadDocument, externalHost } })
21+
}
22+
>
23+
click me
24+
</button>
25+
)
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { ErrorComponent, ErrorComponentProps } from '@tanstack/solid-router'
2+
3+
export function UserErrorComponent({ error }: ErrorComponentProps) {
4+
return <ErrorComponent error={error} />
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { redirect } from '@tanstack/solid-router'
2+
import { createServerFn } from '@tanstack/solid-start'
3+
4+
export const throwRedirect = createServerFn()
5+
.validator(
6+
(opts: {
7+
target: 'internal' | 'external'
8+
reloadDocument?: boolean
9+
externalHost?: string
10+
}) => opts,
11+
)
12+
.handler((ctx) => {
13+
if (ctx.data.target === 'internal') {
14+
throw redirect({ to: '/posts', reloadDocument: ctx.data.reloadDocument })
15+
}
16+
const href = ctx.data.externalHost ?? 'http://example.com'
17+
throw redirect({
18+
href,
19+
})
20+
})

0 commit comments

Comments
 (0)