next-urql
Advanced tools
Comparing version 5.0.0 to 5.0.1
# Changelog | ||
## 5.0.1 | ||
### Patch Changes | ||
- Publish with npm provenance | ||
Submitted by [@kitten](https://github.com/kitten) (See [#3180](https://github.com/urql-graphql/urql/pull/3180)) | ||
## 5.0.0 | ||
@@ -4,0 +11,0 @@ |
{ | ||
"name": "next-urql", | ||
"version": "5.0.0", | ||
"version": "5.0.1", | ||
"description": "Convenience wrappers for using urql with NextJS.", | ||
@@ -37,4 +37,4 @@ "sideEffects": false, | ||
"react-is": "^17.0.1", | ||
"@urql/core": "4.0.0", | ||
"urql": "4.0.0" | ||
"@urql/core": "4.0.7", | ||
"urql": "4.0.1" | ||
}, | ||
@@ -48,2 +48,5 @@ "dependencies": { | ||
}, | ||
"publishConfig": { | ||
"provenance": true | ||
}, | ||
"scripts": { | ||
@@ -50,0 +53,0 @@ "test": "vitest --config ../../vitest.config.ts", |
256
README.md
@@ -1,10 +0,1 @@ | ||
<div align="center"> | ||
<img src="../../docs/assets/next-logo.png" alt="Next.js" height="200" width="200"> | ||
<img src="../../packages/site/src/assets/sidebar-badge.svg" alt="urql" height="200" width="200"> | ||
<br /> | ||
<a href="https://npmjs.com/package/next-urql"> | ||
<img alt="NPM Version" src="https://img.shields.io/npm/v/next-urql.svg" /> | ||
</a> | ||
</div> | ||
## `next-urql` | ||
@@ -14,246 +5,3 @@ | ||
### Motivation | ||
Using GraphQL with server-side rendering in React is a challenging problem. Currently, React has no support for `Suspense` for data fetching on the server. To get around this, a prepass step can be used to walk the tree (or a subsection of the tree) of your React application and suspend when it encounters thrown `Promise`s. For more information, check out [`react-ssr-prepass`](https://github.com/FormidableLabs/react-ssr-prepass). | ||
`next-urql` handles integrating this prepass step for you, such that your Next.js application using `urql` will prefetch your GraphQL queries on the server before sending down markup to the Client. | ||
### Installation | ||
Install `next-urql` along with its `peerDependencies`. | ||
```sh | ||
yarn add next-urql react-is urql graphql | ||
# or | ||
npm install --save next-urql react-is urql graphql | ||
``` | ||
`react-is` helps to support server-side `Suspense` with `react-ssr-prepass`. This assumes you have followed the basic installation steps for `urql` [here](https://github.com/urql-graphql/urql#installation). | ||
Note that if you are using Next before v9.4 you'll need to polyfill fetch, this can be | ||
done through [`isomorphic-unfetch`](https://www.npmjs.com/package/isomorphic-unfetch). | ||
### Usage | ||
To use `next-urql`, first `import` the `withUrqlClient` higher order component. | ||
```javascript | ||
import { withUrqlClient } from 'next-urql'; | ||
``` | ||
Then, for any page in your `pages` directory for which you want to prefetch GraphQL queries, wrap the page in `withUrqlClient`. For example, let's say you have an `index.js` page that renders two components that make GraphQL requests using `urql`, `PokemonList` and `PokemonTypes`. To run their queries initially on the server-side you'd do something like the following: | ||
```javascript | ||
import React from 'react'; | ||
import Head from 'next/head'; | ||
import { withUrqlClient } from 'next-urql'; | ||
import PokemonList from '../components/pokemon_list'; | ||
import PokemonTypes from '../components/pokemon_types'; | ||
const Root = () => ( | ||
<div> | ||
<Head> | ||
<title>Root</title> | ||
<link rel="icon" href="/static/favicon.ico" /> | ||
</Head> | ||
<PokemonList /> | ||
<PokemonTypes /> | ||
</div> | ||
); | ||
export default withUrqlClient(() => ({ url: 'https://graphql-pokemon.now.sh' }))(Root); | ||
``` | ||
Read more below in the [API](#API) section to learn more about the arguments that can be passed to `withUrqlClient`. | ||
#### Integration with `_app.js` | ||
Next allows you to override the root of your application using a special page called [`_app.js`](https://nextjs.org/docs#custom-app). If you want to have all GraphQL requests in your application fetched on the server-side, you _could_ wrap the component exported by `_app.js` in `withUrqlClient`. However, be aware that this will opt you out of [automatic static optimization](https://nextjs.org/docs#automatic-static-optimization) for your entire application. In general, it's recommended practice to only use `withUrqlClient` on the pages that have GraphQL operations in their component tree. Read more in the [Caveats](#Caveats) section. Check out our example for using `next-urql` with `_app.js` [here](./examples/2-with-_app.js/README.md). | ||
### API | ||
`next-urql` exposes a single higher order component, `withUrqlClient`. This HoC accepts two arguments: | ||
#### `clientOptions` (Required) | ||
The `clientOptions` argument is required. It represents all of the options you want to enable on your `urql` Client instance. It has the following union type: | ||
```typescript | ||
type NextUrqlClientConfig = (ssrExchange: SSRExchange, ctx?: PartialNextContext) => ClientOptions; | ||
``` | ||
The `ClientOptions` `interface` comes from `urql` itself and has the following type: | ||
```typescript | ||
interface ClientOptions { | ||
/** The GraphQL endpoint your application is using. */ | ||
url: string; | ||
/** Any additional options to pass to fetch. */ | ||
fetchOptions?: RequestInit | (() => RequestInit); | ||
/** An alternative fetch implementation. */ | ||
fetch?: typeof fetch; | ||
/** The exchanges used by the Client. */ | ||
exchanges?: Exchange[]; | ||
/** A flag to enable suspense on the server. next-urql handles this for you. */ | ||
suspense?: boolean; | ||
/** The default request policy for requests. */ | ||
requestPolicy?: RequestPolicy; | ||
/** Use HTTP GET for queries. */ | ||
preferGetMethod?: boolean; | ||
/** Mask __typename from results. */ | ||
maskTypename?: boolean; | ||
} | ||
``` | ||
You can create a client by passing a function which receives the `ssrExchange` and Next's context object, `ctx`, as arguments and returns `urql`'s Client options. This is helpful if you need to access some part of Next's context to instantiate your Client options. **Note: `ctx` is _only_ available on the initial server-side render and _not_ on client-side navigation**. This is necessary to allow for different Client configurations between server and client. | ||
```typescript | ||
withUrqlClient((_ssrExchange, ctx) => ({ | ||
url: 'http://localhost:3000', | ||
fetchOptions: { | ||
headers: { | ||
Authorization: ctx | ||
? `Bearer ${ctx?.req?.headers?.Authorization ?? ''}` | ||
: localStorage.getItem('token') ?? '', | ||
}, | ||
}, | ||
})); | ||
``` | ||
In client-side SPAs using `urql`, you typically configure the Client yourself and pass it as the `value` prop to `urql`'s context `Provider`. `withUrqlClient` handles setting all of this up for you under the hood. By default, you'll be opted into server-side `Suspense` and have the necessary `exchanges` set up for you, including the [`ssrExchange`](https://formidable.com/open-source/urql/docs/api/#ssrexchange-exchange-factory). | ||
### Resetting the client instance | ||
In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this is an uncommon scenario | ||
and we consider it "unsafe" so evaluate this carefully for yourself. | ||
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. | ||
#### `exchanges` | ||
When you're using `withUrqlClient` and you don't return an `exchanges` property we'll assume you wanted the default exchanges, these contain: `dedupExchange`, `cacheExchange`, `ssrExchange` (the one you received as a first argument) and the `fetchExchange`. | ||
When you yourself want to pass exchanges don't forget to include the `ssrExchange` you received as the first argument. | ||
#### `withUrqlClientOptions` | ||
The second argument for `withUrqlClient` is an options object, this contains one `boolean` property named `ssr`, you can use this to tell | ||
`withUrqlClient` that the wrapped component does not use `getInitialProps` but the children of this wrapped component do. This opts you into | ||
`ssr` for these children. | ||
### Different Client configurations on the client and the server | ||
There are use cases where you may need different configurations for your `urql` Client on the client-side and the server-side; for example, you may want to interact with one GraphQL endpoint on the server-side and another on the client-side. `next-urql` supports this as of v0.3.0. We recommend using `typeof window === 'undefined'` or a `process.browser` check. | ||
```typescript | ||
withUrqlClient({ | ||
url: | ||
typeof window === 'undefined' | ||
? 'https://my-server-graphql-api.com/graphql' | ||
: 'https://my-client-graphql-api.com/graphql', | ||
}); | ||
``` | ||
If you want more customization of your Client instance to modify requests on specific routes, for instance, consider using a custom exchange. You can find an example of that [here](/examples/3-with-custom-exchange/README.md). | ||
### Accessing the `urql` Client inside a Page component's `getInitialProps` method | ||
There are use cases where you may want to access the `urql` Client instance inside your Page component's `getInitialProps` method. To support this, we actually attach the `urql` Client instance to the `ctx` object passed to your Page's `getInitialProps` method. You can access it like so: | ||
```typescript | ||
import { NextUrqlPageContext } from 'next-urql'; | ||
const Page = () => { | ||
return <main />; | ||
}; | ||
Page.getInitialProps = async (ctx: NextUrqlPageContext) => { | ||
// Do something with the urql Client instance! | ||
let client = ctx.urqlClient; | ||
return { | ||
...props, | ||
}; | ||
}; | ||
``` | ||
### Usage with ReasonML | ||
While there are no official bindings for using `next-urql` with ReasonML, porting `next-urql` to Reason is not too difficult. Moreover, having your own bindings means you can select only the pieces you need from the library. Here's an example of how you could bind `next-urql` if you only needed access to the non-functional `clientOptions` API, and only wanted to pass a `url` and `fetchOptions`. This assumes BuckleScript 7 to take advantage of records compiling into plain JS objects and assumes usage of [`bs-fetch`](https://github.com/reasonml-community/bs-fetch). | ||
```reason | ||
type clientOptions = { | ||
url: string, | ||
fetchOptions: Fetch.requestInit | ||
}; | ||
[@bs.module "next-urql"] | ||
external withUrqlClient: | ||
(. clientOptions) => | ||
(. React.component('props)) => React.component('props) = | ||
"withUrqlClient"; | ||
``` | ||
Which can then be used like so: | ||
```reason | ||
let headers = Fetch.HeadersInit.make({ "Content-Type": "application/json" }); | ||
let client = { | ||
url: "https://mygraphqlapi.com/graphql", | ||
fetchOptions: Fetch.RequestInit.make(~headers, ~method_=POST, ()) | ||
}; | ||
[@react.component] | ||
let make = () => { | ||
<h1>"Heck yeah, next-urql with Reason!"->React.string</h1> | ||
}; | ||
let default = (withUrqlClient(. clientOptions))(. make); | ||
``` | ||
The great part about writing thin bindings like this is that they are zero cost – in fact, the above bindings get totally compiled away by BuckleScript, so you get the full benefits of type safety with absolutely zero runtime cost! | ||
### Restricting Data Fetching to the Server | ||
If you want to use a `Client` in Next.js' newer methods like `getServerSideProps` you may use the `initUrqlClient` function to create a client on the fly. This will need to be done per request. | ||
```javascript | ||
import { initUrqlClient } from 'next-urql'; | ||
export const getServerSideProps = async ctx => { | ||
const client = initUrqlClient( | ||
{ | ||
url: '/graphql', | ||
}, | ||
false /* set to false to disable suspense */ | ||
); | ||
const result = await client.query(QUERY, {}).toPromise(); | ||
return { | ||
props: { data: result.data }, | ||
}; | ||
}; | ||
``` | ||
The first argument passed to the `initUrqlClient` function is the same object that we'd normally pass to `createClient`. | ||
The second argument is a `boolean` flag indicating whether or not to enable `suspense`; typically, we'd disable it for manual usage. | ||
### Examples | ||
You can see simple example projects using `next-urql` in the `examples` directory or on [CodeSandbox](https://codesandbox.io/s/next-urql-pokedex-oqj3x). | ||
### Caveats | ||
Using `withUrqlClient` on a page that has `getInitialProps` will opt that component and it's children into a prepass that does a first pass of all queries, when that | ||
component has children using `getInitialProps` but that component itself is not and you want to opt in to this behavior you'll have to set the second argument of | ||
`withUrqlClient`, this means `withUrqlClient(() => clientOptions, { ssr:true })`. | ||
This measure is available so we can support `getStaticProps`, ... | ||
When you are using `getStaticProps`, `getServerSideProps`, or `getStaticPaths`, you should opt-out of `Suspense` by setting the `neverSuspend` option to `true` in your `withUrqlClient` configuration. | ||
your `withUrqlClient`. | ||
During the prepass of your component tree `next-urql` can't know how these functions will alter the props passed to your page component. This injection | ||
could change the `variables` used in your `useQuery`. This will lead to error being thrown during the subsequent `toString` pass, which isn't supported in React 16. | ||
More documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#nextjs | ||
Examples can be found at https://github.com/urql-graphql/urql/tree/main/examples/with-next |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
0
91515
7