All Articles

MDX and Vercel with gatsby starting lumen

Damian Schenkelman
Damian Schenkelman
2020-06-14
5 min read

The new blog

I had been meaning to start a new blog for a while. After some thinking I decided to use gatsbyjs, that I’d want mdx.js support and to host in on Vercel:

  • I decided on mdx was mostly because “it is new(ish) and I want to try it out”
  • The Vercel decision was mostly because I think it is a great service and I know a number of people that work there 😁

I looked at various Gastby templates until I caught one that caught my eye: gatsby-starter-lumen. I liked the base theme, its support for Google Analytics, Disqus comments, and mobile support. As someone that reads a lot on my phone I really, but also not a good UI developer, I really wanted my blog to be readable on mobile devices. Unfortunately, the template did not support mdx, it was built to deploy with Netlify. Thus, I decided to do adapt the starter to fit my needs.

Adding mdx support

I found this blog post on how to adapt the “Gatsby Starter Blog” to use MDX. After following the steps described there (which mostly involved search + replace) it took me a while to realize I needed to make some changes to the jest-config.js file:

  1. The __PATH_PREFIX__ variable was replaced by __BASE_PATH__:
globals: {
-    __PATH_PREFIX__: ''
+    __BASE_PATH__: ''
},
  1. I needed to transform .md and .mdx files:
   transform: {
-    '^.+\\.js?$': '<rootDir>/jest/jest-preprocess.js'
+    '^.+\\.js?$': '<rootDir>/jest/jest-preprocess.js',
+    '^.+\\.(md|mdx)$': 'jest-transformer-mdx'
  1. And I needed to ignore gatsby-plugin-mdx in the jest configuration:
   transformIgnorePatterns: [
-    'node_modules/(?!(gatsby)/)'
+    'node_modules/(?!(gatsby|gatsby-plugin-mdx)/)'

Only after having done all of that I actually found this blog post that dealt with many of these details 😅.

MDX demo

The great thing is that now I can add JSX in Markdownn 🚀. If I add this code:

<div><button>test</button></div>

A button renders:

Cool, right?

Removing netlify

  1. Delete the netlify.toml file.
  2. Remove the entire src/cms directory.
  3. Run
npm uninstall -S gatsby-plugin-netlify gatsby-plugin-netlify-cms netlify-cms-app
npm install -D @now/node
  1. Remove the Netlify plug-in from gatsby-config.js:
-    'gatsby-plugin-netlify',
-    {
-      resolve: 'gatsby-plugin-netlify-cms',
-      options: {
-        modulePath: `${__dirname}/src/cms/index.js`,
-      }
-    },

Adding Vercel support

Setting up Vercel is trivial (which is why I ❤️ it so much). Run now and confirm that you want to deploy the current directory:

➜  blog git:(master) ✗ now
Now CLI 19.1.0
? Set up and deploy “~/Documents/github/blog”? [Y/n] y

Pick your scope (in my case I was already logged in):

➜  blog git:(master) ✗ now
Now CLI 19.1.0
? Set up and deploy “~/Documents/github/blog”? [Y/n] y
? Which scope do you want to deploy to? 
● Damian Schenkelman 

Because the current directory is named “blog” I was asked if I want to link my current repository with that project. The .vercel folder was also created and added to my .gitignore file automatically:

? Found project “damianschenkelman/blog”. Link to it? [Y/n] y
🔗  Linked to damianschenkelman/blog (created .vercel)

After a minute or so the deploy finished. That’s it 😱:

➜  blog git:(master) ✗ now
Now CLI 19.1.0
? Set up and deploy “~/Documents/github/blog”? [Y/n] y
? Which scope do you want to deploy to? Damian Schenkelman
? Found project “damianschenkelman/blog”. Link to it? [Y/n] y
🔗  Linked to damianschenkelman/blog (created .vercel)
🔍  Inspect: https://vercel.com/damianschenkelman/blog/35v6x3zvc [8s]
✅  Preview: https://blog.damianschenkelman.vercel.app [copied to clipboard] [1m]
📝  To deploy to production (blog-alpha-rose.vercel.app), run `vercel --prod`

Vercel + Github integration

I also set up the Vercel for Github integration so pushing to GitHub automatically updates the blog. To do that I only signed in to my Vercel dashboard and clicked Import project.

Then click Continue to import a Git repository:

Type in the URL of the Git repository and click Continue.

That’s it!

Appendix: Fixing the jest snapshot tests

The original gatsby-starter-lumen has some Jest snapshot tests. For example, the Content.test.js file has this contents at the time of writing:

// @flow strict
import React from 'react';
import renderer from 'react-test-renderer';
import Content from './Content';

describe('Content', () => {
  it('renders correctly', () => {
    const props = {
      title: 'test',
      body: '<p>test</p>'
    };

    const tree = renderer.create(<Content {...props} />).toJSON();
    expect(tree).toMatchSnapshot();
  });
});

Fixing the tests is not required to get the blog to work, but I don’t like changing code and breaking tests :). To support mdx, the body needs to be “wrapped”:

// @flow strict
import React from 'react';
import renderer from 'react-test-renderer';
import Content from './Content';
import prepareMdx from '../../../utils/prepareMdx';

describe('Content', () => {
  it('renders correctly', async () => {
    const body = await prepareMdx('<p>test</p>');

    const props = {
      title: 'test',
      body
    };

    const tree = renderer.create(<Content {...props} />).toJSON();
    expect(tree).toMatchSnapshot();
  });
});

And this is what prepareMdx.js looks like:

// @flow strict
import mdx from '@mdx-js/mdx';
import { transform } from '@babel/core';

const transpile = async (content) => {
  const jsx = await mdx(content);
  return jsx;
};

export default async function prepareMdx(body: string) {
  return transform(await transpile(body), {
    configFile: false,
    plugins: [
      '@babel/plugin-transform-react-jsx',
      '@babel/plugin-syntax-object-rest-spread',
    ],
    presets: [
      require('@babel/preset-react'),
      [
        require('@babel/preset-env'),
        {
          useBuiltIns: 'entry',
          corejs: 2,
          modules: false,
        },
      ],
    ],
  }).code.replace('export default function', 'return function');
}