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:
- The
__PATH_PREFIX__
variable was replaced by__BASE_PATH__
:
globals: {
- __PATH_PREFIX__: ''
+ __BASE_PATH__: ''
},
- 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'
- 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
- Delete the
netlify.toml
file. - Remove the entire
src/cms
directory. - Run
npm uninstall -S gatsby-plugin-netlify gatsby-plugin-netlify-cms netlify-cms-app
npm install -D @now/node
- 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');
}