Giter Site home page Giter Site logo

next-urql's Introduction

Project Moved

As of March 7, 2020, next-urql has been moved into a core package in the urql monorepo. In an effort to better consolidate and centralize work on the extended urql ecosystem, we at Formidable feels it makes sense to group these projects under a single umbrella. This also promotes better discoverability for contributors and future maintainers.

All new issues, pull requests, and code discussion for this project should happen there. All new releases will be published from that package. Thanks so much for using next-urql!

next-urql

A set of convenience utilities for using urql with NextJS.

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 Promises. For more information, check out react-ssr-prepass.

next-urql handles integrating this prepass step for you, such that your NextJS 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.

npm install --save next-urql urql react-is isomorphic-unfetch

react-is, styled-components, and isomorphic-unfetch help to support server-side Suspense with react-ssr-prepass. This assumes you have followed the basic installation steps for urql here.

Usage

To use next-urql, first import the withUrqlClient higher order component.

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:

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 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. 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 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 section. Check out our example for using next-urql with _app.js here.

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:

type NextUrqlClientConfig =
  | Omit<ClientOptions, 'exchanges' | 'suspense'>
  | ((ctx: NextPageContext) => Omit<ClientOptions, 'exchanges' | 'suspense'>);

The ClientOptions interface comes from urql itself and has the following type:

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. See mergeExchanges below for information on modifying exchanges in next-urql. */
  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;
}

This means you have two options for creating your urql Client. The first involves just passing the options as an object directly:

withUrqlClient({
  url: 'http://localhost:3000',
  fetchOptions: {
    referrer: 'no-referrer',
    redirect: 'follow',
  },
});

The second involves passing a function, which receives Next's context object, ctx, as an argument 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.

