It技術

Notion+HUGOで寝転びながらブログを書く

Notion+HUGOで寝転びながらブログを書く

結論

  • Hugoでサイトをカスタマイズしながら、Notionで記事の管理ができる

  • Notionはスマホから使えるので、寝転びながらブログが書ける

  • 以下のリポジトリを使うのが良さそう

    https://github.com/HEIGE-PCloud/Notion-Hugo

はじめに

みなさん、ブログ書いてますか。

自分は最近以下の記事に影響を受けて、久々にブログを再開しました。

https://qiita.com/HiromuMasuda0228/items/a71dea7ef4d77a30b118

ブログを書く場合、色々と選択肢はあると思います。

自分が思いつく範囲だと以下が有力です。

  • ブログサービス
    • はてなブログ
    • Qiita
    • Zenn
  • セルフホスト
    • 静的サイトジェネレータ
    • Wordpress

自分も色々試してきましたが、

  • カスタマイズがしやすい
  • ポートフォリオとして使いやすい
  • 様々なテーマが公開されているので、デザインができなくても大丈夫
  • ほとんどの操作を好きなエディタからできる

という利点から、静的サイトジェネレータであるHUGOを利用していました。

https://gohugo.io/

さて、エンジニアの皆さん、こんなふうに思ったことはないですか?

  • ブログ書くの、面倒くさい
  • ブログを書くためにPCを開くのがめんどくさい
  • 寝転びながら、スマホで書けたらいいのに

自分はめっちゃあります笑

この問題を

  • スマホから文章を書きやすい Notion
  • サイトのカスタマイズが簡単にできる HUGO

を組み合わせることで解決できないかと、方法を模索したのが本記事になります。

方法

Notion Hugoで検索すると、以下のリポジトリが出てくるので利用させていただきました。

https://github.com/HEIGE-PCloud/Notion-Hugo

これは、以下のことを行ってくれるリポジトリになっています。

  1. Notionでページを管理
  2. スクリプトでNotionのページを取得してマークダウンに変換&配置
  3. HUGOで静的サイト作成
  4. github pagesにデプロイ

このリポジトリの「Get Started」の手順を進めることで、Github Pages上でサイトを公開できます。

私のサイトの最終的な設定がどうなったかは、以下のgithubを見ていただければと思います。

https://github.com/hakomori64/hakomori64.github.io

Q&A

基本的な手順は「Get Started」に沿って進めていただければいいので省略します。本記事では、

  • 動作の仕組み
  • Get Startedの古くなっている点の補足
  • カスタマイズの方法

などをQ&A形式で説明していきます。

どのように使っていけばいいの?

「Get Started」で以下のようなNotionのページを複製して自分のNotionのワークスペースに持ってきたと思います。

上の画像であれば、以下のようにページが構成されます。

  • /posts/markdown
  • /posts/this-proof-of-riemann-hypothesis-by-chatgpt
  • /about
  • /test-embed

つまり、インテグレーションに共有したページの

  • データベース以下のポスト
  • 子ページ

が、サイトからアクセスできる形になります。

新規で投稿を作成する場合は、Postsデータベースに投稿を追加していくか、ページ直下に子ページを追加していくことになります。

次に、実際に投稿をどのように作っていくかを説明します。

例えば、本記事は以下のようなページを作成することで公開しています。

データベースの「新規」ボタンから、このページを作成しました。

いろいろなプロパティが設定されていますが、これがHUGOのフロントマターに変換されます。フロントマターはページのメタ情報を設定する項目になります。

https://gohugo.io/content-management/front-matter/

例えば上の例だと、以下のような設定になってます。

  • このページのタグは「Notion」、「Hugo」にする
  • カテゴリは「Web開発」にする
  • キーワードは「Notion」、「Hugo」にする
  • draft(下書き)状態にしておく
    • このチェックを外すことで記事を公開できます

また「プロパティを追加」するから、自分の好きなようにフロントマターを追加できます。

omit_header_textプロパティは私が勝手に追加した項目です。

あとは自由に記事を書いていき、書き終わったらdraftプロパティのチェックを外します。

Notionのどのような要素がサイトで使えるの?

このリポジトリはNotionの要素のマークダウンへの変換に以下のライブラリを使っています。

https://github.com/HEIGE-PCloud/Notion-To-Markdown

2023/1/1時点で以下の要素に対応しているみたいです。

  • heading
  • images
  • quotes
  • links
  • bullets
  • todo
  • inline code
  • code block
  • strikethrough, underline, bold, italic
  • nested blocks
  • embeds, bookmarks, videos, files (converted to links)
  • Simple tables
  • toggle
  • divider
  • equation block (converted to code blocks)

どのような仕組みで記事が公開されるの?

「Get Started」でテンプレートのリポジトリを複製してきたと思いますが、このリポジトリにはGithub Actionsの設定がされています。

https://github.com/HEIGE-PCloud/Notion-Hugo/blob/main/.github/workflows/cd.yml

