Using Contentlayer with Next.js
I've just added a new section to this blog — Today I Learned notes. With that, I'm writing down a few other things I've changed around, and how it works together.
Contentlayer in a statically generated site
First off, Contentlayer. It simplified things quite a lot. If I had half a brain left back when I started the blog, and used 11ty instead of the monstrocity that Next.js is, Contentlayer would be an overkill. But with Next.js, you don't get the automatic pipeline that grabs all of your markdown files and renders them — you build that pipeline yourself.
And that generation pipeline generally consists of a few stages:
- Read the source files, populate and compute their fields based on
frontmatter or whatever custom logic you want, and define your types. For
me, that was a
lib/posts.ts
that has just a handful of functions and made sure thatPost.created
is actually a date. - Configure and setup a way to process markdown. That would likely involve
MDX
ornext-mdx-remote
or something similar. Not too complex, but that's just boilerplate code. Would be cool if you didn't have to write boilerplate, huh? - Rendering your content within the site URL structure — Next.js makes that relatively straightforward.
Coming from the world of OG backend web frameworks (Wait, is Rails and Symphony OG?), Contentlayer looks similar to what you'd call an ORM, except it's not exactly a relational mapper. You could say it's an Object Markdown Mapper questionmark.
Anyway, Contentlayer allows you to specify what fields (and types) your markdown
sources have, and then it will generate the types and objects for you, including
a nice allPosts()
or allPages()
or allWhateverYourTypeIs()
that fetches
them. The only thing left for you to write is a function that grabs your
processed content and sorts it.
Here it is in this blog's repository.
To get all that, you specify your source data type and fields in a
contentlayer.config.ts
file:
It also works well with MDX, and that comes in two pieces. First, you tell
Contentlayer that you're actually about to render some MDX, and specify what
plugins you want to use in remark
and rehype
:
And then you render your content with a component that Contentlayer makes for
you in getMDXComponent
:
Adding multiple source types to your Contentlayer configuration
So what if you want multiple types of posts, with different fields? Well, you
defineDocumentType
several times, but then your contentlayer.config.ts
starts to cause pain comparable to package.json
. So as any sane person who
dealt with an ORM before, you split it into the config itself, and the data
definition files that you can tuck away in lib
, like this:
Here's the commit with that split for respawn.io.
And here's the
full contentlayer.config.ts
— that now defines wikilinks, some other formatting, and uses rehypePrettyCode
for code blocks. At the time of this writing, 38 lines of code to bootstrap all
of that.
I think I've played with Next.js for a little bit too long, so I'm no longer
sure if that's actually neat, or if that's way too much. But after tinkering
with next-mdx-remote
and friends, I'd say 38 lines for the whole mdx
conversion configuration is pretty cool.
Links
- Here's the original Hello, World! post for this blog.
- Read more on Contentlayer
- More on Rehype Pretty Code code highlighting — the best and most flexible I've tried so far.
- Today I learned — a pile of short notes on how I broke things that day.