Gatsby: Use ApolloClient with Gatsby V2

Created on 23 Jan 2019  ·  10Comments  ·  Source: gatsbyjs/gatsby

Summary

I am trying to integrate ApolloClient with Gatsby V2, but I am having some troubles since it already includes GraphQL and they use different versions.

Relevant information

Looking on the internet, I have found a workaround in develop environment using Yarn with:

  "resolutions": {
    "graphql": "0.13.2"
  },

Unfortunately, it won't compile with gatsby build and outputs the following:

error Building static HTML for pages failed

See our docs page on debugging HTML builds for help https://gatsby.app/debug-html

  38 |       var args = [a, b, c, d, e, f];
  39 |       var argIndex = 0;
> 40 |       error = new Error(
     | ^
  41 |         format.replace(/%s/g, function() { return args[argIndex++]; })
  42 |       );
  43 |       error.name = 'Invariant Violation';


  WebpackError: Invariant Violation: Could not find "client" in the context of ApolloConsumer. Wrap the root component in an <ApolloProvider>

  - invariant.js:40 invariant
    [lib]/[invariant]/invariant.js:40:1

  - ApolloConsumer.js:4 ApolloConsumer
    [lib]/[react-apollo]/ApolloConsumer.js:4:1



  - bootstrap:25 a.render
    lib/webpack/bootstrap:25:1

  - bootstrap:24 a.read
    lib/webpack/bootstrap:24:1

  - bootstrap:36 renderToString
    lib/webpack/bootstrap:36:1

  - static-entry.js:190 Module../.cache/static-entry.js.__webpack_exports__.default.React.Component [as default]
    lib/.cache/static-entry.js:190:18

  - bootstrap:24 Promise
    lib/webpack/bootstrap:24:1

  - api-ssr-docs.js:135 Promise._execute
    lib/.cache/api-ssr-docs.js:135:1


  - bootstrap:68 new Promise
    lib/webpack/bootstrap:68:1


  - bootstrap:5 tryCatcher
    lib/webpack/bootstrap:5:1

  - bootstrap:50 MappingPromiseArray._promiseFulfilled
    lib/webpack/bootstrap:50:1

  - api-runner-ssr.js:6 MappingPromiseArray.PromiseArray._iterate

This is the way I wrap my ApolloProvider:

/**
 * Implement Gatsby's Browser APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/browser-apis/
 */

// You can delete this file if you're not using it

import React from 'react'
import { CookiesProvider } from 'react-cookie'
import { ApolloProvider } from 'react-apollo'
import ApolloClient from 'apollo-boost'
import Cookies from 'universal-cookie'

import { version } from './src/graphql'

const cookies = new Cookies()
const client = new ApolloClient({
  uri: process.env.GRAPHQL_URL,
  request: operation => {
    operation.setContext({
      headers: {
        Authorization: cookies.get('jwt')
          ? `Bearer ${cookies.get('jwt')}`
          : undefined,
      },
    })
  },
})

export const wrapRootElement = ({ element }) => {
  return (
    <CookiesProvider>
      <ApolloProvider client={client}>{element}</ApolloProvider>
    </CookiesProvider>
  )
}

Environment (if relevant)


  System:
    OS: macOS 10.14.2
    CPU: (8) x64 Intel(R) Core(TM) i7-6920HQ CPU @ 2.90GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 8.15.0 - ~/.nvm/versions/node/v8.15.0/bin/node
    Yarn: 1.3.2 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v8.15.0/bin/npm
  Languages:
    Python: 2.7.10 - /usr/bin/python
  Browsers:
    Chrome: 71.0.3578.98
    Firefox: 57.0.4
    Safari: 12.0.2
  npmPackages:
    gatsby: ^2.0.76 => 2.0.91 
    gatsby-image: ^2.0.20 => 2.0.26 
    gatsby-plugin-manifest: ^2.0.9 => 2.0.13 
    gatsby-plugin-offline: ^2.0.16 => 2.0.21 
    gatsby-plugin-react-helmet: ^3.0.2 => 3.0.5 
    gatsby-plugin-sass: ^2.0.7 => 2.0.7 
    gatsby-plugin-sharp: ^2.0.14 => 2.0.17 
    gatsby-source-filesystem: ^2.0.8 => 2.0.16 
    gatsby-transformer-sharp: ^2.1.8 => 2.1.10 

File contents (if changed)

gatsby-config.js:

module.exports = {
  siteMetadata: {
    title: `Gatsby Default Starter`,
    description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
    author: `@gatsbyjs`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
      },
    },
    'gatsby-plugin-sass',
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.app/offline
    // 'gatsby-plugin-offline',
  ],
}

package.json:

{
  "name": "gatsby-starter-default",
  "private": true,
  "description": "A simple starter to get up and developing quickly with Gatsby",
  "version": "0.1.0",
  "author": "Kyle Mathews <[email protected]>",
  "engines": {
    "node": "8.15.0"
  },
  "dependencies": {
    "apollo-boost": "^0.1.25",
    "dotenv": "^6.2.0",
    "formik": "^1.4.2",
    "gatsby": "^2.0.76",
    "gatsby-image": "^2.0.20",
    "gatsby-plugin-manifest": "^2.0.9",
    "gatsby-plugin-offline": "^2.0.16",
    "gatsby-plugin-react-helmet": "^3.0.2",
    "gatsby-plugin-sass": "^2.0.7",
    "gatsby-plugin-sharp": "^2.0.14",
    "gatsby-source-filesystem": "^2.0.8",
    "gatsby-transformer-sharp": "^2.1.8",
    "graphql": "^0.13.2",
    "graphql-tag": "^2.10.1",
    "node-sass": "^4.11.0",
    "prop-types": "^15.6.2",
    "react": "^16.6.3",
    "react-apollo": "^2.3.3",
    "react-cookie": "^3.0.8",
    "react-dom": "^16.6.3",
    "react-helmet": "^5.2.0",
    "yup": "^0.26.7"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "start": "gatsby serve --port ${PORT}",
    "format": "prettier --write \"src/**/*.js\"",
    "test": "echo \"Write tests! -> https://gatsby.app/unit-testing\"",
    "heroku-postbuild": "gatsby build"
  },
  "devDependencies": {
    "husky": "^1.3.1",
    "prettier": "^1.15.2",
    "pretty-quick": "^1.10.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/gatsbyjs/gatsby-starter-default"
  },
  "bugs": {
    "url": "https://github.com/gatsbyjs/gatsby/issues"
  },
  "resolutions": {
    "graphql": "0.13.2"
  },
  "husky": {
    "hooks": {
      "pre-commit": "pretty-quick --staged"
    }
  }
}

gatsby-node.js:

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */

// You can delete this file if you're not using it

// Implement the Gatsby API “onCreatePage”. This is
// called after every page is created.

require('dotenv').config({
  path: `.env.${process.env.NODE_ENV}`,
})

exports.onCreatePage = ({ page, actions }) => {
  const { createPage } = actions
  // Make the front page match everything client side.
  // Normally your paths should be a bit more judicious.
  if (page.path === `/`) {
    page.matchPath = `/*`
    createPage(page)
  }
}

gatsby-browser.js:

/**
 * Implement Gatsby's Browser APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/browser-apis/
 */

// You can delete this file if you're not using it

import React from 'react'
import { CookiesProvider } from 'react-cookie'
import { ApolloProvider } from 'react-apollo'
import ApolloClient from 'apollo-boost'
import Cookies from 'universal-cookie'

import { version } from './src/graphql'

const cookies = new Cookies()
const client = new ApolloClient({
  uri: process.env.GRAPHQL_URL,
  request: operation => {
    operation.setContext({
      headers: {
        Authorization: cookies.get('jwt')
          ? `Bearer ${cookies.get('jwt')}`
          : undefined,
      },
    })
  },
})

export const wrapRootElement = ({ element }) => {
  return (
    <CookiesProvider>
      <ApolloProvider client={client}>{element}</ApolloProvider>
    </CookiesProvider>
  )
}

gatsby-ssr.js: N/A

question or discussion

Most helpful comment

Hi! 👋

I built an app live at the GraphQL Summit that does this. Video is here: https://www.youtube.com/watch?v=wNUg1jpj9T0&index=9&t=168s&list=PLz8Iz-Fnk_eQGt4-VFFCXYuYcuKaw4F07

I’m going to close this, but please follow up if you have any additional questions!

All 10 comments

@guidolodetti Could you please link to a minimal reproduction repository for this?

@sidharthachatterjee here is the started project with my additional commit for ApolloClient. Using withApollo() breaks the yarn build task!

@devnasim you got same issue right ?

@guidolodetti @sidharthachatterjee look into that https://github.com/devnasim/gatsby-apollo-graphql
might be helpful.

Hey @guidolodetti

This is breaking because on SSR the root element is unwrapped and therefore Apollo Client complains about the lack of a Provider.

You'll want to implement wrapRootElement in gatsby-ssr.js as well like this:

import React from 'react'
import { ApolloProvider } from 'react-apollo'
import ApolloClient from 'apollo-boost'

const client = new ApolloClient({
  uri: 'http://localhost:4000',
})

export const wrapRootElement = ({ element }) => (
  <ApolloProvider client={client}>{element}</ApolloProvider>
)

Also you'll need to add isomorphic-fetch to your dependencies since apollo looks for fetch to make HTTP requests

You can check out a minimal working example of Gatsby with Apollo at https://github.com/jlengstorf/gatsby-with-apollo (H/T @jlengstorf)

Hi! 👋

I built an app live at the GraphQL Summit that does this. Video is here: https://www.youtube.com/watch?v=wNUg1jpj9T0&index=9&t=168s&list=PLz8Iz-Fnk_eQGt4-VFFCXYuYcuKaw4F07

I’m going to close this, but please follow up if you have any additional questions!

Hi @jlengstorf, your sample codes link does not use any plugin to bring in apollo client. there is a plugin gatsby theme apollo which can be used to enable client side apollo too. Any difference between using your method vs the plugin? Thanks

@myhendry to give you some context. The example code in the repo you mentioned is meant to show you that you're not bound to the Gatsby graphql layer exclusively, you can use apollo just fine without any issues. More even if you should need more than just fetching the data, more specificaly if you need to do some mutations or probably subscriptions. Technically there aren't any differences, the theme that currently exists it's basically a pre built kit that will streamline your development process, so that you don't waste time on adding the packages and creating the files and adding the code, leaving you with just some minor configurations that are probably required and focus on getting content into the you're developing

Thanks @jonniebigodes for the explanation. Got it :)

hey i followed the process of adding apollo clien by referencing https://github.com/jlengstorf/gatsby-with-apollo (H/T @jlengstorf)
but still i can't see the content on view source for SSR

Was this page helpful?
0 / 5 - 0 ratings

Related issues

totsteps picture totsteps  ·  3Comments

3CordGuy picture 3CordGuy  ·  3Comments

magicly picture magicly  ·  3Comments

benstr picture benstr  ·  3Comments

dustinhorton picture dustinhorton  ·  3Comments