Next.js + Contentlayer Example

Initial s/Commit/Post/g

This is the first post on this website and I already started trying to make it as not boring as possible.

If you are reading this post on the internet it means I successfully completed my first substantial(ish) front-end project.

It is based on:

  1. Next.js with App Router
  2. Contentlayer for MDX content
  3. Not yet using Tailwind CSS properly because believe it or not this is the third element in an ordered list (for real)

I mostly followed Contentlayer's excellent documentation with minor adjustments.

Since with MDX all posts are stored on the disk and not in a relational database I wanted to at least add ordering. So all my posts in are in the posts directory and are titled like "xxxx-actual-post-title" where xxxx is the post index starting from 0000 followed by the actual post slug/path/title.

These numbers are useful only for housekeeping purposes so to remove them from the URL I added a computed field slug to the Post document type, so I don't have to substring anything on the React side. And also adjusted the url computed field. Unfortunately, I couldn't use the slug inside the url computed field.

// contentlayer.config.ts

import { defineDocumentType, makeSource } from "contentlayer/source-files";

export const Post = defineDocumentType(() => ({
  name: "Post",
  filePathPattern: "**/*.mdx",
  fields: {
    title: { type: "string", required: true },
    createdOn: { type: "date", required: true },
  },
  computedFields: {
    slug: {
      type: "string",
      // Without first 5 symbols because name format is xxxx-post-url
      resolve: (post) => post._raw.flattenedPath.substring(5),
    },
    url: {
      type: "string",
      // Without first 5 symbols because name format is xxxx-post-url
      resolve: (post) => `/${post._raw.flattenedPath.substring(5)}`,
    },
  },
}));

export default makeSource({ contentDirPath: "posts", documentTypes: [Post] });

Also I replaced the date field with createdOn that feels like more descriptive name, since I plan to add a new updatedOn date field later.

I'm not including other files because changes are trivial and TypeScript will likely complain about problems in your editor.

What doesn't work (or I don't know how to check if it works yet):

  • akchyually using MDX. This is now processed as markdown despite having .mdx extension
  • using images
  • using lists (again, this is a list!)
  • link styling

If you see an image below, it means I figured out images.

The image:

 ,_     _
 |\\_,-~/
 / _  _ |    ,--.
(  @  @ )   / ,-'
 \  _T_/-._( (
 /         `. \
|         _  \ |
 \ \ ,  /      |
  || |-_\__   /
 ((_/`(____,-'

// From https://www.asciiart.eu/animals/cats

As a backend developer I really enjoyed the experience.

And now with this post published upgrading the stack further will be more meaningful because I will see how new features enhance this post. And future ones! Because I hope there will be more posts on this website than the median number of posts on the developers blogs.

TODO: speaking of meaningfulness, just slap here some random useless React Component to verify that MDX really works.