gatsby build fails when StaticQuery has closing tag

Created on 25 Jun 2018  ·  20Comments  ·  Source: gatsbyjs/gatsby

Description

When I use <StaticQuery></StaticQuery>
gatsby build fails.
When I use <StaticQuery />, everything works.

Failure message:

Error: ./src/components/layout.js
  Module build failed (from ./node_modules/babel-loader/lib/index.js):
  TypeError: Cannot read property 'push' of undefined

This happens at the following location:
https://github.com/gatsbyjs/gatsby/blob/f41eb2a58d8a8d5e84663bb6a9080aa6b3d530df/packages/babel-plugin-remove-graphql-queries/src/index.js#L139

The value of path2.parent is:

Node {
  type: 'JSXClosingElement',
  start: 1095,
  end: 1109,
  loc:
   SourceLocation {
     start: Position { line: 38, column: 8 },
     end: Position { line: 38, column: 22 } },
  name:
   Node {
     type: 'JSXIdentifier',
     start: 1097,
     end: 1108,
     loc: SourceLocation { start: [Position], end: [Position] },
     name: 'StaticQuery' } }

Environment

System:
OS: Linux 4.13 Ubuntu 17.10 (Artful Aardvark)
CPU: x64 AMD A10-6700 APU with Radeon(tm) HD Graphics
Shell: 5.2 - /usr/bin/zsh
Binaries:
Node: 9.10.1 - /usr/local/bin/node
Yarn: 1.6.0 - /usr/local/bin/yarn
npm: 5.8.0 - /usr/local/bin/npm
Browsers:
Chrome: 65.0.3325.162
Firefox: 60.0.2
npmPackages:
gatsby: next => 2.0.0-beta.9
gatsby-plugin-react-helmet: next => 3.0.0-beta.2
gatsby-plugin-sharp: next => 2.0.0-beta.2
gatsby-plugin-typography: next => 2.2.0-beta.2
gatsby-remark-component: ^1.1.3 => 1.1.3
gatsby-remark-copy-linked-files: next => 2.0.0-beta.2
gatsby-remark-emojis: ^0.2.3 => 0.2.3
gatsby-remark-generic-extensions: ^0.0.1 => 0.0.1
gatsby-remark-images: next => 2.0.1-beta.3
gatsby-remark-smartypants: ^1.4.12 => 1.4.12
gatsby-source-filesystem: next => 2.0.1-beta.3
gatsby-transformer-remark: next => 2.1.1-beta.2

File contents (if changed)

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

help wanted bug

All 20 comments

Please post the relevant code where you use StaticQuery

Didn't work:

import React from 'react'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from "gatsby"
import Header from '../components/header'
import './layout.css'

export default ({ children }) => (
    <StaticQuery
      query={graphql`
  query SiteTitleQuery {
    site {
      siteMetadata {
        title
        description
        keywords
      }
    }
  }
      `}
      render={data=> (
          <>
            <Helmet
              title={data.site.siteMetadata.title}
              meta={[
                  { name: 'description', content: data.site.siteMetadata.description },
                  { name: 'keywords', content: data.site.siteMetadata.keywords },
              ]}
              >
              <link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/css/tachyons.min.css"/>
            </Helmet>
            <Header siteTitle={data.site.siteMetadata.title} />
            <div className="measure-wide center ph2">
              {children}
            </div>
          </>
      )}>
    </StaticQuery>
)

Worked:

import React from 'react'
import Helmet from 'react-helmet'
import { StaticQuery, graphql } from "gatsby"
import Header from '../components/header'
import './layout.css'

export default ({ children }) => (
    <StaticQuery
      query={graphql`
  query SiteTitleQuery {
    site {
      siteMetadata {
        title
        description
        keywords
      }
    }
  }
      `}
      render={data=> (
          <>
            <Helmet
              title={data.site.siteMetadata.title}
              meta={[
                  { name: 'description', content: data.site.siteMetadata.description },
                  { name: 'keywords', content: data.site.siteMetadata.keywords },
              ]}
              >
              <link rel="stylesheet" type="text/css" href="https://unpkg.com/[email protected]/css/tachyons.min.css"/>
            </Helmet>
            <Header siteTitle={data.site.siteMetadata.title} />
            <div className="measure-wide center ph2">
              {children}
            </div>
          </>
      )} />
)

Yeah, that won't work. render is the property of <StaticQuery /> and therefore it only needs a self-closing bracket. If you want to wrap your content you'll need to pass children to the component.
https://reactjs.org/docs/render-props.html#using-props-other-than-render

Because in your upper example you're writing <StaticQuery render={}></StaticQuery.
Do you have eslint enabled? Because this would give you an error telling you to either pass children to the component or use a /> instead.

i wonder if we can put in a warning when there is no self closing bracket.

i wonder if we can put in a warning when there is no self closing bracket.

That is what I was thinking. It was pretty confusing when I got the error, and required me to dig into the underlying js files to diagnose.

Do you have eslint enabled? Because this would give you an error telling you to either pass children to the component or use a /> instead.

^this

👍 to eslint.

I'm going to mark this as a bug also, Gatsby should either handle <StaticQuery></StaticQuery> or provide a more helpful error message when there's no self-closing bracket.

