Table of Contents

<--   Back

Contentlayer: Optimize getStaticProps on Next.js


TL:DR

Remove unnecessary data that doesn’t render on getStaticProps.

Why?

When you pass Contentlayer data to getStaticProps on Next.js, by default will include the raw markdown, which is redundant and bad for load speed.

import { allPosts, Post } from 'contentlayer/generated';
 
export async function getStaticProps() {
  const posts: Post[] = allPosts;
  return {
    props: {
      posts,
    }
  };
}

HTML result.

<script id="__NEXT_DATA__" type="application/json">
  {
    "props": {
      "pageProps": {
        "posts": [
          {
            "title": "Change me!",
            "date": "2022-03-11T00:00:00.000Z",
            "body": {
              "raw": "\nWhen you change a source file, Contentlayer automatically updates the content cache, which prompts Next.js to reload the content on screen.\n",
              "html": "<p>When you change a source file, Contentlayer automatically updates the content cache, which prompts Next.js to reload the content on screen.</p>"
            },
            "_id": "change-me.md",
            "_raw": {
              "sourceFilePath": "change-me.md",
              "sourceFileName": "change-me.md",
              "sourceFileDir": ".",
              "contentType": "markdown",
              "flattenedPath": "change-me"
            },
            "type": "Post",
            "url": "/posts/change-me"
          },
          {
            "title": "Click me!",
            "date": "2022-02-28T00:00:00.000Z",
            "body": {
              "raw": "\nBlog posts have their own pages. The content source is a markdown file, parsed to HTML by Contentlayer.\n",
              "html": "<p>Blog posts have their own pages. The content source is a markdown file, parsed to HTML by Contentlayer.</p>"
            },
            "_id": "click-me.md",
            "_raw": {
              "sourceFilePath": "click-me.md",
              "sourceFileName": "click-me.md",
              "sourceFileDir": ".",
              "contentType": "markdown",
              "flattenedPath": "click-me"
            },
            "type": "Post",
            "url": "/posts/click-me"
          },
          {
            "title": "What is Contentlayer?",
            "date": "2022-02-22T00:00:00.000Z",
            "body": {
              "raw": "\n**Contentlayer makes working with content easy.** It is a content preprocessor that validates and transforms your content into type-safe JSON you can easily import into your application.\n",
              "html": "<p><strong>Contentlayer makes working with content easy.</strong> It is a content preprocessor that validates and transforms your content into type-safe JSON you can easily import into your application.</p>"
            },
            "_id": "what-is-contentlayer.md",
            "_raw": {
              "sourceFilePath": "what-is-contentlayer.md",
              "sourceFileName": "what-is-contentlayer.md",
              "sourceFileDir": ".",
              "contentType": "markdown",
              "flattenedPath": "what-is-contentlayer"
            },
            "type": "Post",
            "url": "/posts/what-is-contentlayer"
          }
        ]
      },
      "__N_SSG": true
    },
    "page": "/",
    "query": {},
    "buildId": "lJqgQzHmHoKqCJDQ-Nldm",
    "isFallback": false,
    "gsp": true,
    "scriptLoader": []
  }
</script>

Optimizing

Clone data1 and remove unnecessary things.

import { allPosts, Post } from 'contentlayer/generated';
 
export async function getStaticProps() {
  const posts: Post[] = allPosts.map((post) => {
    const copy = structuredClone(post);
    copy.body.raw = "";
    copy._raw.sourceFilePath = "";
    copy._raw.sourceFileName = "";
    copy._raw.sourceFileDir = "";
    copy._raw.flattenedPath = "";
    return copy;
  });
  return {
    props: {
      posts,
    }
  };
}

Why Clone?

Contentlayer use single source of truth JSON, modifying data might causing race condition when you need one data on two place or more.

SSOT all allPosts list List Posts all->list page Post Page all->page list->all page->all

HTML result.

<script id="__NEXT_DATA__" type="application/json">
  {
    "props": {
      "pageProps": {
        "posts": [
          {
            "title": "Change me!",
            "date": "2022-03-11T00:00:00.000Z",
            "body": {
              "raw": "",
              "html": "<p>When you change a source file, Contentlayer automatically updates the content cache, which prompts Next.js to reload the content on screen.</p>"
            },
            "_id": "change-me.md",
            "_raw": {
              "sourceFilePath": "",
              "sourceFileName": "",
              "sourceFileDir": "",
              "contentType": "markdown",
              "flattenedPath": ""
            },
            "type": "Post",
            "url": "/posts/change-me"
          },
          {
            "title": "Click me!",
            "date": "2022-02-28T00:00:00.000Z",
            "body": {
              "raw": "",
              "html": "<p>Blog posts have their own pages. The content source is a markdown file, parsed to HTML by Contentlayer.</p>"
            },
            "_id": "click-me.md",
            "_raw": {
              "sourceFilePath": "",
              "sourceFileName": "",
              "sourceFileDir": "",
              "contentType": "markdown",
              "flattenedPath": ""
            },
            "type": "Post",
            "url": "/posts/click-me"
          },
          {
            "title": "What is Contentlayer?",
            "date": "2022-02-22T00:00:00.000Z",
            "body": {
              "raw": "",
              "html": "<p><strong>Contentlayer makes working with content easy.</strong> It is a content preprocessor that validates and transforms your content into type-safe JSON you can easily import into your application.</p>"
            },
            "_id": "what-is-contentlayer.md",
            "_raw": {
              "sourceFilePath": "",
              "sourceFileName": "",
              "sourceFileDir": "",
              "contentType": "markdown",
              "flattenedPath": ""
            },
            "type": "Post",
            "url": "/posts/what-is-contentlayer"
          }
        ]
      },
      "__N_SSG": true
    },
    "page": "/",
    "query": {},
    "buildId": "toHJpUjQDJpnE6IPRFO4s",
    "isFallback": false,
    "gsp": true,
    "scriptLoader": []
  }
</script>

Footnotes

  1. structuredClone() - Web APIs | MDN.


Open GitHub Discussions