DEV Community

Vsevolod
Vsevolod

Posted on • Edited on

How to convert existing markdown blog to mdx

What is MDX? It's like "JSX in markdown". It lets you seamlessly write code in JSX in your markdown blog posts, for example.

Pros:

  • Declarative, more straightforward concept
  • Frontmatter and props support
  • All power of markdown with power of react components

Cons:

  • Non-informative error messages
  • Need to restart development server after each added/changed import component
  • Broken preview in vscode, github, gitlab(even with plugin)

Yes, it has some disadvantages. But nevertheless, I think mdx is the "new markdown". All these problems are temporary, and since it really cutting-edge technology, having all those problems are absolutely natural.
And if it's not production-ready yet, for personal blog or site it's absolute killer.

So, are you ready to discover future of tech blogging?

If you have no blog yet, just use gatsby-starter-blog-mdx, it has mdx support out of the box. Also you can check out official docs.

And for those who already have a blog and want to touch the awesomness of mdx, I will cover in details how to convert your markdown blog to mdx, let's go.

Check out files in this repo as an example

  1. Install all dependencies:
npm i gatsby-plugin-mdx @mdx-js/mdx @mdx-js/react
Enter fullscreen mode Exit fullscreen mode

Optionally, add eslint mdx plugin:

npm i -D eslint-plugin-mdx
Enter fullscreen mode Exit fullscreen mode
  1. Update Gatsby lifecycle files:

In gatsby-config, scroll to gatsby-transformer-remark, and replace:

gatsby-transformer-remark -> gatsby-plugin-mdx

plugins -> gatsbyRemarkPlugins

using following example:

module.exports = {
  plugins: [
      ...
          {
      // line below changed
      resolve: `gatsby-plugin-mdx`, 
      options: {
        // line below changed
        gatsbyRemarkPlugins: [ 
          ....
          `gatsby-remark-smartypants`,
        ],
      },
    },
  ]
}
Enter fullscreen mode Exit fullscreen mode

In gatsby-node, in GraphQL query replace "allMarkdownRemark" with "allMdx", and "MarkdownRemark" with "Mdx",
so it will look like this:

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  const blogPost = path.resolve(`./src/templates/blog-post.js`)
  const result = await graphql(
    `
      {
        allMdx(
          sort: { fields: [frontmatter___date], order: DESC }
          limit: 1000
        ) {
          edges {
            node {
                ...
 const posts = result.data.allMdx.edges
                ...

if (node.internal.type === `Mdx`) {
    const value = createFilePath({ node, getNode })
    ...
  }
...
Enter fullscreen mode Exit fullscreen mode
  1. Update post listing generation

In index.js(or where your posts listed), replace all "allMarkdownRemark" with "allMdx":

class BlogIndex extends React.Component {
  render() {
    const { data } = this.props
    const posts = data.allMdx.edges

    return (
      <Layout location={this.props.location}>
        <SEO title="All posts" />
        <Bio />
        {posts.map(({ node }) => {
          ...
        })}
      </Layout>
    )
  }
}

export default BlogIndex

export const pageQuery = graphql`
  query {
    allMdx(sort: { fields: [frontmatter___date], order: DESC }) {
      edges {
        ...
      }
    }
  }
`
Enter fullscreen mode Exit fullscreen mode
  1. Update blog post template

In your /src/templates/blog-post.js (or similar), you need to do following changes:

  • add import MDXRenderer
  • replace dangerouslySetInnerHTML with MDXRenderer
  • update query(change "markdown" to "mdx" and "html" to "body")
import { MDXRenderer } from 'gatsby-plugin-mdx';

class BlogPostTemplate extends React.Component {
  render() {
    const post = this.props.data.mdx
    return (
      <Layout title={post.frontmatter.title}>
        <ContentSection
          title={post.frontmatter.title}
          subtitle={post.frontmatter.date}
          color="white"
          size="medium"
        >
          <article>

            <MDXRenderer>{post.body}</MDXRenderer>

            ....
    )
  }
}
export default BlogPostTemplate

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    mdx(fields: { slug: { eq: $slug } }) {
      id
      excerpt(pruneLength: 160)
      body
      frontmatter {
      ...
      }
    }
  }
`
Enter fullscreen mode Exit fullscreen mode
  1. rename all your .md files to .mdx
  1. restart your development server:
gatsby develop
Enter fullscreen mode Exit fullscreen mode

So far we changed:

gatsby-config

gatsby-node

blog-post.js

index.js(page)

Congratulations! you now have working mdx blog. Stay tuned.

Check out our themes and articles about Gatsby and subscribe!

Top comments (2)

Collapse
 
nicco88 profile image
Nicco

Great introduction, thank you! :)

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt

Does it make easy to use custom components in Markdown? Like {% github name/repo no-readme %} ?