用 Notion API 打造 Gatsby.js Blog

7 min read

# tech

由於原先在 Local 端搭配 Markdown 來進行編輯部署的方式讓寫作這件事有些麻煩,於是希望可以有個 CMS 工具管理自己的文章,以便調整一些 meta 資訊,主要嘗試了 Ghost 與 Notion API 這兩種方案,最終決定使用 Notion API。

以下分享關於 Source Notion API Plugin 的一些使用心得。

Ghost & Rehype

Ghost 是一個知名的 CMS 服務,一開始選擇使用 Ghost 是因為編輯器的使用體驗良好,串接過程搭配 Digital Ocean(目前的一鍵部署有 Node 版本的問題,可以參考手動教學),並且使用 Gatsby 的 ghost-source-plugin,整體都還算好上手,但有兩個問題讓我猶豫不決:

  1. 串接 Ghost 需要將資料庫架在另外一台伺服器上,需要一筆主機費用
  2. Ghost API 只支援回傳 Plain Text 或 HTML 而非 Markdown String

前者還算可以接受,但後者這讓 Gatsby 在轉換資源上難以搭配寫好的 Prism 樣式、跟圖片大小調整等等全都變得不支援。

這時候就必須仰賴 Rehype 相關的 Plugin 來幫我們判斷 HTML Tag 進行樣式的轉換,目前實測上 gatsby-rehype-prismjs 能成功使用,但 gatsby-rehype-inline-image 持續出現不知名的 bug,最後決定開始找別的解決方案。

Notion API

很巧的是,最近開始關注到 Notion API 開放的消息,也看到很多將 Notion 部署成網站的解決方案,像是 Superb, Potion 等服務,於是我就在想,難道不能直接將 Notion API 對接 Gatsby 來當作部落格後台嗎?

於是搜尋了 Plugin 發現果然有相關的 Plugin - gatsby-source-notion-api,使用的方式非常簡單,只要在 gatsby-config.js 裡面新增你的 Developer Key 跟 DB id 即可取得相關資源。

於是我們可以先到 Notion Setting 裡面申請 Create Integration:

接著可以看到需要填寫一些關於 Integration 的基本資料:

並選擇使用情境,複製下 Token:

最後到對應的 DB 開啟 Share 分享權限給自用的 Integration:

這樣就可以取得資料了,接著我們在 gatsby-config.js 裡面新增 DB id 與剛剛取得的密碼。

{
      resolve: `gatsby-source-notion-api`,
      options: {
        token: `<-- 你的 Token -->`,
        databaseId: `<-- Notion DB 的 id -->`,
				// e.g. https://notion.so/<username>/<DB id>
	    },
},

此時執行 Gatsby 就可以從 graphql 裡面發現有了 allNotion Nodes,以及如果有使用 remark 相關插件的話,也能發現 notion 的資源透過 remark 轉換完畢。

由於 Gatsby 屬於 SSG 會在 build 的時候就載入資源,所以 Notion 這邊更新並不會同步到你的部落格上,每次有新文章的時候,需要重新 build 一次網站。

另外要注意的是,由於目前 Notion API 屬於 beta 狀態,許多 block 尚未支援,以部落格最常使用到的 code block 與 image 來說都是,所以這邊需要透過一些小技巧來迴避這個問題。

code block

code block 在 Notion 上需要避免將 code block 轉為 block,而是保持純文字的方式讓 remark 去做 markdown 的判斷。

或者也可以採用 code snippest 的方式,使用 code sandbox 或 gist 等服務來嵌入程式碼。

image

圖片的話我自己則是採用 AWS S3 作為圖床,並搭配 uPic 這樣的上傳服務來撰寫部落格,並同樣注意在 Notion 之中複製貼上外部的圖片連結時記得保持純文字的狀態,並移除點擊連結。

然而,原生的 gatsby-remark-images 並不支援外部連結的圖片,這讓文章內的圖片失去原先的 RWD 效果,於是這邊改用社群開發的 gatsby-remark-images-anywhere 來處理。

雖然暫時 Notion API 在這兩個 block 的支援度上有限,不過依照目前 Notion API 的更新速度,可以期待這些 block 後續開放之後,就可以讓後台端也能保持樣式,讓平常閱讀筆記更加流暢。

部落格架構調整

經過這樣後台的建置,現在可以更輕鬆的幫文章上 meta 資訊,於是開始對部落格本身進行調整。

首先在部落格架構上分成:日常跟技術兩個分類並分成兩個站點,兩大分類下每篇文章又有不同的狀態,分別是:publish, log 跟 draft,於是這邊將過去透過重複的兩組 pages 來執行的分站,透過 template 來產生。

// before 
pages
├── 404.js
├── blog
│   ├── archive.js
│   ├── index.js
│   ├── log.js
│   └── tags.js
├── code
│   ├── archive.js
│   ├── index.js
│   ├── log.js
│   └── tags.js
└── index.js

templates
└── post.js

// after
pages
├── 404.js
└── index.js

templates
├── archive.js
├── index.js
├── log.js
├── post.js
└── tags.js

接著在 gatsby-node.js 裡面針對新增的 templates 根據對應的 category group 來 createPage

const categories =  result.data.categoryGroup.group;
categories.forEach(({ fieldValue: category }) => {
  actions.createPage({
    path: `/${category}/`,
    component: require.resolve('./src/templates/index.js'),
    context: {
      category
    }
  })

  ...
});

最後在 template 裡根據需要的資料來 export graphql query 即可。

後記

經過這一次對部落格的升級,對 Gatsby 包含:gatsby-node 的運作模式、source 與 transform 的插件有了更深的理解,下一步將會更深入 SSG 本身來去理解。