mainにプッシュするか、1時間経過がトリガーとなってビルド&デプロイが実行されます。

  1. トリガーが発生する

  2. Notionからページを取得してマークダウンに変換する

    以下が実行される

    https://github.com/HEIGE-PCloud/Notion-Hugo/blob/main/src/index.ts

  3. hugoコマンドでサイトをビルドする

  4. github pagesにデプロイする

このような流れになっています。

Github pagesにデプロイされない

「Get Started」の設定に加えて、リポジトリのSettings → Pages → Build and Deploymentで以下のように設定する必要があります。

  1. Sourceを「Github Actions」に変更
  2. 「Static HTML」の「Configure」を選択

Notionのページをインテグレーションに共有できない

「Get Started」にNotionのページをインテグレーションに共有するように書いている箇所があります。(以下の画像のような感じ)

2023/1/1時点で、この操作ができなくなっています。

インテグレーションにページを共有するには、

  1. ページ右上の3点リーダー ⇨ 「コネクト」⇨ 「コネクトの追加」と進む
  2. コネクトの一覧に作成したインテグレーションが表示されているので選択する

という手順になります。

以下のような表示になれば、コネクトが正常に追加されています。

audioやvideoをプレビューしたい

Notionのテンプレートの「Markdown」という記事で、Notionの各ブロックがどんな感じで表示されているのかが確認できますが、Video要素やAudio要素が以下のようになってると思います。

  • video要素は元動画ファイルへのリンクになっている
  • audio要素は表示されていない

これをサイト内でプレビューするためには少し工夫が必要です。

src/render.tsrenderPageという関数があり、これに手を加えて以下のようにします。

renderPageはNotionのページをMarkdown文字列に変換する関数です。

https://github.com/hakomori64/hakomori64.github.io/blob/dafbaa2dd48a300f1bc475e3174a6c2e48cc2ee5/src/render.ts

具体的に変更を加えたのは以下の箇所です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    n2m.setCustomTransformer('video', async (block) => {
        const { video } = block as any;
        console.info(`video: ${JSON.stringify(video)}`);
        if (video?.external?.url) {
            return `<video style="width: 100%; height: auto;" src="${video?.external?.url}" controls></video>`;
        } else if (video?.file?.url) {
            return `<video style="width: 100%; height: auto;" src="${video?.file?.url}" controls></video>`;
        } else {
            return '';
        }
    });

    n2m.setCustomTransformer('audio', async (block) => {
        const { audio } = block as any;
        console.info(`audio: ${JSON.stringify(audio)}`);
        if (audio?.external?.url) {
            return `<audio style="width: 100%; height: auto;" controls><source src="${audio?.external?.url}"></audio>`;
        } else if (audio?.file?.url) {
            return `<audio style="width: 100%; height: auto;" controls><source src="${audio?.file?.url}"></audio>`;
        } else {
            return '';
        }
        return '';
    });

このn2mというオブジェクトがNotionのブロックのマークダウンへの変換を担っています。

このオブジェクトのsetCustomTransformerというメソッドを呼び出すことで、ブロックをどのように変換するかを指定することができます。video要素をvideoタグに、audio要素をaudioタグに変換しているのがなんとなく伝わるかなと思います。styleの指定などはここをいじれば良いです。

カバー画像がサイト上で表示されるようにしたい。

Notionのページには以下のようにカバー画像が設定できます。(宇宙の部分)

適切な設定をすることで、この画像をサイトの記事のアイキャッチ部分にすることができます。(以下の画像のような感じ)

HUGOのドキュメントを見ると、各記事のフロントマターでfeatured_imageという項目を入れてやればいいみたいです。以下の解説記事がわかりやすかったので載せておきます。

https://jam.bchari.com/posts/featured-image/

この項目を設定するためには、またコードを少しいじる必要があります。これもrenderPageを少しいじる必要があります。

https://github.com/hakomori64/hakomori64.github.io/blob/dafbaa2dd48a300f1bc475e3174a6c2e48cc2ee5/src/render.ts

キモは以下の箇所です。この部分でページのカバー画像を取得してfeatured_imageに設定しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// set featuredImage
    const featuredImageLink = await getCoverLink(page.id, notion);
    if (featuredImageLink) {
        const { link, expiry_time } = featuredImageLink;
        frontMatter.featured_image = link;
        // update nearest_expiry_time
        if (expiry_time) {
            if (nearest_expiry_time) {
                nearest_expiry_time = expiry_time < nearest_expiry_time ? expiry_time : nearest_expiry_time
            } else {
                nearest_expiry_time = expiry_time
            }
        }
    }

元々のリポジトリでは

1
frontMatter.featuredImage = link;

というふうに、フロントマターの名前が異なっていたので、カバー画像がページに表示されていなかったようです。

まとめ

元々メモアプリとしてNotionを利用していたこともあり、記事を書く心理的なハードルが大きく下がりました。

ブログサイトを作ることは好きですが、ブログを書くこと自体は面倒に感じてしまう性格なので、これまでブログを作っては放置することを繰り返してきました。

これからはNotionを使ってバリバリブログを書けたらいいなと思います。