Hellodan
Hellodan

Reputation: 1208

How do I use multiple createPage routes in gatsby-node.js

Im currently having an issue when using multiple createPage routes in gatsby-node.js. I am trying to use Gatsby js with Shopify commerce storefront & and another CMS for blog articles so I need a way of creating routes when viewing products and when viewing blog articles respectively.

Currently, I am experiencing an error that only appears when trying to view a product detail page that reads:

(EnsureResources, ) TypeError: Cannot read property 'page' of undefined

My gatsby-node.js currently looks like this

const path = require(`path`)

// Create product page urls
exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  return graphql(`
    {
      allShopifyProduct {
        edges {
          node {
            handle
          }
        }
      }
    }
  `).then(result => {
    result.data.allShopifyProduct.edges.forEach(({ node }) => {
        const id = node.handle
      createPage({
        path: `/product/${id}/`,
        component: path.resolve(`./src/templates/product-page.js`),
        context: {
            id,
        },
      })
    })
  })
}

// Create blog post slug urls
exports.createPages = async ({graphql, actions}) => {
  const {createPage} = actions
  const blogTemplate = path.resolve('./src/templates/blog.js')
  const res = await graphql (`
    query {
      allContentfulBlogPost {
        edges {
          node {
            slug
          }
        }
      }
    }
  `)

  res.data.allContentfulBlogPost.edges.forEach((edge) => {
    createPage ({
      component: blogTemplate,
      path: `/blog/${edge.node.slug}`,
      context: {
        slug: edge.node.slug
      }
    })
  })
}

Upvotes: 2

Views: 2338

Answers (1)

LekoArts
LekoArts

Reputation: 1569

You can't define the same API (createPages) twice. Do it in one function, especially since you can all put it into one query.

This code is obviously untested, but should work:

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

  const result = await graphql(`
    {
      shopify: allShopifyProduct {
        nodes {
          handle
        }
      }
      contentful: allContentfulBlogPost {
        nodes {
          slug
        }
      }
    }
  `)

  const shopifyTemplate = require.resolve(`./src/templates/product-page.js`)
  const contentfulTemplate = require.resolve('./src/templates/blog.js')

  if (result.errors) {
    return
  }

  result.data.shopify.nodes.forEach(product => {
    const id = product.handle

    createPage({
      path: `/product/${id}/`,
        component: shopifyTemplate,
        context: {
            id,
        },
    })
  })

  result.data.contentful.nodes.forEach(post => {
    createPage ({
      component: contentfulTemplate,
      path: `/blog/${post.slug}`,
      context: {
        slug: post.slug
      }
    })
  })
}

The nodes is a shortcut for edges.node and valid syntax. The shopify: is an alias before the name of the query. You don't need to use path, you can also use require.resolve. The async/await syntax is better to read IMO.

Upvotes: 9

Related Questions