Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add @urql/tanstack-react-router #3729

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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': minor
---

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
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
8 changes: 8 additions & 0 deletions packages/tanstack-react-router-urql/jsr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@urql/tanstack-react-router",
"version": "0.0.0",
"exports": {
".": "./src/index.ts"
},
"exclude": ["node_modules"]
}
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": "0.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": "urql GraphQL Contributors",
"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",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are missing the export mappings, examples in other packages

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i was looking at packages/react-urql/package.json which also does not have export mappings.
Why do we need export mappings here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

React-urql is a special case due to some old frameworks, vite is a good bundler so we should incorporate export mappings to future proof the package. What we do with react-urql is still a bit of a pickle, especially with regards to react-native

"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.43.2",
"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
Loading