Gathering detailed insights and metrics for trpc-svelte-query-adapter
Gathering detailed insights and metrics for trpc-svelte-query-adapter
Gathering detailed insights and metrics for trpc-svelte-query-adapter
Gathering detailed insights and metrics for trpc-svelte-query-adapter
A simple adapter to use `@tanstack/svelte-query` with trpc, similar to `@trpc/react-query`.
npm install trpc-svelte-query-adapter
Module System
Min. Node Version
Typescript Support
Node Version
NPM Version
74 Stars
138 Commits
6 Forks
2 Watching
3 Branches
3 Contributors
Updated on 28 Nov 2024
TypeScript (68.91%)
Svelte (27.02%)
JavaScript (3.59%)
HTML (0.47%)
Cumulative downloads
Total Downloads
Last day
215%
715
Compared to previous day
Last week
46.8%
2,566
Compared to previous week
Last month
-31.4%
8,663
Compared to previous month
Last year
1,107.8%
80,126
Compared to previous year
1
6
1
tRPC
- svelte-query
Adapter[!NOTE] The README on npmjs might not be fully up to date. Please refer to the README on the Github Repo for the latest setup instructions.
An adapter to call tRPC
procedures wrapped with @tanstack/svelte-query
, similar to @trpc/react-query
. This is made possible using proxy-deep
.
1# npm 2npm install trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query 3 4# yarn 5yarn add trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query 6 7# pnpm 8pnpm add trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query
If you are using client-side Svelte, you would need to install @trpc/server
as a devDependency
using --save-dev
.
The following functions from @trpc/react-query
are ported over:
useQuery
-> createQuery
useInfiniteQuery
-> createInfiniteQuery
useMutation
-> createMutation
useSubscription
-> createSubscription
useQueries
-> createQueries
useUtils
-> createUtils
getQueryKey
You can refer to tanstack-query docs
and @trpc/react-query docs
for documentation on how to use them.
There are also some new procedures that are only relevant for SvelteKit:
createServerQuery
createServerInfiniteQuery
createServerQueries
As for these procedures, you can refer to the Server-Side Query Pre-Fetching section.
The following instructions assume the tRPC
router to have the following procedures:
1export const router = t.router({ 2 greeting: t.procedure 3 .input((name: unknown) => { 4 if (typeof name === 'string') return name; 5 6 throw new Error(`Invalid input: ${typeof name}`); 7 }) 8 .query(async ({ input }) => { 9 return `Hello, ${input} from tRPC v10 @ ${new Date().toLocaleTimeString()}`; 10 }), 11}); 12 13export type Router = typeof router;
@tanstack/svelte-query
as per svelte-query docs.@trpc/client
and export the tRPC
client.tRPC
client with svelteQueryWrapper
from trpc-svelte-query-adapter
, as demonstrated in the example below:1// src/lib/trpc.ts 2import type { Router } from '/path/to/trpc/router'; 3import { createTRPCProxyClient, httpBatchLink } from '@trpc/client'; 4 5import { svelteQueryWrapper } from 'trpc-svelte-query-adapter'; 6 7const client = createTRPCProxyClient<Router>({ 8 links: [ 9 httpBatchLink({ 10 // Replace this URL with that of your tRPC server 11 url: 'http://localhost:5000/api/v1/trpc/', 12 }), 13 ], 14}); 15 16export const trpc = svelteQueryWrapper<Router>({ client });
tRPC
client can then be used in svelte
components as follows:1<script lang="ts"> 2 import { trpc } from "/path/to/lib/trpc"; 3 4 const foo = trpc.greeting.createQuery('foo', { retry: false }); 5</script> 6 7{#if $foo.isPending} 8 Loading... 9{:else if $foo.isError} 10 Error: {$foo.error.message} 11{:else if $foo.data} 12 {$foo.data.message} 13{/if}
For SvelteKit, the process is pretty much the same as for client-only svelte. However, if you intend to call queries from the server in a load
function, you would need to setup @tanstack/svelte-query
according to the the ssr example in the svelte-query docs.
Upon doing that, you would also need to pass in the queryClient
to svelteQueryWrapper
when initializing on the server, which you can get by calling the event.parent
method in the load
function. You can see an example of this in the Server-Side Query Pre-Fetching section. For this purpose, you might also want to export your client wrapped in a function that optionally takes in queryClient
and passes it onto svelteQueryWrapper
.
Here is an example of what that might look like:
1import type { QueryClient } from '@tanstack/svelte-query'; 2 3const client = createTRPCProxyClient<Router>({ 4 links: [ 5 httpBatchLink({ 6 // Replace this URL with that of your tRPC server 7 url: 'http://localhost:5000/api/v1/trpc/', 8 }), 9 ], 10}); 11 12export function trpc(queryClient?: QueryClient) { 13 return svelteQueryWrapper<Router>({ 14 client, 15 queryClient, 16 }); 17}
Which can then be used in a component as such:
1<!-- routes/+page.svelte --> 2<script lang="ts"> 3 import { trpc } from "$lib/trpc/client"; 4 5 const client = trpc(); 6 const foo = client.greeting.createQuery("foo", { retry: false }); 7</script> 8 9<p> 10 {#if $foo.isPending} 11 Loading... 12 {:else if $foo.isError} 13 Error: {$foo.error.message} 14 {:else} 15 {$foo.data} 16 {/if} 17</p>
The main thing that needs to passed in to svelteQueryWrapper
is the tRPC
client itself. So, this adapter should support different implementations of tRPC
for Svelte and SvelteKit. For example, if you are using trpc-sveltekit by icflorescu
, all you would need to do after setting it up would be to change the client initialization function from something like this:
1let browserClient: ReturnType<typeof createTRPCClient<Router>>; 2 3export function trpc(init?: TRPCClientInit) { 4 const isBrowser = typeof window !== 'undefined'; 5 if (isBrowser && browserClient) return browserClient; 6 const client = createTRPCClient<Router>({ init }); 7 if (isBrowser) browserClient = client; 8 return client; 9}
to this:
1import { svelteQueryWrapper } from 'trpc-svelte-query-adapter'; 2import type { QueryClient } from '@tanstack/svelte-query'; 3 4let browserClient: ReturnType<typeof svelteQueryWrapper<Router>>; 5 6export function trpc(init?: TRPCClientInit, queryClient?: QueryClient) { 7 const isBrowser = typeof window !== 'undefined'; 8 if (isBrowser && browserClient) return browserClient; 9 const client = svelteQueryWrapper<Router>({ 10 client: createTRPCClient<Router>({ init }), 11 queryClient, 12 }); 13 if (isBrowser) browserClient = client; 14 return client; 15}
Which can then be initialized and used in the way that it is described in its docs.
This adapter provides 3 additional procedures: createServerQuery
, createServerInfiniteQuery
and createServerQueries
, which can be used to call their counterpart procedures in the load
function in either a +page.ts
or +layout.ts
. These procedures return a promise
and therefore can only really be called on the server.
By default, these 3 procedures will pre-fetch the data required to pre-render the page on the server. However, if you wish to disable this behaviour on certain queries, you can do so by setting the ssr
option to false
.
These procedures can be used as such:
[!NOTE] Gotta await top-level promises to pre-fetch data from SvelteKit v2.
1// +page.ts 2// tRPC is setup using `trpc-sveltekit` for this example. 3import { trpc } from '$lib/trpc/client'; 4import type { PageLoad } from './$types'; 5 6export const load = (async (event) => { 7 const { queryClient } = await event.parent(); 8 const client = trpc(event, queryClient); 9 10 return { 11 foo: await client.greeting.createServerQuery('foo'), 12 queries: await client.createServerQueries( 13 (t) => 14 ['bar', 'baz'].map((name) => t.greeting(name, { ssr: name !== 'baz' })) // pre-fetching disabled for the `baz` query. 15 ), 16 }; 17}) satisfies PageLoad;
Then, in the component:
1<!-- +page.svelte --> 2<script lang="ts"> 3 import { page } from "$app/stores"; 4 import type { PageData } from "./$types"; 5 6 export let data: PageData; 7 8 const foo = data.foo(); 9 const queries = data.queries(); 10</script> 11 12{#if $foo.isPending} 13 Loading... 14{:else if $foo.isError} 15 {$foo.error} 16{:else if $foo.data} 17 {$foo.data} 18{/if} 19<br /><br /> 20 21{#each $queries as query} 22 {#if query.isPending} 23 Loading... 24 {:else if query.isError} 25 {query.error.message} 26 {:else if query.data} 27 {query.data} 28 {/if} 29 <br /> 30{/each}
You can also optionally pass new inputs to the queries and infinite queries from the client side(see #34, #47) like so:
1<script lang="ts"> 2 import { page } from "$app/stores"; 3 import type { PageData } from "./$types"; 4 5 import { derived, writable } from '@svelte/store'; 6 7 export let data: PageData; 8 9 const name = writable('foo'); 10 const newNames = writable<string[]>([]); 11 12 const foo = data.foo($name); 13 14 // You can also access the default input if you pass in a callback as the new input: 15 // const foo = data.foo((old) => derived(name, ($name) => old + name)); 16 17 const queries = data.queries((t, old) => derived(newNames, ($newNames) => [...old, ...$newNames.map((name) => t.greeting(name))])); 18</script> 19 20<div> 21 {#if $foo.isPending} 22 Loading... 23 {:else if $foo.isError} 24 {$foo.error} 25 {:else if $foo.data} 26 {$foo.data} 27 {/if} 28 <input bind:value={$name} /> 29</div> 30 31<br /> 32 33<div> 34 {#each $queries as query} 35 {#if query.isPending} 36 Loading... 37 {:else if query.isError} 38 {query.error.message} 39 {:else if query.data} 40 {query.data} 41 {/if} 42 <br /> 43 {/each} 44 45 <form on:submit|preventDefault={(e) => { 46 const data = new FormData(e.currentTarget).get('name'); 47 if (typeof data === 'string') $newNames.push(data); 48 $newNames = $newNames; 49 }}> 50 <input name="name" /> 51 <button type="submit">Submit</button> 52 </form> 53</div>
For more usage examples, you can refer to the example app provided in the repo.
No vulnerabilities found.
No security vulnerabilities found.