NotionとHugoでつくるblog

はじめに

Notionと静的サイトジェネレーターのHugo、それとGitHub ActionsGitHub Pagesを組み合わせて自動化されたBlog環境(ヘッドレスCMS)を構築します。

注意:本解説で扱うlounge-n/notion-md-exportアクションは現在開発途中のものです。本ページは動作確認のために書かれたものです。解説に従って環境を整えると一応の動作はしますが正式リリースまでお待ち下さい。正式リリースの後にこの注釈は削除されます。

作業を始める前提となる環境の準備

このページでは以下のことについて説明しません。それぞれ調べてください。

  • ローカル(手元のPC)へのhugoおよびgitのインストール
  • GitHubリポジトリの作成などGitHubを利用する上での基礎知識
  • Notionデータベース作成方法

環境構築 Notion side

ブログ執筆用のNotionデータベース

最低限3つのプロパティが必要となります。タグやカテゴリなどは後からカスタマイズすることが可能なのでまずは次のプロパティ構成のデータベースを作成して下さい。

  • Title(種類:タイトル)ブログ記事のタイトルになります。
  • Date(種類:日付)記事の投稿日付およびURLパスに用いられます。
  • Publish(種類:チェックボックス)GitHubにアップロード記事を指定します。

インテグレーションとコネクト

My Integrationsにアクセスしてインテグレーションを作成します。内部インテグレーションとしてコンテンツの読み取りと更新の2つを許可して下さい。

データベースに戻り、作成したインテグレーションをメニューの「コネクト」から追加して下さい。これによりトークンを用いてデータベースに外部からアクセスすることが可能となります。

環境構築 GitHub side

NotionからMarkdownを書き出すリポジトリとコンテンツを公開するためのリポジトリの2つを用意します。
双方を1つのリポジトリで運用することも可能ですが、2つに分けて棲み分けを行う方法がおすすめです。

GitHubリポジトリ1(Markdown書き出し用)

空のプライベートリポジトリを作成します。リポジトリ名の制約はありません。これはデプロイ元のリポジトリとなります。
次に、Settings > Secrets > Actions より次の環境変数を設定します。

NameSecret
NOTION_AUTH_TOKENMy Integrationsで作成したインテグレーションのトークンを値として設定します。
NOTION_DATABASE_IDNotionデータベースURLの次の部分を値として設定します。https://www.notion.so/xxxx/<データベースID>?v=xxxx

GitHubリポジトリ2(GitHub Pages公開コンテンツ用)

空のパブリックリポジトリを作成します。リポジトリ名は次のルールに従って下さい。これはデプロイ先のリポジトリとなります。

GitHub Pagesでは1つのアカウントまたは1つのOrganizationにつき公開できるGitHub Page1つだけです。上記ルールに従ったリポジトリのみGitHub Pageとして公開することができます。

次に、リポジトリのSettingより書き込み権限付きのデプロイキーを登録します。
デプロイキーについては デプロイキーの管理 を参照して下さい。ちなみに、デプロイキーとして鍵を生成する場合はパスフレーズを設定しないことに注意して下さい。
リポジトリ1のシークレットキーACTIONS_DEPLOY_KEYに秘密鍵を、リポジトリ2にデプロイキーとして公開鍵を登録します。

Hugo

ローカルでHugo環境を新規作成します。なお、本記事執筆時点で使用したHugoのバージョンは*v0.108.0+extended*でした。作成したディレクトリに移動してgit初期化します。

$ hugo new site <任意のディレクトリ名>  
$ cd <作成されたディレクトリ名>  
$ git init

次にテーマを設定します。本サイトはMainroadを使用しています。次のようにthemesディレクトリ配下にcloneするかサブモジュールとして追加します。

$ git clone https://github.com/vimux/mainroad.git themes/mainroad

or

$ git submodule add https://github.com/vimux/mainroad.git themes/mainroad

config.tomlを次のように書き換えて下さい。

baseURL = '/'  
languageCode = 'ja'  
title = '<ブログのタイトル>'  
theme = 'mainroad'

