GatsbyJSで作成したブログのデータソースをNotionにする

2020.10.06

GatsbyJS%E3%81%A6%E3%82%99%E4%BD%9C%E6%88%90%E3%81%97%E3%81%9F%E3%83%95%E3%82%99%E3%83%AD%E3%82%AF%E3%82%99%E3%81%AE%E3%83%86%E3%82%99%E3%83%BC%E3%82%BF%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%92Notion%E3%81%AB%E3%81%99%E3%82%8B%2004fe823549fc475abe358a923e9d406f/Untitled.png

今まではGatsbyのデータソースにNetlifyCMSのマークダウンエディタを使っていました。

普段のメモにNotionを使っています。Notionには記事をそのまま公開できる機能があり、これをそのままGatsbyのデータソースに使ってみました。

blog.kwst.site

いくつかNotion関連のプラグインがありました。その中でも最も使われていそうな gatsby-source-notionso を使いました。

gatsby-source-notionso

Notionに公開用のページを作成

Notionに公開用ページの親ページを作成します。このページに子ページを作成して、それが記事になります。

https://www.notion.so/Blog-188bb73b88944a34a87a8e53afb181b2

プラグインの導入

基本的にはこちらのGetting Startedに沿ってやってきます。

Getting Started

こちらのExampleリポジトリも参考にしました。

pcarion/gatsby-source-notionso-example

gatsby-config.jsにプラグイン追加

自分のブログプロジェクトのgatsby-config.jsgatsby-source-notionsoを追加。(nameBlogにしないとエラーが出ました。)

{
  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
        }
      }
    }
  }
`;

実際のソースコードはこうなっています。

SatoshiKawabata/blog

記事のテンプレート

記事のデータを取ってくるクエリはこんな感じになります。

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
    }
  }
`;

SatoshiKawabata/blog

NotionのデータからHTMLへ変換

Notionのデータのままでは自分のブログにそのまま使うことはできません。それを何らかの形で自分のブログのテンプレートに使えるようにする必要があります。正直この作業が一番大変でした。

そこでNotionのデータをHTMLに変換するパーサを作りました。(ちなみにgatsby-source-notionso-exampleによるパーサーの例はこのようになっています)

SatoshiKawabata/blog

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 : "";
};

SatoshiKawabata/blog

テキストにはインラインのスタイル(太字, イタリック, 下線, 打ち消し線, インラインコード, インラインリンク)があるのでそれらも使えるようにします。このような感じでやりました。

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

参考

ブログを Gatsby + Netlify + Notion に移行

© 2019-2021 kwst.site.