Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
      }
    })
  })
}

like image 826
Hellodan Avatar asked Dec 14 '25 18:12

Hellodan


1 Answers

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.

like image 101
LekoArts Avatar answered Dec 18 '25 10:12

LekoArts



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!