Markdown書き出し用リポジトリをリモートリポジトリに設定し、hugo環境をcommit&pushします。

$ git remote add origin git@github.com:<アカウントorOrganization>/<リポジトリ名>.git  
$ git branch -M main  
$ git add -A  
$ git commit -m "create hugo project"  
$ git push -u origin main

GitHub Actions

.github/workflows/ディレクトリを作成してその中に次の内容でnotion-to-markdown.yamlファイルを保存します。

name: Notion to Markdown  
  
on:  
  workflow_dispatch:  
  
jobs:  
  export_markdown:  
    runs-on: ubuntu-latest  
    steps:  
    - uses: actions/checkout@v3  
      with:  
        fetch-depth: 0  
    - uses: lounge-n/notion-md-export@main  
      with:  
        notion_auth_token: ${{ secrets.NOTION_AUTH_TOKEN }}  
        notion_database_id: ${{ secrets.NOTION_DATABASE_ID }}  
    - name: Diff  
      id: diff  
      run: |  
        git add -N .  
        git diff --name-only --quiet  
      continue-on-error: true  
    - name: Commit & Push  
      run: |  
        set -x  
        git config user.name github-actions[bot]  
        git config user.email 41898282+github-actions[bot]@users.noreply.github.com  
        git add .  
        git commit --author=. -m 'update contents'  
        git push  
      if: steps.diff.outcome == 'failure'

処理の流れを簡単に説明します。

  1. actions/checkoutで作業領域へリポジトリの内容をチェックアウトします
  2. lounge-n/notion-md-exportでNotionデータベースからPublishにチェックの付いたページをMarkdownで書き出す
  3. Diffにて作業領域に差分が生じていたらCommit & PushでリポジトリへPushする

このアクションを実行するとリポジトリの./contentディレクトリ配下にMarkdownファイルが追加されているはずです。

次に、デプロイリポジトリへコンテンツをPushするためのgithub-pages.yamlファイルを以下の内容で保存します。

name: GitHub Pages  
  
on:  
workflow_dispatch:  
  workflow_run:  
    workflows: [Notion to Markdown]  
    types:  
      - completed  
  push:  
    branches:  
      - main  
  
jobs:  
  deploy:  
    runs-on: ubuntu-latest  
    permissions:  
      contents: write  
    concurrency:  
      group: ${{ github.workflow }}-${{ github.ref }}  
    steps:  
      - uses: actions/checkout@v3  
        with:  
          submodules: true  # Fetch Hugo themes (true OR recursive)  
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod  
  
      - name: Setup Hugo  
        uses: peaceiris/actions-hugo@v2  
        with:  
          hugo-version: '0.108.0'  
          extended: true  
  
      - name: Build  
        run: hugo --minify  
  
      - name: Deploy  
        uses: peaceiris/actions-gh-pages@v3  
        # If you're changing the branch from main,  
        # also change the `main` in `refs/heads/main`  
        # below accordingly.  
        if: ${{ github.ref == 'refs/heads/main' }}  
        with:  
          deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}  
          external_repository: <アカウントorOrganization>/<アカウントorOrganization>.github.io  
          publish_branch: main

external_repositoryにはデプロイ先のリポジトリを設定します。
デプロイキーが正しく設定されていればこのアクションを実行するとMarkdownファイルを元にコンテンツがビルドされてデプロイリポジトリにPushされます。

デプロイ直後はページが参照できない可能性がありますが、少し時間を置いた後に次のURLでコンテンツを参照することが可能となります。

https://<アカウントorOrganization>.github.io

2つのアクションと運用方針について

本サイトはnotion-to-markdown.yamlgithub-pages.yamlの組み合わせで構築されています。Github Actionsは定期実行することも可能ですが、それほど頻繁にNotionで記事を書くことはないため手動およびリポジトリへのPushをトリガーに動作するようにしています。

ActionsNameTrigger
notion-to-markdown.yamlNotion to Markdown1. GitHubのWeb UIからの手動実行
github-pages.yamlGithub Pages1. GitHubのWeb UIから手動実行2. Notion to Markdownが実行された後3. mainブランチにPushされた後