Skip to content

Commit d7d5e94

Browse files
committed
chore: move README from root to @lib with symlink [skip ci]
1 parent 55ecab5 commit d7d5e94

File tree

3 files changed

+321
-326
lines changed

3 files changed

+321
-326
lines changed

.github/workflows/npm-publish.yml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ jobs:
1212
- uses: actions/setup-node@v3
1313
with:
1414
node-version: "20"
15-
- name: copy README
16-
uses: canastro/copy-file-action@master
17-
with:
18-
source: "README.md"
19-
target: "@lib/README.md"
2015
- uses: JS-DevTools/npm-publish@v3
2116
with:
2217
token: ${{ secrets.NPM_TOKEN }}

@lib/README.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

@lib/README.md

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
# `tRPC` - `svelte-query` Adapter
2+
3+
[![NPM version][npm-image]][npm-url]
4+
[![License][license-image]][license-url]
5+
[![Last commit][last-commit-image]][repo-url]
6+
7+
> **NOTE:** The README on [npmjs](https://npmjs.com/trpc-svelte-query-adapter) might not be fully up to date. Please refer to the [README on the Github Repo](https://github.com/vishalbalaji/trpc-svelte-query-adapter/#readme) for the latest setup instructions.
8+
9+
This package provides an adapter to call `tRPC` procedures wrapped with <code>[@tanstack/svelte-query](https://tanstack.com/query/latest/docs/svelte/overview)</code>, similar to <code>[@trpc/react-query](https://trpc.io/docs/react-query)</code>. This is made possible using <code>[proxy-deep](https://www.npmjs.com/package/proxy-deep)</code>.
10+
11+
## Installation
12+
13+
```console
14+
# npm
15+
npm install trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query
16+
17+
# yarn
18+
yarn add trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query
19+
20+
# pnpm
21+
pnpm add trpc-svelte-query-adapter @trpc/client @trpc/server @tanstack/svelte-query
22+
```
23+
24+
If you are using client-side Svelte, you would need to install `@trpc/server` as a `devDependency` using `--save-dev`.
25+
26+
## Available Functions
27+
28+
The following functions from `@trpc/react-query` are ported over:
29+
30+
- `useQuery` -> `createQuery`
31+
- `useInfiniteQuery` -> `createInfiniteQuery`
32+
- `useMutation` -> `createMutation`
33+
- `useSubscription` -> `createSubscription`
34+
- `useQueries` -> `createQueries`
35+
- `useUtils` -> `createUtils`
36+
- `getQueryKey`
37+
38+
You can refer to <code>[tanstack-query docs](https://tanstack.com/query/latest/docs/react/overview)</code> and <code>[@trpc/react-query docs](https://trpc.io/docs/react-query)</code> for documentation on how to use them.
39+
40+
There are also some new procedures that are only relevant for SvelteKit:
41+
42+
- `createServerQuery`
43+
- `createServerInfiniteQuery`
44+
- `createServerQueries`
45+
46+
As for these procedures, you can refer to the [Server-Side Query Pre-Fetching](#server-side-query-pre-fetching) section.
47+
48+
## Usage
49+
50+
The following instructions assume the `tRPC` router to have the following procedures:
51+
52+
```typescript
53+
export const router = t.router({
54+
greeting: t.procedure
55+
.input((name: unknown) => {
56+
if (typeof name === 'string') return name;
57+
58+
throw new Error(`Invalid input: ${typeof name}`);
59+
})
60+
.query(async ({ input }) => {
61+
return `Hello, ${input} from tRPC v10 @ ${new Date().toLocaleTimeString()}`;
62+
})
63+
});
64+
65+
export type Router = typeof router;
66+
```
67+
68+
### Client-Only Svelte
69+
70+
1. Setup `@tanstack/svelte-query` as per [svelte-query docs](https://tanstack.com/query/latest/docs/svelte/overview).
71+
2. Setup <code>[@trpc/client](https://trpc.io/docs/client)</code> and export the `tRPC` client.
72+
3. Wrap the exported `tRPC` client with `svelteQueryWrapper` from `trpc-svelte-query-adapter`, as demonstrated in the example below:
73+
74+
```typescript
75+
// src/lib/trpc.ts
76+
import type { Router } from '/path/to/trpc/router';
77+
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
78+
79+
import { svelteQueryWrapper } from 'trpc-svelte-query-adapter';
80+
81+
const client = createTRPCProxyClient<Router>({
82+
links: [
83+
httpBatchLink({
84+
// Replace this URL with that of your tRPC server
85+
url: 'http://localhost:5000/api/v1/trpc/',
86+
}),
87+
],
88+
});
89+
90+
export const trpc = svelteQueryWrapper<Router>({ client });
91+
```
92+
93+
4. The exported `tRPC` client can then be used in `svelte` components as follows:
94+
95+
```svelte
96+
<script lang="ts">
97+
import { trpc } from "/path/to/lib/trpc";
98+
99+
const foo = trpc.greeting.createQuery('foo', { retry: false });
100+
</script>
101+
102+
{#if $foo.isPending}
103+
Loading...
104+
{:else if $foo.isError}
105+
Error: {$foo.error.message}
106+
{:else if $foo.data}
107+
{$foo.data.message}
108+
{/if}
109+
```
110+
111+
### SvelteKit and SSR
112+
113+
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](https://tanstack.com/query/latest/docs/svelte/ssr#using-prefetchquery).
114+
115+
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](#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`.
116+
117+
Here is an example of what that might look like:
118+
119+
```typescript
120+
import type { QueryClient } from '@tanstack/svelte-query';
121+
122+
const client = createTRPCProxyClient<Router>({
123+
links: [
124+
httpBatchLink({
125+
// Replace this URL with that of your tRPC server
126+
url: 'http://localhost:5000/api/v1/trpc/',
127+
}),
128+
],
129+
});
130+
131+
export function trpc(queryClient?: QueryClient) {
132+
return svelteQueryWrapper<Router>({
133+
client,
134+
queryClient
135+
});
136+
};
137+
```
138+
139+
Which can then be used in a component as such:
140+
141+
```svelte
142+
<!-- routes/+page.svelte -->
143+
<script lang="ts">
144+
import { trpc } from "$lib/trpc/client";
145+
146+
const client = trpc();
147+
const foo = client.greeting.createQuery("foo", { retry: false });
148+
</script>
149+
150+
<p>
151+
{#if $foo.isPending}
152+
Loading...
153+
{:else if $foo.isError}
154+
Error: {$foo.error.message}
155+
{:else}
156+
{$foo.data}
157+
{/if}
158+
</p>
159+
```
160+
161+
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 <code>[trpc-sveltekit by icflorescu](https://icflorescu.github.io/trpc-sveltekit)</code>, all you would need to do after setting it up would be to change the client initialization function from something like this:
162+
163+
```typescript
164+
let browserClient: ReturnType<typeof createTRPCClient<Router>>;
165+
166+
export function trpc(init?: TRPCClientInit) {
167+
const isBrowser = typeof window !== 'undefined';
168+
if (isBrowser && browserClient) return browserClient;
169+
const client = createTRPCClient<Router>({ init });
170+
if (isBrowser) browserClient = client;
171+
return client;
172+
}
173+
```
174+
175+
to this:
176+
177+
```typescript
178+
import { svelteQueryWrapper } from 'trpc-svelte-query-adapter';
179+
import type { QueryClient } from '@tanstack/svelte-query';
180+
181+
let browserClient: ReturnType<typeof svelteQueryWrapper<Router>>;
182+
183+
export function trpc(init?: TRPCClientInit, queryClient?: QueryClient) {
184+
const isBrowser = typeof window !== 'undefined';
185+
if (isBrowser && browserClient) return browserClient;
186+
const client = svelteQueryWrapper<Router>({
187+
client: createTRPCClient<Router>({ init }),
188+
queryClient
189+
});
190+
if (isBrowser) browserClient = client;
191+
return client;
192+
}
193+
```
194+
195+
Which can then be initialized and used in the way that it is described [in its docs](https://icflorescu.github.io/trpc-sveltekit/getting-started).
196+
197+
#### Server-Side Query Pre-Fetching
198+
199+
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.
200+
201+
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`.
202+
203+
These procedures can be used as such:
204+
205+
> **NOTE:** [Gotta await top-level promises to pre-fetch data from SvelteKit v2](https://kit.svelte.dev/docs/migrating-to-sveltekit-2#top-level-promises-are-no-longer-awaited).
206+
207+
```typescript
208+
// +page.ts
209+
// tRPC is setup using `trpc-sveltekit` for this example.
210+
import { trpc } from '$lib/trpc/client';
211+
import type { PageLoad } from './$types';
212+
213+
export const load = (async (event) => {
214+
const { queryClient } = await event.parent();
215+
const client = trpc(event, queryClient);
216+
217+
return {
218+
foo: await client.greeting.createServerQuery('foo'),
219+
queries: await client.createServerQueries((t) =>
220+
['bar', 'baz'].map((name) => t.greeting(name, { ssr: name !== 'baz' })), // pre-fetching disabled for the `baz` query.
221+
),
222+
};
223+
}) satisfies PageLoad
224+
```
225+
226+
Then, in the component:
227+
228+
```svelte
229+
<!-- +page.svelte -->
230+
<script lang="ts">
231+
import { page } from "$app/stores";
232+
import type { PageData } from "./$types";
233+
234+
export let data: PageData;
235+
236+
const foo = data.foo();
237+
const queries = data.queries();
238+
</script>
239+
240+
{#if $foo.isPending}
241+
Loading...
242+
{:else if $foo.isError}
243+
{$foo.error}
244+
{:else if $foo.data}
245+
{$foo.data}
246+
{/if}
247+
<br /><br />
248+
249+
{#each $queries as query}
250+
{#if query.isPending}
251+
Loading...
252+
{:else if query.isError}
253+
{query.error.message}
254+
{:else if query.data}
255+
{query.data}
256+
{/if}
257+
<br />
258+
{/each}
259+
```
260+
261+
You can also optionally pass new inputs to the queries and infinite queries from the client side(see [#34](/../../issues/34)) like so:
262+
263+
```svelte
264+
<script lang="ts">
265+
import { page } from "$app/stores";
266+
import type { PageData } from "./$types";
267+
268+
export let data: PageData;
269+
270+
let name = 'foo';
271+
let newNames: string[] = [];
272+
273+
$: foo = data.foo(name); // `$` label to make the query reactive to the input
274+
275+
// You can also access the default input if you pass in a callback as the new input:
276+
// $: foo = data.foo((old) => old + name);
277+
278+
$: queries = data.queries((t, old) => [...old, ...newNames.map((name) => t.greeting(name))]);
279+
</script>
280+
281+
{#if $foo.isPending}
282+
Loading...
283+
{:else if $foo.isError}
284+
{$foo.error}
285+
{:else if $foo.data}
286+
{$foo.data}
287+
{/if}
288+
289+
<br />
290+
<input bind:value={name} />
291+
292+
<br /><br />
293+
294+
{#each $queries as query}
295+
{#if query.isPending}
296+
Loading...
297+
{:else if query.isError}
298+
{query.error.message}
299+
{:else if query.data}
300+
{query.data}
301+
{/if}
302+
<br />
303+
{/each}
304+
305+
<form on:submit|preventDefault={(e) => {
306+
const data = new FormData(e.currentTarget).get('name');
307+
if (typeof data === 'string') newNames.push(data);
308+
newNames = newNames;
309+
}}>
310+
<input name="name" />
311+
<button type="submit">Submit</button>
312+
</form>
313+
```
314+
315+
[npm-url]: https://npmjs.org/package/trpc-svelte-query-adapter
316+
[npm-image]: https://img.shields.io/npm/v/trpc-svelte-query-adapter.svg
317+
[license-url]: LICENSE
318+
[license-image]: http://img.shields.io/npm/l/trpc-svelte-query-adapter.svg
319+
[repo-url]: https://github.com/vishalbalaji/trpc-svelte-query-adapter
320+
[last-commit-image]: https://img.shields.io/github/last-commit/vishalbalaji/trpc-svelte-query-adapter

0 commit comments

Comments
 (0)