MDXRenderer is not working #34714
-
Preliminary Checks
DescriptionI am sorry that my English is so bad I want to display mdx's body with src/templates/blog-post.js import * as React from "react"
import { Link, graphql } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import Bio from "../components/bio"
import Layout from "../components/layout"
import Seo from "../components/seo"
const BlogPostTemplate = ({ data, location }) => {
const post = data.mdx
const siteTitle = data.site.siteMetadata?.title || `Title`
const { previous, next } = data
return (
<Layout location={location} title={siteTitle}>
<Seo
title={post.frontmatter.title}
description={post.frontmatter.description || post.excerpt}
/>
<article
className="blog-post"
itemScope
itemType="http://schema.org/Article"
>
<header>
<h1 itemProp="headline">{post.frontmatter.title}</h1>
<p>{post.frontmatter.date}</p>
</header>
<MDXRenderer>{post.excerpt}</MDXRenderer>
<hr />
<footer>
<Bio />
</footer>
</article>
<nav className="blog-post-nav">
<ul
style={{
display: `flex`,
flexWrap: `wrap`,
justifyContent: `space-between`,
listStyle: `none`,
padding: 0,
}}
>
<li>
{previous && (
<Link to={previous.fields.slug} rel="prev">
← {previous.frontmatter.title}
</Link>
)}
</li>
<li>
{next && (
<Link to={next.fields.slug} rel="next">
{next.frontmatter.title} →
</Link>
)}
</li>
</ul>
</nav>
</Layout>
)
}
export default BlogPostTemplate
export const pageQuery = graphql`
query BlogPostBySlug(
$id: String!
$previousPostId: String
$nextPostId: String
) {
site {
siteMetadata {
title
}
}
mdx(id: { eq: $id }) {
id
excerpt(pruneLength: 160)
body
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
description
}
}
previous: markdownRemark(id: { eq: $previousPostId }) {
fields {
slug
}
frontmatter {
title
}
}
next: markdownRemark(id: { eq: $nextPostId }) {
fields {
slug
}
frontmatter {
title
}
}
}
`
{
"name": "gatsby-starter-blog",
"private": true,
"description": "A starter for a blog powered by Gatsby and Markdown",
"version": "0.1.0",
"author": "Kyle Mathews <[email protected]>",
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
},
"dependencies": {
"@babel/runtime": "^7.16.0",
"@mdx-js/mdx": "^2.0.0-next.9",
"@mdx-js/react": "^2.0.0",
"gatsby": "^4.6.0",
"gatsby-plugin-feed-mdx": "^1.1.0",
"gatsby-plugin-gatsby-cloud": "^4.6.0",
"gatsby-plugin-google-analytics": "^4.6.0",
"gatsby-plugin-image": "^2.6.0",
"gatsby-plugin-manifest": "^4.6.0",
"gatsby-plugin-mdx": "^3.5.0",
"gatsby-plugin-offline": "^5.6.0",
"gatsby-plugin-react-helmet": "^5.6.0",
"gatsby-plugin-sharp": "^4.6.0",
"gatsby-remark-copy-linked-files": "^5.6.0",
"gatsby-remark-images": "^6.6.0",
"gatsby-remark-prismjs": "^6.6.0",
"gatsby-remark-responsive-iframe": "^5.6.0",
"gatsby-remark-smartypants": "^5.6.0",
"gatsby-source-filesystem": "^4.6.0",
"gatsby-transformer-sharp": "^4.6.0",
"prismjs": "^1.25.0",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-helmet": "^6.1.0",
"typeface-merriweather": "0.0.72",
"typeface-montserrat": "0.0.75"
},
"devDependencies": {
"prettier": "^2.5.1"
},
"homepage": "https://github.com/gatsbyjs/gatsby-starter-blog#readme",
"keywords": [
"gatsby"
],
"license": "0BSD",
"main": "n/a",
"repository": {
"type": "git",
"url": "git+https://github.com/gatsbyjs/gatsby-starter-blog.git"
},
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,md}\"",
"start": "gatsby develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
}
}
Reproduction LinkSteps to ReproduceI followed this mdx convert guide Expected ResultDisplaying mdx's body with MDXRenderer Actual ResultUnhandled Runtime Error occured EnvironmentSystem:
OS: MacOS monterey
CPU: 2 GHz クアッドコアIntel Core i5
npmPackages:
"@mdx-js/mdx": "^2.0.0-next.9",
"@mdx-js/react": "^2.0.0",
"gatsby": "^4.6.0",
"gatsby-source-filesystem": "^4.6.0",
"gatsby-plugin-mdx": "^3.5.0", Config FlagsNo response |
Beta Was this translation helpful? Give feedback.
Replies: 13 comments 20 replies
-
My MDXRenderer doesn't work too!!! |
Beta Was this translation helpful? Give feedback.
-
You need to use v1 of |
Beta Was this translation helpful? Give feedback.
-
Another question is how do I actually get these "children" as props in my component? I'm not new to the Gatsby framework, and I still can't figure this example out. Please, clarify a bit. |
Beta Was this translation helpful? Give feedback.
-
I end up by using Here my example of a resolver: const remarkGfm = require('remark-gfm');
/**
* Resolver to compile MDX string to JSX string
*/
const compileMDXResolver = {
type: `DescriptionBody`,
async resolve(node, args, context, info) {
const result = await compileMDXWithCustomOptions(
{
source: node.description,
absolutePath: __dirname + '/src/pages/events/list/index.mdx',
},
{
pluginOptions: {
plugins: []
},
customOptions: {
mdxOptions : {
outputFormat: 'function-body',
jsxRuntime: 'automatic',
jsx: false,
useDynamicImport: true,
remarkPlugins: [
remarkGfm,
],
}
},
getNode,
getNodesByType,
pathPrefix,
reporter,
cache,
store,
}
)
return { value: result.processedMDX.toString() }
}
} And the React component: import React from 'react'
import { useState, useEffect, Fragment } from 'react'
import * as runtime from 'react/jsx-runtime'
import {MDXProvider, useMDXComponents} from "@mdx-js/react"
import PropTypes from 'prop-types';
import { run } from '@mdx-js/mdx'
export default function MyMDX({code}) {
const [mdxModule, setMdxModule] = useState()
const Content = mdxModule ? mdxModule.default : Fragment
useEffect(() => {
;(async () => {
setMdxModule(await run(code, {...runtime, useMDXComponents}))
})()
}, [code])
return (
<Content />
)
}
MyMDX.propTypes = {
code: PropTypes.string,
}
MyMDX.defaultProps = {
code: '',
} Then I use the provider: import { MDXProvider } from "@mdx-js/react"
....
<.....>
<MDXProvider>
{children}
</MDXProvider>
</....> |
Beta Was this translation helpful? Give feedback.
-
Hello @NazAnton I tried what you suggested above, but then I'm only getting the value back as a parsed string, this is what my code looks like:
After setting the mdx value to state, I then render its value on the UI like this:
Unfortunately, what I get rendered back is the string, is there a way to render the component itself after compiling? |
Beta Was this translation helpful? Give feedback.
-
Handling MDX rendering without MDXRendererGeneralHere is my report. I solved all the MDX issues with the new "gatsby-plugin-mdx" v4 breaking changes approach. But before I show the updated approach, I'll show how I did things with "gatsby-plugin-mdx" v3 to compare the two approaches. *All of the code snippets below are very generic. They are only shown as illustrations to accompany my explanations to make it easier for you to understand how things work. Don't mindlessly copy them into your project. Initial approach v3At the Node layer.I queried the required .mdx file. Then extract a At the Client layer.In the template component I get the Code v3Query data for article.mdx files
Page creation phase
Articles Template Component
New approach v4+At the Node layer.I queried the required .mdx file. Then extract not a At the Client layer.In the template component I get the Code v4Query data for article.mdx files
No more Page creation phase
No This is where the magic happens. More on that here. Articles Template Component
After ConclusionI should note that I wasn't very careful when reading the v3 to v4 migration guide and literally missed the query string trick. But when I carefully studied the documentation, everything became clear. Another thing to note is that the migration is worth 20 minutes of work if you have an approach like mine and build pages programmatically. A few changes to the GraphQL query, a few to the |
Beta Was this translation helpful? Give feedback.
-
Compiling MDX by yourself without "gatsby-plugin-mdx"GeneralHi @jideabdqudus, If you're only using one .mdx file per template, the above guide will satisfy your needs perfectly, and the following solution will be redundant for you. But I, for instance, use multiple .mdx files per template, then you might find something useful here. For ease of further explanation, let's say article.mdx is the main content on a page and excerpt.mdx is the short description of it, somewhere at the top of the page. Since the new approach does not allow you to provide multiple .mdx files to this special query string, you will have to handle the additional .mdx content yourself. The Gatsby is using external tools to process MDX content. Specifically, the MDX-JS project that provides all the tools. So, why not use these tools directly in the project yourself, without using "gatsby-plugin-mdx" at all? But first, more about my excerpt.mdx file. In my project, it is full fledged MDX with custom tags and MDX syntax. Simple plain text doesn't meet the needs of my project, so I literally need to have multiple MDX files to render a single page. There is one major difference compared to my article.mdx files - I have no imports in the excerpt.mdx files. I'm not saying that a home-brewed MDX compilation won't work with imports, but I am saying that I haven't tried this approach yet with .mdx files that contain import expressions. So it's good to know before experimenting with *All of the code snippets below are very generic. They are only shown as illustrations to accompany my explanations to make it easier for you to understand how things work. Don't mindlessly copy them into your project. Query data for excerpt.mdx files
Page creation phase
The For simplicity, I don't show the code related to article.mdx here, but in practice I use the Gatsby-way shown above. That is, I have a mixed approach. I'm also intentionally not showing you how I Articles Template Component
Note, that I do not use here not only "gatsby-plugin-mdx", but ConclusionDoes this mean you can do not use Gatsby's solution at all to handle MDX content? It seems so. But I still prefer to use "gatsby-plugin-mdx" whenever possible so that my own code is cleaner and not cluttered with my own versions of solutions when there is no need for it and when the same functionality is already provided by ready-made plugins/ packages. |
Beta Was this translation helpful? Give feedback.
-
@jideabdqudus I would be happy too and very thankful about an easy and working example to solve using mdx in gatsby v5 |
Beta Was this translation helpful? Give feedback.
-
I've been working on a project where I'm querying MDX files in my Gatsby project. I was struggling with rendering the MDX body without the V3 render method. I saw this discussion and still wan't able to figure it out, so I wanted to post my solution, incase it's helpful to anyone still struggling with this. I'm using synchronous methods here, passing the raw MDX body from from graphQL query to the I'm not sure about using this as it calls eval(), but I was thinking that since this is compiled by Gatsby on a static site I wouldn't have too many issues. Open to thoughts on this though.
|
Beta Was this translation helpful? Give feedback.
-
Solution worked with gatsby-plugin-mdx version 5.7.0Here is my solution, worked like a charm. I had a very emotional moment when it finally worked after so many hours trying so many different things. I just wanted to hit my head against the wall but I'm glad I didn't lol. Hope this can be helpful to someone. My issueI have 1 template and multiple mdx files. Wanted to use the template to create multiple pages and want to generate the content into HTML straight from mdx files. Checked all of the documents and solutions but I couldn't understand how this
becomes this
I tried changing
Detailed implementationAs mentioned by jessapp above, the
Here is my detailed solution (Note that names and paths are random so please change them according to your own project) gatsby-node.js
your-template.jsx
gatsby-config.js
|
Beta Was this translation helpful? Give feedback.
-
I just upgraded to V5 as well, And I also used My project uses the
Each mdx file uses the The query function in the template file is as follows:
If I use |
Beta Was this translation helpful? Give feedback.
-
what if you want to render the body as jsx on allMdx and in for example a list view and not only on the separate single page for the post? |
Beta Was this translation helpful? Give feedback.
-
Hey @LekoArts, I'm exploring ways to swap out MDXRenderer within a component. While I've got the hang of generating pages with templates using createPage, I occasionally find myself wanting to render the body of certain MDX files directly within components. Any suggestions or insights on how to accomplish this? |
Beta Was this translation helpful? Give feedback.
You need to use v1 of
@mdx-js/mdx
and@mdx-js/react
(vianpm install @mdx-js/mdx@v1 @mdx-js/react@v1
) untilgatsby-plugin-mdx
is compatible with v2