Gatsby: Is it possible to insert JSX into a page's HTML using onCreatePage?

Created on 8 Jul 2018  路  3Comments  路  Source: gatsbyjs/gatsby

Relevant information

I'm using Contentful as the source for pages and posts. For a single page, I would like to use something like onCreatePage to insert one or perhaps several React components into a certain point in the page's HTML. The insertion point is marked by an empty span with an ID. In order to use getElementByID and set its innerHTML, however, I need a way to get at the page's markup from onCreatePage's page object. Is that possible?

And while we're on the subject, it would be really cool if the onCreatePage documentation could be expanded.

File contents

Here's my current gatsby-config.js:

const path = require('path')

const pageTemplate = path.resolve('./src/templates/page.js')
const postTemplate = path.resolve('./src/templates/post.js')
const blogCategoryTemplate = path.resolve('./src/templates/blogCategory.js')

const contentfulQuery = contentType => `
  {
    content: allContentful${contentType} {
      edges {
        node {
          parent {
            id
          }
          slug
        }
      }
    }
  }
`

const pageSets = [
  { query: contentfulQuery(`Page`), component: pageTemplate },
  { query: contentfulQuery(`Post`), component: postTemplate },
  { query: contentfulQuery(`Category`), component: blogCategoryTemplate },
]

const pagePath = node => {
  switch (node.parent.id) {
    case `Post`:
      return `/blog/` + node.slug
    case `Category`:
      return `/blog/category/` + node.slug
    default:
      return node.slug
  }
}

exports.createPages = ({ graphql, boundActionCreators }) => {
  const { createPage } = boundActionCreators
  pageSets.forEach(async ({ query, component }) => {
    const response = await graphql(query)
    if (response.errors) {
      console.error(response.errors)
      throw new Error(response.errors)
    }
    response.data.content.edges.forEach(({ node }) => {
      createPage({
        path: pagePath(node),
        component,
        context: {
          slug: node.slug,
        },
      })
    })
  })
}
question or discussion

Most helpful comment

@m-allanson Thanks for the tip!

I tried the following

exports.onCreateNode = async ({ node, loadNodeContent }) => {
  if (node.path === `/standorte`) {
    console.log('node :', node)
    const nodeContent = await loadNodeContent(node)
    console.log('nodeContent :', nodeContent)
  }
}

which indeed gave me the expected node

node : { layout: 'index',
  jsonName: 'standorte.json',
  internalComponentName: 'ComponentStandorte',
  path: '/standorte',
  matchPath: undefined,
  component: '/Users/Janosh/Sites/sbs/src/templates/page.js',
  componentChunkName: 'component---src-templates-page-js',
  context: { slug: 'standorte' },
  pluginCreator___NODE: 'Plugin default-site-plugin',
  pluginCreatorId: 'Plugin default-site-plugin',
  componentPath: '/Users/Janosh/Sites/sbs/src/templates/page.js',
  id: 'SitePage /standorte',
  parent: 'SOURCE',
  children: [],
  internal:
   { type: 'SitePage',
     contentDigest: 'c7e186dbbf6979360b012ccb27679ff3',
     description: 'Your site\'s "gatsby-node.js"',
     owner: 'internal-data-bridge' } }

Problem is, once it reaches loadNodeContent, I get the error:

nodeContent : Promise {
  _bitField: 17825792,
  _fulfillmentHandler0:
   Error: Could not find function loadNodeContent for plugin internal-data-bridge
       at /Users/Janosh/Sites/sbs/node_modules/gatsby/dist/redux/index.js:141:15
       at Promise._execute (/Users/Janosh/Sites/sbs/node_modules/bluebird/js/release/debuggability.js:303:9)
...

Any advice on how to proceed would be great!

All 3 comments

You could do this using the onCreateNode API to add the new content to your Contentful nodes. This is typically how transformer plugins work. An example of this is the gatsby-transformer-remark which creates markdownRemark nodes from markdown files.

Check out the onCreateNode docs for a bit more info. A lot of the examples and plugins in this repo implement onCreateNode, which can be a handy reference.

PRs that improve any part of the docs are always very welcome! Particularly if you're working through an area and feel that there's some vital info missing.

@m-allanson Thanks for the tip!

I tried the following

exports.onCreateNode = async ({ node, loadNodeContent }) => {
  if (node.path === `/standorte`) {
    console.log('node :', node)
    const nodeContent = await loadNodeContent(node)
    console.log('nodeContent :', nodeContent)
  }
}

which indeed gave me the expected node

node : { layout: 'index',
  jsonName: 'standorte.json',
  internalComponentName: 'ComponentStandorte',
  path: '/standorte',
  matchPath: undefined,
  component: '/Users/Janosh/Sites/sbs/src/templates/page.js',
  componentChunkName: 'component---src-templates-page-js',
  context: { slug: 'standorte' },
  pluginCreator___NODE: 'Plugin default-site-plugin',
  pluginCreatorId: 'Plugin default-site-plugin',
  componentPath: '/Users/Janosh/Sites/sbs/src/templates/page.js',
  id: 'SitePage /standorte',
  parent: 'SOURCE',
  children: [],
  internal:
   { type: 'SitePage',
     contentDigest: 'c7e186dbbf6979360b012ccb27679ff3',
     description: 'Your site\'s "gatsby-node.js"',
     owner: 'internal-data-bridge' } }

Problem is, once it reaches loadNodeContent, I get the error:

nodeContent : Promise {
  _bitField: 17825792,
  _fulfillmentHandler0:
   Error: Could not find function loadNodeContent for plugin internal-data-bridge
       at /Users/Janosh/Sites/sbs/node_modules/gatsby/dist/redux/index.js:141:15
       at Promise._execute (/Users/Janosh/Sites/sbs/node_modules/bluebird/js/release/debuggability.js:303:9)
...

Any advice on how to proceed would be great!

Due to the high volume of issues, we're closing out older ones without recent activity. Please open a new issue if you need help!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hobochild picture hobochild  路  3Comments

rossPatton picture rossPatton  路  3Comments

Oppenheimer1 picture Oppenheimer1  路  3Comments

benstr picture benstr  路  3Comments

dustinhorton picture dustinhorton  路  3Comments