Adding additional context to a page is a supported part of
calling createPage
. This field is often used to pass a
simple identifying piece of information, like an id
or a
slug
, that can be used by a page template to fetch the
relevant information.
createPage({// Path for this page — requiredpath: `${edge.node.frontmatter.slug}`,component: blogPostTemplate,context: {// Add optional context data to be inserted// as props into the page component..//// The context data can also be used as// arguments to the page GraphQL query.//// The page "path" is always available as a GraphQL// argument.}});
However, when dealing with pages generated from src/pages
,
we don't have manual control of how the pages are
constructed: gatsby-plugin-page-creator
handles it for us.
In gatsby-mdx
we added support for generating pages from .mdx
files by
default.
Through adding support for .mdx
pages by default, we also
want to expose frontmatter defined in .mdx
files to the
page at runtime for use in rendering. To do that, we need to
hijack the page and modify the page context to add the
frontmatter.
In this case, we use the onCreatePage
lifecycle which
hands us every page that is created by Gatsby right after
it's created. If the extension is .mdx
, we do some
processing and then deep merge the frontmatter in with the
additional context so as to allow any pre-existing context
to still be passed through.
const path = require("path");const fs = require("fs-extra");const merge = require("lodash/merge");const defaultOptions = require("../utils/default-options");const extractExports = require("../utils/extract-exports");const mdx = require("../utils/mdx");module.exports = async ({ page, actions },pluginOptions) => {const { createPage, deletePage } = actions;const { extensions, ...options } = defaultOptions(pluginOptions);const ext = path.extname(page.component);// we test to see if frontmatter is created already because that's what// we're trying to insert and if we don't check we can end up in infinite loopsif (extensions.includes(ext) &&!page.context.frontmatter) {const content = await fs.readFile(page.component,"utf8");const code = await mdx(content, options);// grab the exported frontmatterconst { frontmatter } = extractExports(code);deletePage(page);createPage(merge({context: {frontmatter: {...frontmatter}}},page));}};
Another interesting note is that we check to see if the
frontmatter
is already set in the page context. This is to
prevent infinite loops that will occur if another plugin or
user re-creates the page.