Use notion as CMS for Jekyll
Hi
Several days ago, I got familiar with Next.js and i wasn abale to create a blog using Vercel (mymoment.vercel.app) and I was curious how can I deploy it to cloudflare
After reading and raising questions, I realized that Cloudflare Pages is only a STATIC page host and I can’t use it like Vercel to deploy live Next.js site (after editing Notion, I have to redeploy the site)
On the other hand, I had a website based on Jekyll and I am more comfortable with Jekyll (its alos more developed, maybe because its used by Github Pages)
Afterward, I decided to look for a way to use Notion as CMS for Jekyll
Time wasted ☹️
Tea break
With my friends
Okay, I did it, but how…
a little different 😉
I found this blog post which was helpful
First I created a package.json
file in root directory. content:
1
2
3
4
5
6
7
8
9
10
11
{
"scripts": {
"start": "node notion.js"
},
"dependencies": {
"@notionhq/client": "^1.0.4",
"dotenv": "^16.0.1",
"notion-to-md": "^2.5.4"
},
"type": "module"
}
⚠️ remember to follow updates and change version number
then I created notion.js
in root directory as well. content: (updated on Aug 3th)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { Client } from '@notionhq/client'
import dotenv from 'dotenv'
import { NotionToMarkdown } from 'notion-to-md'
import * as fs from 'fs'
dotenv.config()
const notion = new Client({
auth: process.env.NOTION_TOKEN,
})
const response = await notion.databases.query({
database_id: process.env.NOTION_DATABASE_ID,
})
const n2m = new NotionToMarkdown({ notionClient: notion})
const kebabCase = str => str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.join('-')
.toLowerCase();
const pages = response
.results
.filter(x => x.properties.Name.title.length > 0)
pages.map(async x => {
const mdBlocks = await n2m.pageToMarkdown(x.id)
const content = n2m.toMarkdownString(mdBlocks)
const createdDate = x.created_time.split('T')[0]
//const createdTime = x.created_time
const publishTime = x.properties.Published.date.start
const topCategories = x.properties.TopCategory.select.name
const subCategories = x.properties.SubCategory.select.name
const mathCheck = x.properties.Math.checkbox
const mermaidCheck = x.properties.Mermaid.checkbox
const title = x.properties.Name.title[0].plain_text
const filename = kebabCase(title)
const tags = x.properties.Tags.multi_select
.map(x => ` - ${x.name}`)
.join('\n')
const pageContent =
`---
title: ${title}
date: ${publishTime}
tags:
${tags}
categories: [${topCategories}, ${subCategories}]
math: ${mathCheck}
mermaid: ${mermaidCheck}
---
${content}
`
fs.writeFile(`./_posts/${createdDate}-${filename}.md`, pageContent, (err) => {
console.log(err);
});
return
});
Updates:
- use
publishTime
instead oncreated_time
so the time can be modified by a property- use
topCategories
andsubCategories
to categorize posts (note that my theme support only one-step subcategory)- use
mathCheck
andmermaidCheck
to enable Math and Mermaid support in posts
And a notion.yml
in .github/workflows/notion.yml
content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Build Notion Posts
on:
schedule:
- cron: "*/30 * * * *"
# change branch based on your repository
push:
branches: [ "note" ]
pull_request:
branches: [ "note" ]
workflow_dispatch:
jobs:
build_posts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 15.x
- name: Run a multi-line script
run: |
touch .env
echo 'NOTION_TOKEN=$' >> .env
echo 'NOTION_DATABASE_ID=$' >> .env
yarn
yarn start
- uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: build pages from notion
👉
cron
set a period based on your preference
⚠️ create
NOTION_TOKEN
andNOTION_DATABASE_ID
in [ settings → Secrets → Actions ] and set their proper value ( I will explain )
and booom, its done
Token and ID
- Create a Notion Integration → https://developers.notion.com/docs/getting-started
Copy Internal Integration Token, Its your
NOTION_TOKEN
- Duplicate a template page https://notion.so/7875426197cf461698809def95960ebf
-
Extract database ID
Its your
NOTION_DATABASE_ID
1
2
https://www.notion.so/myworkspace/a8aec43384f447ed84390e8e42c2e089?v=...
|--------- Database ID --------|
Enjoy
Oh oh oh wait
I found jekyll-notion
which is more helpful and can handle the convertion faster with less steps :)
Personally, I think the npm script is better 🤨
But
jekyll-notion
is more compatible with Cloudflare Pages 🤔 Let’s say, you dont need to import Form Notion to Github and then push it to cloudflare
By jekyll-notion
Ruby add-ons, Notion database is imported during deployment (on Cloudflare)
Last stage
overall, I decided to use notion-to-md
(npm) package to import my notion to github.
Tweaks
- I use Github API to run Integration workflow and update
.md
files based on changed Notion block content.
Personal Advice:
- create another branch on you github repo and import
.md
files from Notion to that branch (using automated script and github action mentioned above)- After importing, Cloudflare starts redeploying.
- CF-Pages creates a subdomain with the name of that branch (e.g. import.alireza.pages.dev) and you can review deployment before pushing to main website 😉
- CF-Pages requires 2-5 min to deploy your website.
- I use Cloudflare Pages Hooks to update my website
Hope you enjoy it