gatsby: StaticQuery silently fails when used inside wrapRootElement and wrapPageElement

Description

Using a StaticQuery in a a component inside wrapRootElement or wrapPageElement results in Loading (StaticQuery) both for gatsby-node.js and gatsby-ssr.js.

Steps to reproduce

Using this wrapRootElement implementation the issue appears:

import React from 'react'
import { graphql, StaticQuery } from 'gatsby'

export const wrapRootElement = ({ element }) => (
  <StaticQuery
    query={graphql`
      query {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data => element}
  />
)

When using this code, the context is empty which seems to be the reason.

import React from 'react'
import { StaticQueryContext } from 'gatsby'

export const wrapRootElement = ({ element }) => (
  <StaticQueryContext.Consumer>
    {staticQueryData => {
      console.log(staticQueryData)
      return element
    }}
  </StaticQueryContext.Consumer>
)

Expected result

The context should be set for the wrapRootElement and wrapPageElement APIs or if this is intended, there should be a warning in StaticQuery if no context is available.

Actual result

It fails silently and appears to be loading forever.

Environment

  System:
    OS: Linux 4.4 Ubuntu 16.04.5 LTS (Xenial Xerus)
    CPU: x64 Intel(R) Core(TM) i5-2400 CPU @ 3.10GHz
    Shell: 4.3.48 - /bin/bash
  Binaries:
    Node: 10.9.0 - ~/opt/node/latest/bin/node
    Yarn: 1.9.4 - ~/opt/node/latest/bin/yarn
    npm: 6.4.1 - ~/opt/node/latest/bin/npm
  Browsers:
    Chrome: 68.0.3440.106
    Firefox: 61.0.1
  npmPackages:
    gatsby: next => 2.0.0-rc.4 
    gatsby-plugin-manifest: next => 2.0.2-rc.1 
    gatsby-plugin-offline: next => 2.0.0-rc.1 
    gatsby-plugin-react-helmet: next => 3.0.0-rc.1 
  npmGlobalPackages:
    gatsby-cli: 1.1.58

File contents (if changed)

gatsby-config.js: N/A package.json: N/A gatsby-node.js: see above gatsby-browser.js: see above gatsby-ssr.js: N/A

If given some general directions, I would be happy to contribute and make a PR for this issue.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 23
  • Comments: 46 (10 by maintainers)

Commits related to this issue

Most upvoted comments

Is this problem really solved? I keep getting the following error:

Generating SSR bundle failed

Can't resolve 'public/static/d/3159585216.json' in '/Users/a1/private/za-Szklem'

If you're trying to use a package make sure that 'public/static/d/3159585216.json' is installed. If you're trying to use a local file make sure that the path is correct.

File: gatsby-ssr.js

not finished Building static HTML for pages - 2.181s

I updated to the given version, and I do something like this (in gatsby-ssr.js):

import React from 'react';
import { graphql, StaticQuery } from 'gatsby';
import { wrapRootElement as wrap } from './root-wrapper';

export const wrapRootElement = wrap;

export const wrapPageElement = ({ element, props }) => {
  return (
    <StaticQuery
      query={graphql`
        query {
          site {
            siteMetadata {
              title
            }
          }
        }
      `}
      render={data => <h1>test {element}</h1>}
    />
  );
};

@antoinerousseau Yep, I’m seeing the same thing. This is a pretty knarly bug I think.

At the moment if you want to initialize your providers with data from a StaticQuery you’re kind of stuck. The knock on effect from that is that there’s no simple/idiomatic way to share a single piece of static data globally across the application afaics.

Ok there are few things that need to be solved:

I ve got the same problem after many research it’s appear that you need to put the file where is located your staticquery in the folder ./src else you will get “Loading (StaticQuery)”

so what i did: in gatsby-ssr and gatsby-browser

var provider = require(`./src/inject-provider`)  
exports.wrapPageElement = provider.wrapPageElement

and in inject-provider.js (that you can use esmodule so import and so on) your layout with the static-query.

Certainly because babel compile only in src/*.js

WILL BE GREAT to add this in the DOC Thanks gatby

This was fixed in https://github.com/gatsbyjs/gatsby/pull/25723

Static queries should now just work in wrapRootElement or wrapPageElement

Upgrade to gatsby@2.24.13 and try it out! 🙂

The project that I need this for just got active again. Any news on a fix?

Fyi, I was able to get my <StaticQuery> working with wrapPageElement but not wrapRootElement. I’m using it to load i18n messages into react-intl’s <IntlProvider> in the root layout. But it might means that <IntlProvider> is re-mounting on each page change…

Hi all. I have that issue only in iframe. So it works in prod, but doesn’t work in develop. And works without iframe. I have added in gatsby-ssr

exports.wrapPageElement = ({element}) => {
  useMenuData()
  return element
}

where useMenuData has useStaticQuery Is it possible to useStaticQuery in iframe in develop?

I copy any components with queries from my local plugin directory to .cache/fragments/ during onPreExtractQueries. Gatsby picks these files up during query extraction which means your query fragments are ready to use. (We use this to dynamically create a fragment based on site metadata as well.)

@elskwid Could you share that code? We started a new project and are again having this issue.

Top-level wrappers are pretty much a standard in the React ecosystem. I’m surprised this issue has only so little traction.

We need a reasonable way to handle this as well. Passing providers on component level seems suboptimal at best.

Another workaround. I’m currently running all queries inside createPages and then saving all data I need available within providers as json files within static/global. Then in the providers I just import the data I need from that static directory.

Possibly related / helpful to someone: We’re importing a component using <StaticQuery> from gatsby-ssr.js. It fails silently on dev, but it’s fine on build.

Interestingly, switching from <StaticQuery> to the useStaticQuery() hook fails loudly on dev - but again is fine on build.

@coxom fwiw I’m using wrapPageElement and storing initialisation state to localStorage so that it only reloads on a new build, not on every page load or refresh. Not ideal but in my case I’m initialising a lot of data so it’s significantly improved performance until there’s a proper resolution to this issue.

@pieh I am using that workaround but for a production release it would be useful to have the code only load once and not on every page change.

@coxom this code is buried in a pretty complicated internal plugin at the moment. I should note that this process is only needed if you have a plugin or external library that needs to add fragments to the site. If you’re looking for a way to get general usage fragments in a more standard setup just let me know, we have a way we’re doing that too. 😉

Essentially, we have a file with GraphQL fragments in it (i.e. site-metdata-fragments.js):

import { graphql } from 'gatsby'

export const siteMetadataFields = graphql`
  fragment SiteMetadataFields on Site {
    siteMetadata {
    }
  }
`

Then, in gatsby-node.js we copy this file into the .cache folder using the onPreExtractQueries hook. Ours is more complicated but it’s basically a simple file copy from site-metadata-fragments.js go .cache/fragments/site-metadata-fragments.js.

By using this hook, the fragments are present when Gatsby extracts the queries, so you can use them in your app.

Does that give you enough to go on?

@krabbypattified and @TylerBarnes - I have been looking through the Gatsby source for a way to do this. I have a workaround 😄 (i.e. hacky abuse of the .cache) that seems to be working for me in development.

I copy any components with queries from my local plugin directory to .cache/fragments/ during onPreExtractQueries. Gatsby picks these files up during query extraction which means your query fragments are ready to use. (We use this to dynamically create a fragment based on site metadata as well.)