I'm building a blog with Gatsby, I've made some progress but when I try to render mdx in my blog template, it doesn't render to anything.
I use createPages api, and everything works accordingly except this. When I wanted to use it gives an error 'Element type is invalid'. From my research, it is because its outdated with mdx v2?
This is the bit where I create pages and pass nodes
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const result = await graphql(
`
query AllQueries {
site {
siteMetadata {
title
}
}
allMdx(sort: {fields: [frontmatter___date], order: DESC}) {
nodes {
fields {
slug
}
excerpt
frontmatter {
date(formatString: "Do MMMM YYYY ")
title
description
}
body
}
}
}
`
)
const blogPostTemplate = path.resolve(`./src/templates/blog-post.js`)
const articles = result.data.allMdx.nodes
result.data.allMdx.nodes.forEach((node, index) => {
console.log('node', node)
createPage({
path: `/blog${node.fields.slug}`,
component: blogPostTemplate,
context: {
post: node,
prev: index == 0 ? null : articles[index -1],
next: articles.length -1 ? articles[index + 1] : null
},
})
})
I can get frontmatter, title, date etc. without any problems.
node [Object: null prototype] {
fields: [Object: null prototype] { slug: '/eighth-post' },
excerpt: 'Heading Level Two Some text\n\nHeading Level Three\n\nSome more text',
frontmatter: [Object: null prototype] {
date: '5th October 2022 ',
title: 'Eighth Post',
description: 'This article is the truth'
},
body: '\n' +
'\n' +
'\n' +
'## Heading Level Two\n' +
'\n' +
'Some text\n' +
'\n' +
'### Heading Level Three\n' +
'\n' +
'Some more text'
}
This is the example of a node that I'm getting. Thank you. This is the template I'm using to render posts.
import React from "react";
import { Link } from "gatsby";
import Layout from "../components/layout";
function BlogPost({ pageContext }) {
const { post } = pageContext
const prev = pageContext.prev
? {
url : `${pageContext.prev.fields.slug}`,
title : pageContext.prev.frontmatter.title
} : null
const next = pageContext.next
? {
url : pageContext.next.fields.slug,
title : pageContext.next.frontmatter.title
} : null
return (
<Layout>
<div className="card" key={post.fields.slug}>
<Link className="card-link" to={`.${post.fields.slug}`}>
<h2 className="card-title">{post.frontmatter.title}</h2>
</Link>
<p className="card-date">{post.frontmatter.date}</p>
<p className="card-description">{post.frontmatter.description}</p>
<p>{post.body}</p>
<nav>
{next &&
<Link to={`..${next.url}`} className="previous">
<span>< {next.title} </span>
</Link>
}
{prev &&
<Link to={`..${prev.url}`} className="next">
<span>{prev.title} ></span>
</Link>
}
</nav>
</div>
</Layout>
)
}
export default BlogPost
This is the gatsby-config file
module.exports = {
siteMetadata: {
title: `My Online Portfolio`,
description: `my home on the web`,
siteUrl: `https://evilsaint.cloud`,
social: {
twitter: `https://twitter.com/_EvilSaint_`
},
},
plugins: [
`gatsby-plugin-image`,
`gatsby-plugin-sitemap`,
`gatsby-plugin-mdx`,
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
{
resolve: 'gatsby-plugin-mdx',
options: {
extensions: [`.mdx`, `md`],
gatsbyRemarkPlugins: [
{
resolve: `gatsby-remark-highlight-code`,
options: {
terminal: "ubuntu",
},
},
],
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
"name": "images",
"path": "./src/images/"
},
__key: "images"
},
{
resolve: 'gatsby-source-filesystem',
options: {
"name": "pages",
"path": "./src/pages/"
},
__key: "pages"
},
{
resolve: `gatsby-transformer-remark`,
options: {
footnotes: true,
gfm: true,
plugins: [],
},
},
{
resolve: 'gatsby-source-filesystem',
options: {
"name": `blogs`,
"path": `${__dirname}/src/blog/`,
},
__key: "blogs"
},
'gatsby-transformer-remark',
]
};
The problem is that you are just rendering the body as is, as a plain text:
<p>{post.body}</p>
If you want to render the content as MDX you have two options:
Using the built-in plugin by Gatsby (see docs):
gatsby-transformer-remark
gatsby-config.js
:module.exports = {
plugins: [
{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown-pages`,
path: `${__dirname}/src/markdown-pages`,
},
},
`gatsby-transformer-remark`,
],
}
Important: add it below gatsby-source-filesystem
instance
dangerouslySetInnerHTML
to display the internal content. Change your current <p>
to:<p dangerouslySetInnerHTML={{ __html: post.body }}/>
Caveats: using dangerouslySetInnerHTML
you are potentially exposing your site as XSS (Cross-Site Scripting)
Use another library like markdown-to-jsx
(or similar)
import Markdown from 'markdown-to-jsx';
...
<Markdown options={{ wrapper: 'p' }}>{post.body}</Markdown>