2020.10.6
今まではGatsbyのデータソースにNetlifyCMSのマークダウンエディタを使っていました。
普段のメモにNotionを使っています。Notionには記事をそのまま公開できる機能があり、これをそのままGatsbyのデータソースに使ってみました。
いくつかNotion関連のプラグインがありました。その中でも最も使われていそうな gatsby-source-notionso を使いました。
Notionに公開用ページの親ページを作成します。このページに子ページを作成して、それが記事になります。
https://www.notion.so/Blog-188bb73b88944a34a87a8e53afb181b2
基本的にはこちらのGetting Startedに沿ってやってきます。
こちらのExampleリポジトリも参考にしました。
pcarion/gatsby-source-notionso-example
gatsby-config.js
にプラグイン追加自分のブログプロジェクトのgatsby-config.js
にgatsby-source-notionso
を追加。(name
はBlog
にしないとエラーが出ました。)
{
resolve: `gatsby-source-notionso`,
options: {
rootPageUrl:
"https://www.notion.so/kwst/Blog-188bb73b88944a34a87a8e53afb181b2",
name: "Blog",
},
}
Notion blog post by SatoshiKawabata · Pull Request #136 · SatoshiKawabata/blog
gatsby-node.js
にクエリを追加gatsby-node.js
でGraphQLのクエリallNotionPageBlog
を追加します。
pageId
ページのID
title
ページのタイトル
slug
ページのURL
excerpt
記事の概要
pageIcon
たぶんNotionで設定したページのアイコンだと思われます
return graphql(
`
query {
allNotionPageBlog(
filter: { isDraft: { eq: false } }
sort: { fields: [indexPage], order: DESC }
) {
edges {
node {
pageId
title
slug
excerpt
pageIcon
}
}
}
}
`
);
Notion blog post by SatoshiKawabata · Pull Request #136 · SatoshiKawabata/blog
記事の一覧ページのクエリはgatsby-node.js
と同じような感じです。
export const query = graphql`
query {
allNotionPageBlog(
filter: { isDraft: { eq: false } }
sort: { fields: [indexPage], order: DESC }
) {
edges {
node {
title
slug
excerpt
pageIcon
}
}
}
}
`;
実際のソースコードはこうなっています。
記事のデータを取ってくるクエリはこんな感じになります。
export const query = graphql`
query($pageId: String!) {
notionPageBlog(pageId: { eq: $pageId }) {
blocks {
blockId
blockIds
type
attributes {
att
}
properties {
propName
value {
text
atts {
att
value
}
}
}
}
imageNodes {
imageUrl
localFile {
publicURL
}
}
pageId
slug
title
isDraft
id
indexPage
excerpt
createdAt
}
}
`;
Notionのデータのままでは自分のブログにそのまま使うことはできません。それを何らかの形で自分のブログのテンプレートに使えるようにする必要があります。正直この作業が一番大変でした。
そこでNotionのデータをHTMLに変換するパーサを作りました。(ちなみにgatsby-source-notionso-exampleによるパーサーの例はこのようになっています)
Notionのブロックの種類はこれだけあるのでこれらをHTMLの要素に変換します。今回はテーブルなどは使いません。
type NotionBlockTypes =
| "meta" // メタ情報
| "page" // ページ情報
| "text" // テキスト -> <p>
| "quote" // 引用 -> <blockquote>
| "image" // 画像 -> <img>
| "bookmark" // リンク -> <a>
| "code" // コードブロック -> <pre>
| "bulleted_list" // リスト -> <ul>
| "header" // 見出し1 -> <h1>
| "sub_header" // 見出し2 -> <h2>
| "sub_sub_header"; // 見出し3 -> <h3>
画像のpublic URLはimageNodesというデータに入ってくるのでこういう関数を用意してあげました。
const getPublicImageURL = (src: string, imageNodes: NotionImageNodes[]) => {
const node = imageNodes.find((n) => n.imageUrl === src);
return node ? node.localFile.publicURL : "";
};
テキストにはインラインのスタイル(太字, イタリック, 下線, 打ち消し線, インラインコード
, インラインリンク)があるのでそれらも使えるようにします。このような感じでやりました。
const notionPageText = (propValue: NotionPageText) => {
const span = document.createElement("span");
let currentParent = span;
for (const att of propValue.atts) {
const attElm = document.createElement(att.att === "c" ? "code" : att.att);
if (att.att === "a" && att.value) {
attElm.setAttribute("href", att.value);
}
currentParent.appendChild(attElm);
currentParent = attElm;
}
currentParent.textContent = propValue.text;
return span;
};
また、Notionのデータの型はgatsby-source-notionso/src/types/notion.tsにあるのでこのようにして型情報を取ってきました。
import {
NotionPageBlock,
NotionImageNodes,
NotionPageText,
} from "gatsby-source-notionso/src/types/notion";
各種のメタ情報の記述方法は下記のとおりです。こちらのページを参考にしました。
!slug
ページのURL!date
ページの日付!!
ページの概要!draft
記事がドラフトかどうか(boolean型)!tags
記事のタグ今まではBoostNoteとかで記事を書いて、Netlify CMSに移してアップロードしていました。その手間が省けるのが嬉しいです。あと何より、画像を毎回手動でアップロードしていた作業がなくなったのが嬉しいです。
記事を書く度にデプロイが必要なのが少し面倒なだけですね。
今回の記事のNotionの元記事はこちらになります。
https://www.notion.so/kwst/GatsbyJS-Notion-4e26ab24b719446aa290fa26a577bd3b