withUrqlClient(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. If you need to customize your exchanges beyond the defaults next-urql provides, use the second argument to withUrqlClient, mergeExchanges.

mergeExchanges (Optional)

The mergeExchanges argument is optional. This is a function that takes the ssrExchange created by next-urql as its only argument and allows you to configure your exchanges as you wish. It has the following type signature:

(ssrExchange: SSRExchange) => Exchange[]

By default, next-urql will incorprate the ssrExchange into your exchanges array in the correct location (after any other caching exchanges, but before the fetchExchange – read more here). Use this argument if you want to configure your Client with additional custom exchanges, or access the ssrCache directly to extract or restore data from its cache.

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.

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.

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:

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.

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:

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!

Examples

You can see simple example projects using next-urql in the examples directory or on CodeSandbox.

Caveats

withUrqlClient implements Next's unique getInitialProps method under the hood. This means that any page containing a component wrapped by withUrqlClient will be opted out of automatic static optimization. Automatic static optimization was added in Next v9, so you shouldn't worry about this if using an earlier version of Next. This is not unique to next-urql – any implementation of getInitialProps by any component in your application will cause Next to opt out of automatic static optimization.

next-urql's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

next-urql's Issues

Incompatible with URQL >=1.9

Upgrading from 0.2.3 to 0.3.0 results in the following error:

$ tsc --noEmit
node_modules/next-urql/src/types.ts:3:38 - error TS2307: Cannot find module 'urql/dist/types/exchanges/ssr'.

3 import { SSRExchange, SSRData } from 'urql/dist/types/exchanges/ssr';
                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Found 1 error.

This is because those type definitions are now under the @urql/core namespace.

As a temporary work around I have added the following to my tsconfig.json:

{
  "compilerOptions": {
    "paths": {
      "urql/dist/types/exchanges/*": [
        "node_modules/@urql/core/dist/types/exchanges/*"
      ]
    }
  }
}

Currently this project's package.json specifies "urql": "^1.1.0" which isn't even a year old. I don't know if it's possible to maintain compatibility with older versions and >=1.9.

Handling Authorization

How would you handle authorization, for example if your authorization token is stored as a cookie since you don't have access to the Context

Update examples to use TypeScript.

As more people come to depend on next-urql, we want to ensure our types are as correct as possible, and that we're covering as many edge cases as possible in tests and examples. To that end, I think it makes sense to have our examples implemented in TypeScript. This hopefully shouldn't be too difficult, following the instructions here. We should do both examples/1-with-urql-client and examples/2-with-_app.js.

Bug: pageProps doesn't pass into Component when custom _app.js

Hi guys,

I have an example:

// pages/index.tsx
const Home: React.FC = () => (
  <div>
    <Head>
      <title>Home</title>
      <link rel="icon" href="/favicon.ico" />
    </Head>

    {/* <PokémonList /> */}
  </div>
);

// @ts-ignore
Home.getInitialProps = () => {
  return { test: 'test value' };
};

export default Home;

and

// pages/_app.tsx
import React from 'react';
import { withUrqlClient } from 'next-urql';
import { AppPropsType } from 'next/dist/next-server/lib/utils';

const App: React.FC<AppPropsType> = ({ Component, pageProps }) => {
  console.log(pageProps); // <== BUG HERE, should be return {test: 'test value'}

  return <Component {...pageProps} />;
};

export default App;
// export default withUrqlClient({ url: 'https://graphql-pokemon.now.sh' })(App);

The console.log(pageProps) always return undefined if I used custom with withUrqlClient.

Execute a urql query inside getInitialProps

I'd like to execute a urql query inside getInitialProps. The reason for this is to check if the current user is logged in or not and if not redirect before starting to render the page.

Here's my code:

// _app.js

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

MyApp.getInitialProps = async ctx => {
  // this seems hacky but ctx.ctx is what is available in a pages `getInitialProps` so 
  // I think it might be worthwhile putting urqlClient on `appCtx` in `withUrqlClient` HOC?
  const ctxWithUrql = { ...ctx, ctx: { ...ctx.ctx, urqlClient: ctx.urqlClient } }
  // calls page's `getInitialProps` and fills `appProps.pageProps`
  const appProps = await App.getInitialProps(ctxWithUrql);

  return { ...appProps }
}

export default withUrqlClient({url: process.env.GRAPHQL_ENDPOINT})(MyApp)
// pages/account.js

function Account(props) {
  // cache-only request because current user will be retrieved in `getInitialProps`
  const [result] = useQuery({ query: `{ currentUser { id } }`, requestPolicy: 'cache-only'})
  return (
    <div>
      <h1>Account id {result.currentUser.id}</h1>
    </div>
  )
}

export default withAuthRequired(Account);
// lib/auth/withAuthRequired.js

const executeUrqlQuery = async (client, query) => {
  return new Promise((resolve, reject) => {
    pipe(
      client.executeQuery(createRequest(query.query)),
      subscribe((op) => {
        // setting the requestPolicy here doesn't work, I'm not sure the correct way to set it?
        op.operation.context.requestPolicy = query.requestPolicy
        resolve([op.data, op.error])
      })
    )
  })
}

function withAuthRequired(WrappedComponent) {
  const withAuthRequiredWrapper = props => {
    return <WrappedComponent {...props} />
  }

  withAuthRequiredWrapper.getInitialProps = async ctx => {
    const { urqlClient } = ctx

    const [result, error] = await executeUrqlQuery(urqlClient, { query: `{ users { email } }`, requestPolicy: 'cache-only' });
    
    if (error) {
      // redirect to login
      return
    }

    let pageProps
    if (typeof WrappedComponent.getInitialProps === 'function') {
      pageProps = await WrappedComponent.getInitialProps.call(
        WrappedComponent,
        ctx
      )
    }

    return { ...pageProps }
  }

  return withAuthRequiredWrapper
}

I'm logging this as an issue for a couple of reasons:

  • In withUrqlClient HOC it would be nicer if we put urqlClient on appCtx
  • This might be useful to others and it might be worth adding a utility function to easily execute queries from within getInitialProps?
  • To ensure I'm actually using urql outside of react correctly and how can I set the requestPolicy when doing so? 😅

Circular structure error in 0.2.0

I just upgraded from 0.1.1 to 0.2.0 and now I'm seeing the error below

Circular structure in "getInitialProps" result of page "/mobile-store". https://err.sh/zeit/next.js/circular-structure

Integration with _app.js

Hello,

the doc seems to indicate that it's possible to wrap the App (from _app.js) with withUrqlClient if we don't mind losing static optimization, which is my case.

I just tried and I get this error :

Error: ReactDOMServer does not yet support Suspense.
[0]     at ReactDOMServerRenderer.read (/home/jgoux/Projects/oss/typezafe/node_modules/react-dom/cjs/react-dom-server.node.development.js:3550:25)
[0]     at renderToString (/home/jgoux/Projects/oss/typezafe/node_modules/react-dom/cjs/react-dom-server.node.development.js:4245:27)
[0]     at render (/home/jgoux/Projects/oss/typezafe/node_modules/next/dist/next-server/server/render.js:82:16)
[0]     at Object.renderPage (/home/jgoux/Projects/oss/typezafe/node_modules/next/dist/next-server/server/render.js:323:20)
[0]     at /home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:795:21
[0]     at Generator.next (<anonymous>)
[0]     at asyncGeneratorStep (/home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:239:24)
[0]     at _next (/home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:261:9)
[0]     at /home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:268:7
[0]     at new Promise (<anonymous>)
[0]     at new F (/home/jgoux/Projects/oss/typezafe/node_modules/core-js/library/modules/_export.js:36:28)
[0]     at /home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:257:12
[0]     at Function.getInitialProps (/home/jgoux/Projects/oss/typezafe/.next/server/static/development/pages/_document.js:805:7)
[0]     at Object.loadGetInitialProps (/home/jgoux/Projects/oss/typezafe/node_modules/next/dist/next-server/lib/utils.js:58:29)
[0]     at Object.renderToHTML (/home/jgoux/Projects/oss/typezafe/node_modules/next/dist/next-server/server/render.js:328:36)
[0]     at runMicrotasks (<anonymous>)

Everything works fine when I wrap my pages instead of _app! 👍

How to set res.statusCode?

Is there a way to set HTTP status code with Next-URQL (server-side)?
How to do that?

Without a GraphQL client, when I manually invoked fetchGQL helper, I had something like:

function getInitialProps(ctx) {
  let resp = fetchGQL(...)

  if (resp.error) {
    if (!process.browser) {
      console.error(error)
      if (error.status) {
        ctx.res.statusCode = error.status // !!!
      }
    }
  }
}

Now I can't have access to ctx.res from a component function (serialization kills functions and circular objects) and I don't have access to results of fetching in getInitialProps. So basically I can't use that approach.

I guess it's possible to get HTTP response data via exchanges but I don't think I have access to ctx.res from where those are available. Please clarify.

Client options not updated such as fetchOptions

If you visit a page using withUrqlClient HOC and then login and visit another page and want to set an authorization header like the following (from the readme) the client isn't reinitialized and thus the authorization header is not set.

withUrqlClient(ctx => ({
  url: 'http://localhost:3000',
  fetchOptions: {
    headers: {
      Authorization: `Bearer ${ctx.req.headers.token}`,
    },
  },
}));

Usage Questions

My hat is off to your effort guys to make this work without a finalized Suspense!
Still I'm afraid I'm kinda lost in all the different hacks required for all this to run...
😞

I'm trying to adopt URQL to my GraphQL + NextJS app and I have a couple of lurking questions.
I've read that I don't need getInitialProps to use URQL with NextJS. Sounds great. But I'm not sure how should I restructure my usage patterns previously relying on that function.

Official examples do not demonstrate that aspects.

// pages/[lang]/page.js
function Page(???) {
  // 1) How to pass `ctx` from below to here?
  //    for example I need to log ctx.req.headers

  // 2) How to access NextJS dynamic params (that [lang])?
  //    I previously used getInitialProps({query}) for that

  // 3) What arguments Page accepts in general?
  //    I see that the first is urqlClient, not sure about the others
}

export default withUrqlClient(ctx => {
  return {
    url: `http://localhost:3000/api/graphql`,
     fetchOptions: {
       headers: {
         Authorization: `Bearer ${ctx.req.headers.authorization}`,
       },
     },
  }
})(Page)

P.S. If there's a different place to ask questions like this (Slack?) – pls. suggest it.

useSubscription hook usage example

I'd like to make use of the useSubscription hook when the app is running client-side, and it'd be nice to have the same code run at SSR time. Is it possible to use useSubscription server-side, and if so, is there an example somewhere?

Error when wrapping withUrqlClient with another HOC

Hello!

I am having a weird issue when wrapping withUrlClient with another HOC, (in this case, a withAuth HOC I made).

Given the following withAuth HOC:

const withAuth = (PageComponent: NextPage): NextPage => {
  const AuthWrapper: NextComponentType<NextAuthPageContext> = () => {
    React.useEffect(() => {
      const syncLogout = (event: StorageEvent) => {
        if (event.key === 'logout') {
          Router.push(routes.signIn())
        }
      }

      window.addEventListener('storage', syncLogout)

      return () => {
        window.removeEventListener('storage', syncLogout)
        window.localStorage.removeItem('logout')
      }
    })

    return React.createElement(PageComponent)
  }

  AuthWrapper.getInitialProps = async (ctx) => {
    const token = getToken(ctx)

    if (!token) {
      if (typeof window === 'undefined') {
        ctx.res?.writeHead(302, { Location: routes.signIn() })
        ctx.res?.end()
      } else {
        Router.push(routes.signIn())
      }
    } else {
      ctx.token = token
    }

    let pageProps = {}

    if (PageComponent.getInitialProps) {
      console.log('get pageProps')
      pageProps = await PageComponent.getInitialProps(ctx)
      console.log('pageProps', pageProps)
    }

    return pageProps
  }

  return AuthWrapper
}

And the following abstraction over withUrqlClient:

const withUrql = withUrqlClient((ctx: NextAuthPageContext) => {
  const { token } = ctx

  const host = ctx.req
    ? ctx.req.headers['x-forwarded-host'] || ctx.req.headers.host
    : window.location.host

  const config = {
    url: `${
      host?.includes('localhost') ? 'http' : 'https'
    }://${host}/api/graphql`,
    fetchOptions: {
      headers: {
        Authorization: token ?? `Bearer ${token}`,
      },
    },
  }

  return config
})

I am receiving the following error (maybe related to #24?)

TypeError: Cannot read property 'replace' of undefined #24

This is my page definition:

import React from 'react'
import { NextPage } from 'next'
import compose from 'compose-function'
import { useQuery } from 'urql'

import { withAuth, signOut } from 'lib/auth'
import { withUrql } from 'lib/urql'

import AppLayout from 'layouts/app'
import Typography from '@material-ui/core/Typography'
import Box from '@material-ui/core/Box'

const HomePage: NextPage = () => {
  const [{ data }] = useQuery({
    query: `
      {
        me {
          firstname
          lastname
        }
      }
    `,
  })

  return (
    <AppLayout>
      <Typography>
        {data.me.firstname} {data.me.lastname}
      </Typography>
      <Box clone mt={4}>
        <button type="button" onClick={signOut}>
          Cerrar sesión
        </button>
      </Box>
    </AppLayout>
  )
}

export default compose(withAuth, withUrql)(HomePage)

The code is throwing the error at this step from withAuth:

console.log('get pageProps')
pageProps = await PageComponent.getInitialProps(ctx)
console.log('pageProps', pageProps)

The weird thing is that if I comment the useQuery call, then it passes to the console.log('pageProps', pageProps) and effectively returns the props set in useUrql (i.e. the correct url and fetchOptions).

Screenshot 2020-01-23 at 00 08 09

Why graphQLErrors always empty array?

Hi guys,

I cloned your example https://codesandbox.io/s/next-urql-pokedex-oqj3x

I changed the query. The purpose for faulty

const queryPokemon = gql`
  query pokemon($first: Int!) {
    pokemons(first: $first) {
      id2
    }
  }
`;

But, I did not get graphQLErrors, it's always empty.
Should have received the following error message;
Cannot query field "id2" on type "Pokemon". Did you mean "id"

Sorry, If the problem in urql, not next-urql, thanks in advance.

pages getInitialProps no longer gets called

I'm using withUrqlClient on my _app.js and when I add a getInitialProps to a page it's not getting triggered.

I'm wanting to add a HOC to certain pages that will check if the user is authenticated and if not redirect to the login page.

This is what code looks like when just trying to console log in a pages getInitialProps function.

// pages/_app.js

function MyApp({ Component, pageProps, accessToken }) {
  if (!isServer() && accessToken) {
    setToken(accessToken)
  }

  return <Component {...pageProps} />
}

MyApp.getInitialProps = async ctx => {
  if (isServer()) {
    const cookie = getCookie(ctx)
    if (cookie) {
      const accessToken = await getRefreshToken(cookie, ctx)
      return { accessToken }
    }
  }

  return {}
}

export default withUrqlClient(
  {
    url: process.env.GRAPHQL_ENDPOINT,
  },
  ssrEx => {
    return [
      dedupExchange,
      cacheExchange(),
      refreshTokenExchange(),
      ssrEx,
      fetchExchange,
    ]
  }
)(MyApp)
// pages/account.js

function Account() {
  return (
    <div>
      <h1>Account</h1>
    </div>
  )
}

Account.getInitialProps = async ctx => {
  // This never gets run
  console.log('Account.getInitialProps')
}

export default Account

'next-urql/index.d.ts' is not a module

Hi there! I'm using TypeScript 3.7.2 (but also tried with 3.6.4), and am getting the following error.

ERROR in /Users/tom/_code/web/pages/login.tsx
6:32 File '/Users/tom/_code/web/node_modules/next-urql/index.d.ts' is not a module.
    4 | import gql from 'graphql-tag'
    5 | import { useMutation } from 'urql'
  > 6 | import { withUrqlClient } from 'next-urql'

For context, I was following along with this tutorial, and using Next.js instead of React with React Router.

Happy to provide more info!

Typings seem to be broken in 0.3.0 release

dist/index.d.ts:

export { withUrqlClient } from './with-urql-client';
export * from './types';

These files do not seem to exist:

➜  types git:(gql-refactor) ✗ pwd
/node_modules/next-urql/dist/types
➜  types ✗ ls -lah
total 8
drwxr-xr-x  3 mtford  staff    96B Feb 27 18:43 .
drwxr-xr-x  4 mtford  staff   128B Feb 27 18:43 ..
-rw-r--r--  1 mtford  staff    80B Feb 27 17:40 index.d.ts

I built the project myself and the types seem to generate correctly and are in the dist folder so perhaps something is wrong with your publishing process?

➜  next-urql ✗ node --version
v10.17.0
➜  next-urql ✗ npm --version 
6.13.4

runtime error with [email protected] + react-ssr-prepass

Hi,

I upgraded to [email protected] this morning and it seems that there is an issue with react-ssr-prepass

Here is the stacktrace :

TypeError: Cannot read property 'dispatch' of null
useReducer
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/react-ssr-prepass/src/internals/dispatcher.js:182:42
useState
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/react-ssr-prepass/src/internals/dispatcher.js:163:10
useState
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/react/cjs/react.development.js:1619:21
useSubscription
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/urql/node_modules/use-subscription/cjs/use-subscription.development.js:37:25
useSource
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/urql/src/hooks/useSource.ts:22:3
useQuery
/home/jgoux/Projects/eurofins/colisage-ts/node_modules/urql/src/hooks/useQuery.ts:59:17
useGetSitesQuery
./src/generated/graphql/hooks.ts:1499
  1496 |     `;
  1497 | 
  1498 | export function useGetSitesQuery(options: Omit<Urql.UseQueryArgs<GetSitesQueryVariables>, 'query'> = {}) {
> 1499 |   return Urql.useQuery<GetSitesQuery>({ query: GetSitesDocument, ...options });
  1500 | };
  1501 | export const GetSiteDocument = gql`
  1502 |     query getSite($id: UUID!) {
View compiled
Component
./src/components/pages/settings/sites/index.tsx:40
  37 | const page = usePage();
  38 | const snackbar = useSnackbar();
  39 | const dialog = useDialog();
> 40 | const [{ data }] = useGetSitesQuery();
     | ^  41 | 
  42 | const handleFabClick = () => {
  43 |   page.actions.setCreateSiteForm();

Everything is fine with [email protected]

cacheExchange with next-urql

Hello !

I've been using urql next-urql & @urql/exchange-graphcache with NextJS.
I use the withUrqlClient HOC only on pages that needs SSR but I would like to use optimistic response and I cannot make it work.
At first I wrapped the _app.tsx with a <Provider client={client}></Provider> and still used the withUrqlClient HOC. But then components inside the SSR Page would not benefit from the client side optimistic resolvers.

const client = createClient({
  url: process.env.API_ENDPOINT as string,
  exchanges: [
    dedupExchange,
    cacheExchange({
      optimistic: {
        myMutation: (variables) => ({
          ...variables,
          __typename: 'MyTypeName',
        }),
      },
    }),
    fetchExchange,
  ],
  fetchOptions: {
    credentials: 'include',
  },
});

class MyApp extends App {
  render(): JSX.Element {
    const { Component, pageProps } = this.props as any;
    return (
      <>
          <Provider value={client}>
            <Component {...pageProps} />
          </Provider>
      </>
    );
  }
}

export default MyApp;
const Page = () => (
   <>
      ...
      <MyMutationComponent />
   </>
)

// I tried to use the same as the client side urql
export default withUrqlClient(ctx => {
  url: process.env.API_ENDPOINT as string,
  exchanges: [
    dedupExchange,
    cacheExchange({
      optimistic: {
        myMutation: (variables) => ({
          ...variables,
          __typename: 'MyTypeName',
        }),
      },
    }),
    fetchExchange,
  ],
  fetchOptions: {
    headers: ctx?.req?.headers,
    credentials: 'include',
  },
})(Page);

Obviously if I remove the HOC, the client side urql will work properly.
If I keep the HOC but also keep the Provider that wraps _app.tsx, it still doesn't work because I guess my <MyMutationComponent /> uses the provider from the withUrqlClient HOC.

Should I wrap the component doing the mutation with a client side urql provider ?

Thank you,

n44ps

SyntaxError: Unexpected token *

This is almost certainly me and my lack of experience with Next.js:

I have a working reasonml/next-js site, and I'm trying to add in reason-urql, but I'm hitting this error:

/Users/s/code/nextjs-default/node_modules/wonka/src/wonka.js:3
import * as WonkaJs from "./web/wonkaJs.js";
       ^

SyntaxError: Unexpected token *
    at Module._compile (internal/modules/cjs/loader.js:811:22)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:879:10)
    at Module.load (internal/modules/cjs/loader.js:731:32)
    at Function.Module._load (internal/modules/cjs/loader.js:644:12)
    at Module.require (internal/modules/cjs/loader.js:771:19)
    at require (internal/modules/cjs/helpers.js:68:18)
    at Object.wonka/src/wonka.js (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:5192:18)
    at __webpack_require__ (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:23:31)
    at Module../node_modules/reason-urql/src/UrqlClient.bs.js (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:4247:76)
    at __webpack_require__ (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:23:31)
    at Module../node_modules/reason-urql/src/ReasonUrql.bs.js (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:4172:75)
    at __webpack_require__ (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:23:31)
    at Module../pages/items.bs.js (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:4822:90)
    at __webpack_require__ (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:23:31)
    at Module../pages/index.bs.js (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:4730:70)
    at __webpack_require__ (/Users/s/code/nextjs-default/.next/server/static/development/pages/index.js:23:31)

It's probably not related, given the stacktrace, but my initial sketch of the bindings are very simple:

type urqlClient('a) = 'a => React.element;

type withUrqlClient = {url: string};

[@bs.module "next-urql"]
external withUrqlClient: withUrqlClient => urqlClient('a) = "withUrqlClient";

I'm happy to provide any additional information I can to help sort this out. I'm working off of https://github.com/ryyppy/nextjs-default as a starting point!

TypeError: Cannot read property 'replace' of undefined

These are the versions I'm using:

"dependencies": {
    "@material-ui/core": "^4.8.3",
    "@material-ui/icons": "^4.5.1",
    "graphql": "^14.5.8",
    "graphql-tag": "^2.10.1",
    "isomorphic-unfetch": "^3.0.0",
    "next": "^9.2.0",
    "next-urql": "^0.2.4",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-is": "^16.12.0",
    "styled-components": "^5.0.0",
    "urql": "^1.8.2"
  },
  "devDependencies": {
    "@types/node": "^13.1.7",
    "@types/react": "^16.9.17",
    "typescript": "^3.7.4"
  },

This is the config of the _app.tsx file:

import React from "react";
import App from "next/app";
import Head from "next/head";
import { withUrqlClient } from "next-urql";
import { ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";

import theme from "../lib/theme";
import { Layout } from "../components/Layout";

class MyApp extends App {
  componentDidMount() {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector("#jss-server-side");

    if (jssStyles) {
      jssStyles.parentElement.removeChild(jssStyles);
    }
  }

  render() {
    const { Component, pageProps } = this.props;

    return (
      <>
        <Head>
          <title>Diey | Shooter</title>
          <meta
            name="viewport"
            content="minimum-scale=1, initial-scale=1, width=device-width"
          />
        </Head>
        <ThemeProvider theme={theme}>
          {/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
          <CssBaseline />
          <Layout>
            <Component {...pageProps} />
          </Layout>
        </ThemeProvider>
      </>
    );
  }
}

export default withUrqlClient({
  url: process.env.GRAPHQL_API,
  fetchOptions: {
    headers: {
      "x-hasura-admin-secret": process.env.GRAPHQL_API_PASSWORD
    }
  }
})(MyApp);

This is the page index, the component index.tsx. This error comes when I just run a simple query:

import React from "react";
import Link from "next/link";
import { useQuery } from "urql";

import Container from "@material-ui/core/Container";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import MuiLink from "@material-ui/core/Link";

function Copyright() {
  return (
    <Typography variant="body2" color="textSecondary" align="center">
      {"Copyright © "}
      <MuiLink color="inherit" href="https://material-ui.com/">
        Your Website
      </MuiLink>{" "}
      {new Date().getFullYear()}
      {"."}
    </Typography>
  );
}

const index = () => {
  const [{ data }] = useQuery({
    query: `
    query getSections {
      Sections {
        Publications {
          title
          description
          image
        }
      }
    }  
  `
  });

  console.log(data);

  return (
    <Container maxWidth="sm">
      <Box my={4}>
        <Typography variant="h4" component="h1" gutterBottom>
          Next.js example
        </Typography>
        <Link href="/about">Go to the about page</Link>
        <Copyright />
      </Box>
    </Container>
  );
};

export default index;

How can I solve it? When I add it in index.tsx page happens the same, This is the complete message:

andres@andres:~/Documents/shooter-app$ yarn dev
yarn run v1.21.1
$ next
[ wait ]  starting the development server ...
[ info ]  waiting on http://localhost:3000 ...
[ info ]  bundled successfully, waiting for typecheck results...
[ wait ]  compiling ...
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000
[ event ] build page: /
[ wait ]  compiling ...
[ info ]  bundled successfully, waiting for typecheck results...
[ ready ] compiled successfully - ready on http://localhost:3000
/home/andres/Documents/shooter-app/node_modules/react-ssr-prepass/dist/react-ssr-prepass.development.js:382
      throw error;
      ^

TypeError: Cannot read property 'replace' of undefined
    at /home/andres/Documents/shooter-app/node_modules/isomorphic-unfetch/index.js:3:36
    at executeFetch (/home/andres/Documents/shooter-app/node_modules/urql/dist/cjs/core.js:274:30)
    at /home/andres/Documents/shooter-app/node_modules/urql/dist/cjs/core.js:256:5
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:106:9
    at _1 (/home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:178:20)
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:1017:7
    at _1 (/home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:178:20)
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:477:13
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:498:12
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:748:28
    at b (/home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:865:14)
    at Array.forEach (<anonymous>)
    at b (/home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:864:77)
    at /home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:748:28
    at b (/home/andres/Documents/shooter-app/node_modules/wonka/dist/wonka.js:865:14)
    at Array.forEach (<anonymous>)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Upgrade Next types

Summary

We're currently on Next 8 and can upgrade to Next 9. This involves:

  • switching out @types/next (deprecated) for latest next version
  • rewriting NextContextWithAppTree

Context

Discussion with more detail: #19 (comment)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.