Programmatically Creating Pages

Pages can be created programmatically by combining a source plugin in gatsby-config.js with some createPage calls in gatsby-node.js. For example, using gatsby-source-filesystem we can point to a folder of MDX files and name the collection "posts".

// gatsby-config.js
module.exports = {
plugins: [
`gatsby-mdx`,
{
resolve: "gatsby-source-filesystem",
options: {
name: "posts",
path: `${__dirname}/content/`
}
}
]
};

Then, we can query the GraphQL schema for our MDX content and create pages from it. Creating pages from MDX content requires us to manipulate the scope of the MDX file.

// gatsby-node.js
const componentWithMDXScope = require("gatsby-mdx/component-with-mdx-scope");
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions;
return new Promise((resolve, reject) => {
resolve(
graphql(
`
{
allMdx {
edges {
node {
id
parent {
... on File {
name
sourceInstanceName
}
}
code {
scope
}
}
}
}
}
`
).then(result => {
if (result.errors) {
console.log(result.errors);
reject(result.errors);
}
// Create blog posts pages.
result.data.allMdx.edges.forEach(({ node }) => {
createPage({
path: `/${node.parent.sourceInstanceName}/${node.parent.name}`,
component: componentWithMDXScope(
path.resolve("./src/components/posts-page-layout.js"),
node.code.scope
),
context: { id: node.id }
});
});
})
);
});
};
// posts-page-layout.js
import React from "react";
import { graphql } from "gatsby";
import MDXRenderer from "gatsby-mdx/mdx-renderer";
import { withMDXScope } from "gatsby-mdx/context";
function PostPageTemplate({ data: { mdx } }) {
return <MDXRenderer>{mdx.code.body}</MDXRenderer>;
}
default PostPageTemplate;
const pageQuery = graphql`
query($id: String!) {
mdx(id: { eq: $id }) {
id
code {
body
}
}
}
`;

You can also provide your own scope when rendering using MDXRenderer. By default this will override the automatically generated scope, so to add additional imports to the scope use the context tools.

# My Video
Check out my awesome video:
<YouTube v="UgDDHi-_fyY" />

Using the withMDXScope HOC

// posts-page-layout.js
import React from "react";
import { graphql } from "gatsby";
import MDXRenderer from "gatsby-mdx/mdx-renderer";
import { withMDXScope } from "gatsby-mdx/context";
import YouTube from "react-youtube";
function PostPageTemplate({ data: { mdx }, scope }) {
return (
<MDXRenderer scope={{ YouTube, ...scope }}>{mdx.code.body}</MDXRenderer>
);
}
default withMDXScope(PostPageTemplate);
const pageQuery = graphql`
query($id: String!) {
mdx(id: { eq: $id }) {
id
code {
body
}
}
}
`;