Skip to content

MDX

Created: 2020-05-21 12:47:46 -0700 Modified: 2020-10-01 17:34:40 -0700

MDX is “JSX in Markdown”, and it’s what I’m using (at least for now) for blog posts on The AcAdamy. A blog post can then look like this


title: ‘Placeholder content’

date: ‘May 21st, 2020’

shortDescription: >

This is just about 100 characters of text. It’s like a small tweet.

thumbnail: ‘/blog/placeholder/thumbnail.png’

headerPicture: ‘/blog/placeholder/header_picture.png’

categories: [‘CATEGORY1’]

url: ‘/blog/foo’


import { EmailSignupInBlogPost } from ’../../components/EmailSignup’;

This is markdown.

<EmailSignupInBlogPost />

These are just quick instructions for how to do this. You should be able to figure this all out from the next-mdx-enhanced page.

.mdx-data

const nextEnv = require('next-env');
const withMdxEnhanced = require('next-mdx-enhanced');
const withPlugins = require('next-compose-plugins');
const withNextEnv = nextEnv();
const mdxEnhancedConfig = {
layoutPath: 'layouts',
defaultLayout: true,
fileExtensions: ['mdx'],
remarkPlugins: [],
rehypePlugins: [],
extendFrontMatter: {
process: (mdxContent, frontMatter) => {},
phase: 'prebuild|loader|both',
},
};
const nextConfiguration = {
// MORE OPTIONS GO HERE OF COURSE
poweredByHeader: false,
};
module.exports = withPlugins(
// https://github.com/hashicorp/next-mdx-enhanced/issues/18
[withMdxEnhanced(mdxEnhancedConfig), withNextEnv],
nextConfiguration
);
  • Use it
    • Make a layout in layouts/index.js

import React from “react”;

/* eslint-disable react/prop-types */
/* eslint-disable react/display-name */
export default function MDXLayout(frontMatter) {
const {title, description} = frontMatter;
return ({ children }) => {
return (
<div>
<div>{title} - {description}</div>
<div>Your JSX goes here</div>
<div>{children}</div>
</div>
);
};
}
  • Make the .mdx file from the Introduction section of this very note.
  • Iterate over all of your .mdx files using babel-plugin-import-glob-array
    • Make a .babelrc with these contents

{

“presets”: [“next/babel”],

“plugins”: [“import-glob-array”]

}

  • (no need to modify next.config.js for Babel here since you’re not modifying one of their built-=in plug-ins (reference))

  • Import all of your pages and render components from them

import React, { useState } from "react";
import { frontMatter as blogPosts } from "./blog/*.mdx";
function formatPath(p) {
return p.replace(/\mdx$/, "");
}
export default function Blog() {
return (
<div>
{_.map(blogPosts, (blogPost, index) => {
const { title, shortDescription, __resourcePath } = blogPost;
// You would use "href" in a <Link> below
const href = formatPath(__resourcePath);
return (
<div>
<div>{title}</div>
<div>{shortDescription}</div>
</div>
);
})}
</div>
);
}

When I start an MDX line with my own component (like “<TextLink href={blah}/>More text here”), no <p> tag is emitted. To fix this, I just manually surrounded that line with <p>TEXT</p>.

Module not found: Can’t resolve ‘.mdx-data/5b462b11952e6606145af3b6c04e59ba.json’ (reference)

Section titled Module not found: Can’t resolve ‘.mdx-data/5b462b11952e6606145af3b6c04e59ba.json’ (reference)

I did a few things here, but I don’t know exactly what fixed it:

  • Flush folder: rm -rf .next out .mdx-data
  • Run yarn
  • Try importing a specific .mdx file instead of using babel-plugin-import-glob-array to import *.mdx. I feel like this may have done it since I think I wasn’t generating the right JSON files otherwise.

Dollar sign gets escaped with a backslash

Section titled Dollar sign gets escaped with a backslash

See the Prettier note since this is a Prettier problem.