Gatsby: [v2] nodes being created not available on graphql queries

Created on 24 Jun 2018  路  3Comments  路  Source: gatsbyjs/gatsby

I couldn't find this issue anywhere else, so it might be that it's an implementation problem, but as I'm using v2 beta, I figured there's a good chance that this is a bug.

Description

I fetch data from an API on gatsby-node.js and create nodes for each object but they are only made available on graphQL at specific points, not allowing me to create pages from them.

Steps to reproduce

It seems a bit random, so I've shot them on video and put it on YouTube:

Expected result

As nodes are registered on "onCreatedNode", I'd expect to be able to access them on graphQL every time and be able to create pages from them.

Actual result

I can only query the created nodes' types at times, and never when I have the createdPages function working.

Environment

System:
    OS: Windows 10
    CPU: x64 Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz
  Binaries:
    Yarn: 1.4.0 - C:\Users\henri\AppData\Roaming\npm\yarn.CMD
    npm: 6.0.1 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: 42.17134.1.0
  npmPackages:
    gatsby: next => 2.0.0-beta.9
    gatsby-plugin-react-helmet: next => 3.0.0-beta.2
    gatsby-plugin-sass: next => 2.0.0-beta.2
    gatsby-plugin-styled-components: ^2.0.11 => 2.0.11
    gatsby-plugin-typescript: ^1.4.20 => 1.4.20
    gatsby-source-filesystem: ^1.5.39 => 1.5.39

File contents (if changed)

gatsby-config.js

module.exports = {
  siteMetadata: {
    title: 'Gororobas',
    description: 'Descubra uma receita vegetariana/vegana com o que voc锚 t锚m em casa!',
    siteUrl: 'https://gororobas.netlify.com',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-typescript',
    {
      resolve: 'gatsby-plugin-sass',
      options: {
        file: 'src/styles/main'
      }
    },
  ],
}

package.json

{
  "name": "gororobas",
  "description": "Gororobas",
  "version": "0.5.0",
  "author": "Henrique Cavalieri <[email protected]>",
  "dependencies": {
    "@sanity/block-content-to-react": "^1.3.9",
    "@sanity/client": "^0.132.2",
    "@sanity/image-url": "^0.132.2",
    "@types/react": "^16.4.1",
    "@types/react-dom": "^16.0.6",
    "@types/react-helmet": "^5.0.6",
    "@types/react-router": "^4.0.27",
    "babel-plugin-styled-components": "^1.5.1",
    "babel-plugin-transform-typescript": "^7.0.0-alpha.19",
    "gatsby": "next",
    "gatsby-plugin-react-helmet": "next",
    "gatsby-plugin-sass": "next",
    "gatsby-plugin-styled-components": "^2.0.11",
    "gatsby-plugin-typescript": "^1.4.20",
    "gatsby-source-filesystem": "^1.5.39",
    "node-sass": "^4.9.0",
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-helmet": "^5.2.0",
    "slugify": "^1.3.0",
    "styled-components": "^3.3.3"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "develop": "gatsby develop",
    "format": "prettier --write 'src/**/*.js'",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "devDependencies": {
    "prettier": "^1.12.0"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/gatsbyjs/gatsby-starter-default"
  }
}

gatsby-node.js


const crypto = require('crypto');
const path = require('path');
const slugify = require('slugify');
const sanityClient = require('@sanity/client');

const queries = require('./sanityQueries');

const Sanity = sanityClient({
  projectId: 'projectId', // not the real id
  dataset: 'production',
  useCdn: true,
});

exports.onPreBootstrap = async ({
  actions
}) => {
  const {
    createNode
  } = actions;

  const data = await Sanity.fetch(queries);

  console.log(data);

  data.recipes.forEach(recipe => {
    const {
      body,
      instructions,
      ingredients,
      meta: {
        title
      },
      info: {
        cookingTime,
        prepareTime,
        servings
      }
    } = recipe;

    // creates nodes on graphQL
    // reference: https://www.gatsbyjs.org/docs/bound-action-creators/#createNode
    createNode({
      title,
      body,
      instructions,
      ingredients,
      cookingTime,
      prepareTime,
      servings,
      created: recipe._createdAt,
      updated: recipe._updatedAt,
      slug: recipe.slug || slugify(title),

      // mandatory fields
      id: recipe._id,
      parent: null,
      children: [],
      internal: {
        type: 'Recipe',
        // Content digest is used for caching the node
        contentDigest: crypto
          .createHash(`md5`)
          .update(JSON.stringify(recipe))
          .digest(`hex`),
        description: title,
      }
    })
  });

  data.ingredients.forEach(ingredient => {
    const {
      name,
      price,
      description,
      icon
    } = ingredient;    

    createNode({
      name,
      price,
      description,
      icon,

      // mandatory fields
      id: ingredient._id,
      parent: null,
      children: [],
      internal: {
        type: 'Ingredient',
        contentDigest: crypto
          .createHash(`md5`)
          .update(JSON.stringify(ingredient))
          .digest(`hex`),
        description: name,
      }
    })
  });
}

exports.onCreateNode = ({ node }) => {
  if (node.internal.type === 'Recipe' || node.internal.type === 'Ingredient') {

    console.log('\n working \n', (node.name || node.title))
  }
}

exports.createPages = async ({ actions, graphql }) => {

  const data = await graphql(`
    {
      allSitePage {
        edges {
          node {
            id
          }
        }
      }
    }
  `);

  console.log(data);
}

gatsby-browser.js: N/A
gatsby-ssr.js: N/A

question or discussion

All 3 comments

Try changing exports.onPreBootstrap to exports.sourceNodes (which is where You should be creating nodes) - right now in v2 onPreBootstrap is run before cache is invalidated - so this may cause your nodes to simply be deleted

You're absolutely right, @pieh !! Thank you for the quick and precise answer <3

Just as a final question, when sourcing from an external API the best practice is to create a source plugin yourself?

PS: Feel free to close the issue! :D

Just as a final question, when sourcing from an external API the best practice is to create a source plugin yourself?

Yeah! You can either use an existing source plugin or create your own source plugin. You can create a local plugin if it's a one-off plugin just for your site.

There's some docs and a tutorial on creating source plugins if you want to give it a go.

If you see anything in the docs that could be improved, pull requests are always welcome.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dustinhorton picture dustinhorton  路  3Comments

rossPatton picture rossPatton  路  3Comments

kalinchernev picture kalinchernev  路  3Comments

andykais picture andykais  路  3Comments

mikestopcontinues picture mikestopcontinues  路  3Comments