im interested to help fix this but i have no idea where to start. i vaguely know that it's in the query compiler. any specific place you would point me to?

@sw-yx You could probably start around here. To play around with ASTs this could help.
You will probably land here. Good luck!

awesome. yea I started messing around with astexplorer last night and have been on an ast learning spree for the past few days. I'm modding astexplorer so I can declaratively write out what I want the Before and After to look like and then it shows me the diff in the ASTs (unless it does that already and I don't know about it..?

Just wanted to add the following:

  • No eslint warnings are displayed.
  • This only seems to happen with gatsby build, not gatsby develop

This only seems to happen with gatsby build, not gatsby develop

this sounds very weird to me. it should work the same way both times. I also found a possibly related but when the graphql query is split up from the StaticQuery tag: https://swizec.com/blog/upgrading-gatsby-v2-hivemind/swizec/8481 this definitely happens in Gatsby develop

I have a bunch of personal things to take care of and am feeling a bit sick right now so just in case anyone wants to try fixing this, pls do

I just encountered this same issue, except in a slightly different variant. I saw that <StaticQuery> was using a render prop, so I figured that it would also accept children as a function like most other render prop components. This worked with gatsby develop, but broke on gatsby build. Moving the function into the render prop of a self-closing <StaticQuery/> component fixed this.

Same error. No warning when I try gatsby develop but throws error when done gatsby build

This is the error -

Error: ./src/components/layout.js
  Module build failed (from ./node_modules/babel-loader/lib/index.js):
  TypeError: Cannot read property 'push' of undefined

And this is my ./src/components/layout.js -

import React from "react";
import Helmet from "react-helmet";
import { StaticQuery, graphql, Link } from "gatsby";

const Layout = ({ children, data }) => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
  >
    {data => (
      <>
        <Helmet
          title={data.site.siteMetadata.title}
          meta={[
            { name: "description", content: "Sample" },
            { name: "keywords", content: "sample, something" }
          ]}
        />
        {children}
      </>
    )}
  </StaticQuery>
);

export default Layout;

But works if I use it by passing render as a prop like -

import React from "react";
import Helmet from "react-helmet";
import { StaticQuery, graphql, Link } from "gatsby";

const Layout = ({ children, data }) => (
  <StaticQuery
    query={graphql`
      query SiteTitleQuery {
        site {
          siteMetadata {
            title
          }
        }
      }
    `}
    render={data => (
      <>
        <Helmet
          title={data.site.siteMetadata.title}
          meta={[
            { name: "description", content: "Sample" },
            { name: "keywords", content: "sample, something" }
          ]}
        />
        {children}
      </>
    )}
  />
);

export default Layout;

I may be wrong @deadcoder0904 but I my understanding is that the StaticQuery component receives the data prop so you could remove the data in this line since it doesn't do anything.

const Layout = ({ children, data }) => (

The other components (Helment etc) can only access 'data' when they are rendered within StaticQuery because 'data' is passed as a prop to StaticQuery not Layout.

Sorry if that is a bad explanation, hopefully it still helps to clarify!

@joshdcuneo Yeah thanks. I actually copied v1 example I guess or just missed it Idk. Good catch :)

No dramas. I did the same a couple of days ago I'm pretty sure. :-D

Hi, I'm encountering the same issue. Using children props in <StaticQuery> will make the site fail when building (i.e. running gatsby build).

gatsby develop still works normally.

// this doesn't work...

const IndexLayout: React.SFC = ({ children }) => (
  <LayoutRoot>
    <StaticQuery
      query={graphql`
        query IndexLayoutQuery {
          site {
            siteMetadata {
              title
              description
            }
          }
        }
      `}
    >
      {(data: StaticQueryProps) => (
        <React.Fragment>
          <Helmet
            title={data.site.siteMetadata.title}
            meta={[
              { name: 'description', content: data.site.siteMetadata.description },
              { name: 'keywords', content: 'gatsbyjs, gatsby, javascript, sample, something' }
            ]}
          />
          <Header title={data.site.siteMetadata.title} />
        </React.Fragment>
      )}
    </StaticQuery>
    <LayoutMain>{children}</LayoutMain>
  </LayoutRoot>
)
// ...but this does

const IndexLayout: React.SFC = ({ children }) => (
  <LayoutRoot>
    <StaticQuery
      query={graphql`
        query IndexLayoutQuery {
          site {
            siteMetadata {
              title
              description
            }
          }
        }
      `}
      render={(data: StaticQueryProps) => (
        <React.Fragment>
          <Helmet
            title={data.site.siteMetadata.title}
            meta={[
              { name: 'description', content: data.site.siteMetadata.description },
              { name: 'keywords', content: 'gatsbyjs, gatsby, javascript, sample, something' }
            ]}
          />
          <Header title={data.site.siteMetadata.title} />
        </React.Fragment>
      )}
    />
    <LayoutMain>{children}</LayoutMain>
  </LayoutRoot>
)

I'm using TypeScript, not sure if that might be the problem.

I also have to add that replacing render with children, e.g. <StaticQuery query={...} children={...} /> also works. So I think it might have to do with the StaticQuery component being a self-closing element or not.

Was this page helpful?
0 / 5 - 0 ratings