Skip to content

Commit cae0d95

Browse files
feat: add @urql/tanstack-react-router
1 parent 25d114d commit cae0d95

File tree

13 files changed

+548
-287
lines changed

13 files changed

+548
-287
lines changed

.changeset/afraid-colts-sort.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@urql/tanstack-react-router': major
3+
---
4+
5+
initial implementation of TanStack Router / Start Integration

docs/advanced/server-side-rendering.md

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,13 +111,7 @@ Next, we'll modify our server-side code and add `react-ssr-prepass` in front of
111111
import { renderToString } from 'react-dom/server';
112112
import prepass from 'react-ssr-prepass';
113113

114-
import {
115-
Client,
116-
cacheExchange,
117-
fetchExchange,
118-
ssrExchange,
119-
Provider,
120-
} from 'urql';
114+
import { Client, cacheExchange, fetchExchange, ssrExchange, Provider } from 'urql';
121115

122116
const handleRequest = async (req, res) => {
123117
// ...
@@ -126,7 +120,7 @@ const handleRequest = async (req, res) => {
126120
const client = new Client({
127121
url: 'https://??',
128122
suspense: true, // This activates urql's Suspense mode on the server-side
129-
exchanges: [cacheExchange, ssr, fetchExchange]
123+
exchanges: [cacheExchange, ssr, fetchExchange],
130124
});
131125

132126
const element = (
@@ -577,6 +571,51 @@ is an uncommon scenario, and we consider it "unsafe" so evaluate this carefully
577571
When this does seem like the appropriate solution any component wrapped with `withUrqlClient` will receive the `resetUrqlClient`
578572
property, when invoked this will create a new top-level client and reset all prior operations.
579573

574+
## TanStack Router / TanStack Start
575+
576+
If you're using SSR with [TanStack Router](https://tanstack.com/router) or [TanStack Start](https://tanstack.com/start) you can use the `@urql/tanstack-react-router` package.
577+
578+
To set up `@urql/tanstack-react-router`, first we'll install `@urql/tanstack-react-router` and `urql`:
579+
580+
```sh
581+
pnpm add @urql/tanstack-react-router urql graphql
582+
# or
583+
npm install --save @urql/tanstack-react-router urql graphql
584+
```
585+
586+
Then instantiate a client with a SSR Exchange and make sure the `UrqlProvider` is rendered around the routes:
587+
588+
```tsx
589+
// router.tsx
590+
import { createRouter } from '@tanstack/react-router';
591+
592+
import {
593+
UrqlProvider,
594+
ssrExchange,
595+
cacheExchange,
596+
fetchExchange,
597+
createClient,
598+
} from '@urql/tanstack-react-router';
599+
600+
const ssr = ssrExchange();
601+
const client = createClient({
602+
url: 'https://trygql.formidable.dev/graphql/basic-pokedex',
603+
exchanges: [cacheExchange, ssr, fetchExchange],
604+
suspense: true,
605+
});
606+
607+
const router = createRouter({
608+
routeTree,
609+
Wrap: ({ children }) => (
610+
<UrqlProvider ssr={ssr} client={client}>
611+
{children}
612+
</UrqlProvider>
613+
),
614+
});
615+
```
616+
617+
Then in your React components use the `useQuery` from `@urql/tanstack-react-router`.
618+
580619
## Vue Suspense
581620

582621
In Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Changelog
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## `tanstack-react-router-urql`
2+
3+
A set of convenience utilities for using `urql` with SSR and `@tanstack/react-router` / `@tanstack/start`.
4+
5+
More documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#tanstack--router-tanstack-start
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "@urql/tanstack-react-router",
3+
"version": "1.0.0",
4+
"exports": {
5+
".": "./src/index.ts"
6+
},
7+
"exclude": [
8+
"node_modules",
9+
"cypress",
10+
"**/*.test.*",
11+
"**/*.spec.*",
12+
"**/*.test.*.snap",
13+
"**/*.spec.*.snap"
14+
]
15+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
{
2+
"name": "@urql/tanstack-react-router",
3+
"version": "1.0.0",
4+
"description": "Convenience wrappers for using urql with SSR in @tanstack/react-router and @tanstack/start",
5+
"sideEffects": false,
6+
"homepage": "https://formidable.com/open-source/urql/docs/",
7+
"bugs": "https://github.com/urql-graphql/urql/issues",
8+
"license": "MIT",
9+
"author": "Manuel Schiller",
10+
"repository": {
11+
"type": "git",
12+
"url": "https://github.com/urql-graphql/urql.git",
13+
"directory": "packages/tanstack-react-router-urql"
14+
},
15+
"main": "dist/urql-tanstack-react-router.js",
16+
"module": "dist/urql-tanstack-react-router.es.js",
17+
"types": "dist/urql-tanstack-react-router.d.ts",
18+
"source": "src/index.ts",
19+
"files": [
20+
"LICENSE",
21+
"CHANGELOG.md",
22+
"README.md",
23+
"dist/"
24+
],
25+
"scripts": {
26+
"clean": "rimraf dist",
27+
"check": "tsc --noEmit",
28+
"lint": "eslint --ext=js,jsx,ts,tsx .",
29+
"build": "rollup -c ../../scripts/rollup/config.mjs",
30+
"prepare": "node ../../scripts/prepare/index.js",
31+
"prepublishOnly": "run-s clean build"
32+
},
33+
"devDependencies": {
34+
"@urql/core": "workspace:*",
35+
"urql": "workspace:*",
36+
"@types/react": "^18.3.8",
37+
"@types/react-dom": "^18.3.0",
38+
"graphql": "^16.0.0",
39+
"@tanstack/react-router": "^1.94.1",
40+
"react": "^18.0.0",
41+
"react-dom": "^18.0.0"
42+
},
43+
"peerDependencies": {
44+
"@tanstack/react-router": ">=1.94.1",
45+
"react": ">=18.0.0",
46+
"urql": "^4.0.0"
47+
},
48+
"publishConfig": {
49+
"access": "public",
50+
"provenance": true
51+
}
52+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import * as React from 'react';
2+
import type { SSRExchange, Client } from 'urql';
3+
import { Provider } from 'urql';
4+
5+
export const SSRContext = React.createContext<SSRExchange | undefined>(
6+
undefined
7+
);
8+
9+
/** Provider for `@urql/tanstack-react-router`.
10+
*
11+
* @remarks
12+
* `Provider` accepts a {@link Client} and provides it to all GraphQL hooks, it
13+
* also accepts an {@link SSRExchange} to distribute data when re-hydrating
14+
* on the client.
15+
*
16+
* @example
17+
* ```tsx
18+
* import {
19+
* UrqlProvider,
20+
* ssrExchange,
21+
* cacheExchange,
22+
* fetchExchange,
23+
* createClient,
24+
* } from '@urql/tanstack-react-router';
25+
*
26+
* const ssr = ssrExchange();
27+
* const client = createClient({
28+
* url: 'https://trygql.formidable.dev/graphql/basic-pokedex',
29+
* exchanges: [cacheExchange, ssr, fetchExchange],
30+
* suspense: true,
31+
* });
32+
*
33+
* const router = createRouter ({
34+
* routeTree,
35+
* Wrap: ({ children }) => <UrqlProvider ssr={ssr} client={urqlClient}>{children}</UrqlProvider>,
36+
* });
37+
* }
38+
*
39+
* ```
40+
*/
41+
export function UrqlProvider({
42+
children,
43+
ssr,
44+
client,
45+
}: React.PropsWithChildren<{
46+
ssr: SSRExchange;
47+
client: Client;
48+
}>) {
49+
return React.createElement(
50+
Provider,
51+
{ value: client },
52+
React.createElement(SSRContext.Provider, { value: ssr }, children)
53+
);
54+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from 'urql';
2+
export { useQuery } from './useQuery';
3+
export { UrqlProvider, SSRContext } from './Provider';

0 commit comments

Comments
 (0)