Skip to content

Commit 9b2b9e2

Browse files
committed
feat: tRPC support
1 parent 7203366 commit 9b2b9e2

File tree

21 files changed

+187
-37
lines changed

21 files changed

+187
-37
lines changed

templates/react/add-on/start/assets/src/router.tsx.ejs

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ export const createRouter = () => {
2424
},
2525
scrollRestoration: true,
2626
defaultPreloadStaleTime: 0,
27+
<% if (addOnEnabled.tRPC) { %>
28+
Wrap: (props: { children: React.ReactNode }) => {
29+
return (
30+
<TanstackQuery.Provider>
31+
{props.children}
32+
</TanstackQuery.Provider>
33+
);
34+
},
35+
<% } %>
2736
}), TanstackQuery.getContext().queryClient)
2837
<% } else { %>
2938
const router = createTanstackRouter({
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { initTRPC } from "@trpc/server";
2+
import superjson from "superjson";
3+
4+
const t = initTRPC.create({
5+
transformer: superjson,
6+
});
7+
8+
export const createTRPCRouter = t.router;
9+
export const publicProcedure = t.procedure;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { createTRPCContext } from "@trpc/tanstack-react-query";
2+
import type { TRPCRouter } from "@/trpc/router";
3+
4+
export const { TRPCProvider, useTRPC } = createTRPCContext<TRPCRouter>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { TRPCError } from '@trpc/server'
2+
import type { TRPCRouterRecord } from '@trpc/server'
3+
// import { z } from 'zod'
4+
5+
import { createTRPCRouter, publicProcedure } from './init'
6+
7+
const peopleRouter = {
8+
list: publicProcedure.query(async () =>
9+
fetch('https://swapi.dev/api/people')
10+
.then((res) => res.json())
11+
.then((d) => d.results as { name: string }[]),
12+
),
13+
} satisfies TRPCRouterRecord
14+
15+
export const trpcRouter = createTRPCRouter({
16+
people: peopleRouter,
17+
})
18+
export type TRPCRouter = typeof trpcRouter
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { createAPIFileRoute } from '@tanstack/react-start/api'
2+
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
3+
import { trpcRouter } from '@/integrations/trpc/router'
4+
5+
function handler({ request }: { request: Request }) {
6+
return fetchRequestHandler({
7+
req: request,
8+
router: trpcRouter,
9+
endpoint: '/api/trpc',
10+
})
11+
}
12+
13+
export const APIRoute = createAPIFileRoute('/api/trpc/$')({
14+
GET: handler,
15+
POST: handler,
16+
})

templates/react/add-on/tRPC/info.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"name": "tRPC",
3+
"description": "Integrate tRPC into your application.",
4+
"phase": "add-on",
5+
"templates": ["file-router"],
6+
"link": "https://trpc.io/",
7+
"routes": [],
8+
"dependsOn": ["tanstack-query", "start"]
9+
}
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"dependencies": {
3+
"@trpc/client": "^11.0.0",
4+
"@trpc/server": "^11.0.0",
5+
"@trpc/tanstack-react-query": "^11.0.0",
6+
"superjson": "^2.2.2",
7+
"zod": "^3.24.2"
8+
}
9+
}

templates/react/add-on/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx

-15
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<% if (addOnEnabled.tRPC) { %>
2+
import { QueryClient } from "@tanstack/react-query";
3+
import superjson from "superjson";
4+
import { createTRPCClient, httpBatchStreamLink } from "@trpc/client";
5+
import { createTRPCOptionsProxy } from "@trpc/tanstack-react-query";
6+
7+
import { TRPCProvider } from "@/integrations/trpc/react";
8+
9+
import type { TRPCRouter } from "@/integrations/trpc/router";
10+
11+
function getUrl() {
12+
const base = (() => {
13+
if (typeof window !== "undefined") return "";
14+
return `http://localhost:${process.env.PORT ?? 3000}`;
15+
})();
16+
return base + "/api/trpc";
17+
}
18+
19+
export const trpcClient = createTRPCClient<TRPCRouter>({
20+
links: [
21+
httpBatchStreamLink({
22+
transformer: superjson,
23+
url: getUrl(),
24+
}),
25+
],
26+
});
27+
28+
const queryClient = new QueryClient({
29+
defaultOptions: {
30+
dehydrate: { serializeData: superjson.serialize },
31+
hydrate: { deserializeData: superjson.deserialize },
32+
},
33+
});
34+
35+
const serverHelpers = createTRPCOptionsProxy({
36+
client: trpcClient,
37+
queryClient: queryClient,
38+
});
39+
40+
export function getContext() {
41+
return {
42+
queryClient,
43+
trpc: serverHelpers,
44+
};
45+
}
46+
47+
export function Provider({ children }: { children: React.ReactNode }) {
48+
return (
49+
<TRPCProvider trpcClient={trpcClient} queryClient={queryClient}>
50+
{children}
51+
</TRPCProvider>
52+
);
53+
}
54+
<% } else { %>
55+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
56+
57+
const queryClient = new QueryClient()
58+
59+
export function getContext() {
60+
return {
61+
queryClient,
62+
}
63+
}
64+
65+
export function Provider({ children }: { children: React.ReactNode }) {
66+
return (
67+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
68+
)
69+
}
70+
<% } %>

templates/react/add-on/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs

+15
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/react-router'
22
import { useQuery } from '@tanstack/react-query'
3+
<% if (addOnEnabled.tRPC) { %>
4+
import { useTRPC } from "@/integrations/trpc/react";
5+
<% } %>
36
<% if (codeRouter) { %>
47
import type { RootRoute } from '@tanstack/react-router'
58
<% } else { %>
69
export const Route = createFileRoute('/demo/tanstack-query')({
10+
<% if (addOnEnabled.tRPC) { %>
11+
loader: async ({ context }) => {
12+
await context.queryClient.prefetchQuery(
13+
context.trpc.people.list.queryOptions()
14+
);
15+
},
16+
<% } %>
717
component: TanStackQueryDemo,
818
})
919
<% } %>
1020
function TanStackQueryDemo() {
21+
<% if (addOnEnabled.tRPC) { %>
22+
const trpc = useTRPC();
23+
const { data } = useQuery(trpc.people.list.queryOptions());
24+
<% } else { %>
1125
const { data } = useQuery({
1226
queryKey: ['people'],
1327
queryFn: () =>
@@ -16,6 +30,7 @@ function TanStackQueryDemo() {
1630
.then((d) => d.results as { name: string }[]),
1731
initialData: [],
1832
})
33+
<% } %>
1934

2035
return (
2136
<div className="p-4">

templates/react/base/tsconfig.json.ejs

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
"noUnusedLocals": true,
2121
"noUnusedParameters": true,
2222
"noFallthroughCasesInSwitch": true,
23-
"noUncheckedSideEffectImports": true<% if (addOnEnabled.shadcn) { %>,
23+
"noUncheckedSideEffectImports": true,
2424
"baseUrl": ".",
2525
"paths": {
2626
"@/*": ["./src/*"],
27-
}<% } %>
27+
}
2828
}
2929
}

templates/react/base/vite.config.js.ejs

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import viteReact from "@vitejs/plugin-react";<% if (tailwind) { %>
33
import tailwindcss from "@tailwindcss/vite";
44
<% } %><%if (fileRouter) { %>
55
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";<% } %><% if (addOnEnabled['module-federation']) { %>
6-
import { federation } from "@module-federation/vite";<% } %><% if (addOnEnabled.shadcn) { %>
7-
import { resolve } from "node:path";<% } %><% if (addOnEnabled['module-federation']) { %>
6+
import { federation } from "@module-federation/vite";<% } %>
7+
import { resolve } from "node:path";<% if (addOnEnabled['module-federation']) { %>
88
import federationConfig from "./module-federation.config.js";
99
<% } %>
1010

@@ -15,10 +15,9 @@ export default defineConfig({
1515
globals: true,
1616
environment: "jsdom",
1717
},
18-
<% if (addOnEnabled.shadcn) { %> resolve: {
18+
resolve: {
1919
alias: {
2020
'@': resolve(__dirname, './src'),
2121
},
22-
},
23-
<% } %>
22+
}
2423
});

templates/react/file-router/src/routes/__root.tsx.ejs

+7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@ import <%= integration.name %> from "../<%= integration.path %>";
1010
import appCss from '../styles.css?url'
1111
<% } %><% if (addOnEnabled["tanstack-query"]) { %>
1212
import type { QueryClient } from '@tanstack/react-query'
13+
<% if (addOnEnabled.tRPC) { %>
14+
import { TRPCRouter } from '@/integrations/trpc/router'
15+
<% } %>
16+
1317
interface MyRouterContext {
1418
queryClient: QueryClient
19+
<% if (addOnEnabled.tRPC) { %>
20+
trpc: TRPCRouter
21+
<% } %>
1522
}<% } %>
1623

1724
export const Route = <% if (addOnEnabled["tanstack-query"]) { %>createRootRouteWithContext<MyRouterContext>()<% } else { %>createRootRoute<% } %>({

0 commit comments

Comments
 (0)