whexy1999
NaaS: Notion-as-a-CMS

NaaS: Notion-as-a-CMS

Created
Dec 13, 2022 10:40 PM
Last edited time
Dec 13, 2022 11:34 PM
Tags
In the last post
🆕
Introduce: Dynamic Blogs
, I said that I’m redesigning the blog system to cut off the cost of publishing a new post. I decided to remove the concept of "publishing" from the system and sync my real-time input to the blog post page.
To achieve this goal, I need my blog system to be dynamic. My blog system uses Next.js for Server Side Rendering (SSR). Contents are rendered in the server behind the scene and then delivered to your browser. There are few calculations on the client side, so I can maintain a good performance.
Fortunately, SSR is also very suitable for dynamic data fetching. Many websites use the same technique to fetch raw content from the CMS, render it on the server, and then deliver the pages to the client.
💡
A content management system (CMS) is an application used to manage content, allowing multiple contributors to create, edit and publish. Content in a CMS is typically stored in a database and displayed in a presentation layer based on a set of templates like a website.

Next.js 13

Notion, but as a CMS

To make my blog system dynamic, I need to find a CMS. While I like the idea of GraphQL offered by many good CMSs, such as Sanity and Contentful, they haven’t provided a powerful rich formatting text feature as I used in regular blog posts.
Notion has many kinds of styles 🤯 and has an API to fetch a page or a block. That makes it a very suitable CMS. I found a great NPM module to fetch and render Notion page in React.
react-notion-x
NotionXUpdated Aug 31, 2023
Currently, there will be some bugs if you use it with Next.js 13, especially when you use the beta version of Layouts RFC. But I fixed them all. Here are some notes if you want to do the same thing.

Use react-notion-x with Next.js 13

  1. Use a wrapper class for NotionRenderer and declare it as a client component. NotionAPI can be a server component, which is good that all fetchings are done on the server side.
  1. PDF component won’t compile if you import it because node-canvas cannot work currently.
  1. Collection cannot be lazy imported but only imported directly.
  1. If you use Layouts RFC, contents will be statically rendered by default (and won’t update until you rebuild). Use the segment config to force it to be dynamic.
"use client"; import { NotionRenderer } from "react-notion-x"; import dynamic from "next/dynamic"; import Link from "next/link"; const Code = dynamic(() => import("react-notion-x/build/third-party/code").then(m => m.Code), ); import { Collection } from "react-notion-x/build/third-party/collection"; const Equation = dynamic(() => import("react-notion-x/build/third-party/equation").then( m => m.Equation, ), ); const Modal = dynamic( () => import("react-notion-x/build/third-party/modal").then( m => m.Modal, ), { ssr: false, }, ); type RenderProps = React.ComponentProps<typeof NotionRenderer>; export default function NotionClientRenderer(props: RenderProps) { return ( <NotionRenderer mapPageUrl={pageId => `/dyn/${pageId}`} components={{ Code, Collection, Equation, Modal, PageLink: ({ href, children }) => ( <Link href={href}>{children}</Link> ), }} {...props} /> ); }
example of my NotionRenderer wrapper class
import { NotionAPI } from "notion-client"; import NotionRenderer from "@/components/NotionClientRenderer"; const notion = new NotionAPI(); export const dynamic = "force-dynamic", revalidate = 0; export default async function Page() { const recordMap = await notion.getPage( "c7308a295d2b4a08929d8f6da207260c", ); return ( <NotionRenderer darkMode={false} fullPage={true} recordMap={recordMap} /> ); }
example of my page.js in this blog system
These two files provide the whole functionality of my dynamic blog system. Isn’t that easy?