Skip to content

Commit

Permalink
feat: add @urql/tanstack-react-router
Browse files Browse the repository at this point in the history
  • Loading branch information
schiller-manuel committed Jan 3, 2025
1 parent 25d114d commit cae0d95
Show file tree
Hide file tree
Showing 13 changed files with 548 additions and 287 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-colts-sort.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/tanstack-react-router': major
---

initial implementation of TanStack Router / Start Integration
55 changes: 47 additions & 8 deletions docs/advanced/server-side-rendering.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,7 @@ Next, we'll modify our server-side code and add `react-ssr-prepass` in front of
import { renderToString } from 'react-dom/server';
import prepass from 'react-ssr-prepass';

import {
Client,
cacheExchange,
fetchExchange,
ssrExchange,
Provider,
} from 'urql';
import { Client, cacheExchange, fetchExchange, ssrExchange, Provider } from 'urql';

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

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

## TanStack Router / TanStack Start

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.

To set up `@urql/tanstack-react-router`, first we'll install `@urql/tanstack-react-router` and `urql`:

```sh
pnpm add @urql/tanstack-react-router urql graphql
# or
npm install --save @urql/tanstack-react-router urql graphql
```

Then instantiate a client with a SSR Exchange and make sure the `UrqlProvider` is rendered around the routes:

```tsx
// router.tsx
import { createRouter } from '@tanstack/react-router';

import {
UrqlProvider,
ssrExchange,
cacheExchange,
fetchExchange,
createClient,
} from '@urql/tanstack-react-router';

const ssr = ssrExchange();
const client = createClient({
url: 'https://trygql.formidable.dev/graphql/basic-pokedex',
exchanges: [cacheExchange, ssr, fetchExchange],
suspense: true,
});

const router = createRouter({
routeTree,
Wrap: ({ children }) => (
<UrqlProvider ssr={ssr} client={client}>
{children}
</UrqlProvider>
),
});
```

Then in your React components use the `useQuery` from `@urql/tanstack-react-router`.

## Vue Suspense

In Vue 3 a [new feature was introduced](https://vuedose.tips/go-async-in-vue-3-with-suspense/) that
Expand Down
1 change: 1 addition & 0 deletions packages/tanstack-react-router-urql/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Changelog
5 changes: 5 additions & 0 deletions packages/tanstack-react-router-urql/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## `tanstack-react-router-urql`

A set of convenience utilities for using `urql` with SSR and `@tanstack/react-router` / `@tanstack/start`.

More documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#tanstack--router-tanstack-start
15 changes: 15 additions & 0 deletions packages/tanstack-react-router-urql/jsr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "@urql/tanstack-react-router",
"version": "1.0.0",
"exports": {
".": "./src/index.ts"
},
"exclude": [
"node_modules",
"cypress",
"**/*.test.*",
"**/*.spec.*",
"**/*.test.*.snap",
"**/*.spec.*.snap"
]
}
52 changes: 52 additions & 0 deletions packages/tanstack-react-router-urql/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "@urql/tanstack-react-router",
"version": "1.0.0",
"description": "Convenience wrappers for using urql with SSR in @tanstack/react-router and @tanstack/start",
"sideEffects": false,
"homepage": "https://formidable.com/open-source/urql/docs/",
"bugs": "https://github.com/urql-graphql/urql/issues",
"license": "MIT",
"author": "Manuel Schiller",
"repository": {
"type": "git",
"url": "https://github.com/urql-graphql/urql.git",
"directory": "packages/tanstack-react-router-urql"
},
"main": "dist/urql-tanstack-react-router.js",
"module": "dist/urql-tanstack-react-router.es.js",
"types": "dist/urql-tanstack-react-router.d.ts",
"source": "src/index.ts",
"files": [
"LICENSE",
"CHANGELOG.md",
"README.md",
"dist/"
],
"scripts": {
"clean": "rimraf dist",
"check": "tsc --noEmit",
"lint": "eslint --ext=js,jsx,ts,tsx .",
"build": "rollup -c ../../scripts/rollup/config.mjs",
"prepare": "node ../../scripts/prepare/index.js",
"prepublishOnly": "run-s clean build"
},
"devDependencies": {
"@urql/core": "workspace:*",
"urql": "workspace:*",
"@types/react": "^18.3.8",
"@types/react-dom": "^18.3.0",
"graphql": "^16.0.0",
"@tanstack/react-router": "^1.94.1",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependencies": {
"@tanstack/react-router": ">=1.94.1",
"react": ">=18.0.0",
"urql": "^4.0.0"
},
"publishConfig": {
"access": "public",
"provenance": true
}
}
54 changes: 54 additions & 0 deletions packages/tanstack-react-router-urql/src/Provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import * as React from 'react';
import type { SSRExchange, Client } from 'urql';
import { Provider } from 'urql';

export const SSRContext = React.createContext<SSRExchange | undefined>(
undefined
);

/** Provider for `@urql/tanstack-react-router`.
*
* @remarks
* `Provider` accepts a {@link Client} and provides it to all GraphQL hooks, it
* also accepts an {@link SSRExchange} to distribute data when re-hydrating
* on the client.
*
* @example
* ```tsx
* import {
* UrqlProvider,
* ssrExchange,
* cacheExchange,
* fetchExchange,
* createClient,
* } from '@urql/tanstack-react-router';
*
* const ssr = ssrExchange();
* const client = createClient({
* url: 'https://trygql.formidable.dev/graphql/basic-pokedex',
* exchanges: [cacheExchange, ssr, fetchExchange],
* suspense: true,
* });
*
* const router = createRouter ({
* routeTree,
* Wrap: ({ children }) => <UrqlProvider ssr={ssr} client={urqlClient}>{children}</UrqlProvider>,
* });
* }
*
* ```
*/
export function UrqlProvider({
children,
ssr,
client,
}: React.PropsWithChildren<{
ssr: SSRExchange;
client: Client;
}>) {
return React.createElement(
Provider,
{ value: client },
React.createElement(SSRContext.Provider, { value: ssr }, children)
);
}
3 changes: 3 additions & 0 deletions packages/tanstack-react-router-urql/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from 'urql';
export { useQuery } from './useQuery';
export { UrqlProvider, SSRContext } from './Provider';
Loading

0 comments on commit cae0d95

Please sign in to comment.