🧠

GitHub ActionsでGitHub Pagesにorg-roam-uiを公開する

2024/03/24に公開

私はナレッジ管理のツールとして org-roam を利用しており、作成したorgファイルはGitHubのリポジトリで管理しています。
org-roamの好きな点として、これまで貯めてきたメモをorg-roam-uiを使っておしゃれなグラフで確認できることです。このグラフを育てて大きくしている感じがナレッジを貯めるモチベーションになっています。また、グラフで確認することで、どこにもリンクされていない孤立したメモのリンクの見直しにも活用しています。


グラフは2D・3Dの両方で確認できます。かっこいい!

本来、org-roam-uiはローカルでWebサーバーを立ち上げ、Emacsと連動してブラウザ上でorg-roamを視覚的に使いやすくする機能ですが、個人的にはたまにグラフを見返したい程度でしか使っていなかったので、GitHub ActionsでリポジトリにpushされたorgファイルからGitHub Pageにorg-roam-uiの静的サイトを公開する仕組みを作ったのでご紹介します。

作ったもの

https://github.com/marketplace/actions/publish-org-roam-ui

使い方

(本記事ではorg-roam自体の基本的な使い方は説明しません)

まず、org-roamで作成される.orgファイルと.dbファイルをGitHubで管理します。

init.el
;; org-roamで作成される.orgファイルと.dbファイルの設定を確認
(setq org-roam-directory "/path/to/org-roam-dir")
(setq org-roam-db-location "/path/to/org-roam-dir/<org-roam-filename>.db")
cd /path/to/org-roam-dir/
git init

そして、以下のようなワークフローを作成します。これでmainブランチにorg-roamの更新をpushすると簡単にGitHub Pagesにorg-roam-uiが公開されます。

.github/workflows/publish.yml
name: Publish org-roam-ui page

on:
  push:
    branches:
      - main

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - name: Generate org-roam-ui page
        uses: ikoamu/org-roam-ui-hosting@main
        with:
          org-roam-db-filename: <org-roam-filename>.db
          deploy-to-pages: true

画像表示

GitHub Pages上でも画像を表示したい場合、リポジトリで管理する必要があります。
リポジトリ直下にimgというディレクトリを作成し、その中に画像を作成してください。

* また、org上では相対パスで画像を指定してください
[[./img/test.png]]

サイトのタイトル

ワークフローのyamlでsite-tileを設定することで、サイトのタイトルを変更することができます。(未指定の場合はORUIになります)

.github/workflows/publish.yml
  main:
    runs-on: ubuntu-latest
    steps:
      - name: Generate org-roam-ui page
        uses: ikoamu/org-roam-ui-hosting@main
        with:
          org-roam-db-filename: <org-roam-filename>.db
          deploy-to-pages: true
+         site-title: my org-roam!

code highlighting

元のorg-roam-uiではコードブロックのハイライトはサポートされていません。
https://github.com/org-roam/org-roam-ui/issues/159

しかし、後述しますが、このActionsを実現するためにorg-roam-uiをforkしてカスタマイズしているため、GitHub Pages上ではハイライトされるようにorg-roam-uiを修正しています。

実装方法

org-roam-uiのpublish機能については公式のDiscussionsで議論されています。
https://github.com/org-roam/org-roam-ui/discussions/109

その中の @uncomfyhalomacroさんのこちらのコメントを参考に実装しています。
この方は、org-roam-uiのEmacsとの連携部分やローカル実行前提のコードを変更するpatchを作成しており、それを適用してからbuildするというスクリプトを使って静的サイトを生成しています。

https://github.com/uncomfyhalomacro/org-roam-ui/tree/feature/add-export-functionality

このリポジトリをforkし、GitHubで管理しているファイルを使って上記のスクリプトを実行できるように実装しました。

.db ファイルからjsonファイルを作成する

スクリプトを実装するには、orgファイル間のリンクやタグの情報が書かれているgraphdata.jsonを作成する必要があります。

本来、org-roamの更新処理が実行されたタイミングで org-roam-ui--send-graphdata が実行され、json形式のデータをWebSocketでWebサーバーに送信しています。

https://github.com/uncomfyhalomacro/org-roam-ui/blob/5ac74960231db0bf7783c2ba7a19a60f582e91ab/org-roam-ui.el#L403-L457

GitHub Actions上でemacs-lispを実行するのが難しいため、リポジトリに格納された.db ファイルを読み込んでjsonファイルを生成するスクリプトをJavaScriptで実装しています。

https://github.com/ikoamu/publish-org-roam-ui/blob/main/generate_json.js

.org ファイルをorg-roam-uiのpublicディレクトリに格納する

org-roam-ui上でorgファイルの内容を表示するためにはorgファイルのファイル名を <タイムスタンプ-org-roam上で表示するタイトル>.org から <ノードのID> に変換し、 org-roam-ui/public/note 配下に置く必要があります。
こちらはshellで実装しました。

#!/bin/bash

org_path=$1

mkdir -p notes

# 上記のスクリプトで作成したgraphdata.jsonからタイムスタンプ<->IDの変換を行っている
cat graphdata.json |
jq -c '.data.nodes[]' |
while read -r nodes; do
  id=$(echo "${nodes}" | jq -r '.id')
  file=$(echo "${nodes}" | jq -r '.file') 
  timestamp=$(echo "${file}" | cut -d'-' -f1)
  matching_file=$(find "${org_path}" -name "${timestamp}-*.org" -type f)
  
  if [[ -f "${matching_file}" ]]; then
    cp -p "${matching_file}" "notes/${id}"
  fi
done

コードハイライトされるようにする

org-roam-uiはuniorgを使ってorgからhtmlに変換を行っています。
そのため、processorにrehypePrismを追加してシンタックスハイライトができるようにしています。

org-roam-ui/util/processOrg.tsx
const processor = useMemo(
    () =>
      baseProcessor
        .use(katex, {
          ・・・
        })
        .use(rehype2react, {
          createElement: React.createElement,
          ・・・
-       }),
+       })
+       .use(rehypePrism, { ignoreMissing: true }),
    [previewNode?.id],
  )

ハイライト用のCSSはcdnで取得する様に<head>にリンクを追加しています。
テーマは個人的に好みなので prism-tomorrow を使っています。

org-roam-ui/pages/index.tsx
  return (
    <>
      <Head>
+        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/9000.0.1/themes/prism-tomorrow.min.css" />
      </Head>
    </>
  )
}

最後に

org-roamというかなりマイナーなツールを使っているかつ、同じようにPagesに公開したい!という方がどれくらいいるのかわかりませんが、参考になれば幸いです。

Discussion