📃

Wikiリンクによるドキュメント記述静的サイトジェネレーター「Scraps」を作っている話

2025/02/09に公開
2

こんにちは。タイトルの通りOSSとして開発しているWikiリンクによるドキュメント記述静的サイトジェネレーター(以下、SSG)の紹介です。

Scrapsの概要

ScrapsはMarkdownファイル上で内部リンク(Wikiリンク)を容易にドキュメント記述できるSSGです。CLIによってMarkdownファイルを元に以下のような静的サイトのファイル群を生成します。1つ1つのMarkdownファイルから生成されるページを「Scrap」という概念で扱います。

公式ドキュメントのOverviewは以下です。自給自足でScrapsによって生成しています。

https://boykush.github.io/scraps/scraps/overview.html

現時点では cargo または brew によるインストールをサポートしています。

サンプルサイトとして私自身のナレッジシェアに活用しているサイトはこちらです。

実装方法

実装リポジトリは以下

https://github.com/boykush/scraps

言語

言語はRustを用いて実装しています。

メイン機能のライブラリ選定として、Markdownシンタックスには CommonMarkに準拠したpulldown-cmark、テンプレートエンジンにはTeraを利用しており、同じくRust製のSSGであるzolaを多く参考にしています。

公式ドキュメント: Markdown Syntax

UI

UIに関してはNordテーマを利用しています。

https://www.nordtheme.com/

ダークモード対応についてはデフォルトではユーザーのOS設定に従うようになっています。設定によってLightまたはDarkを固定することが可能です。

公式ドキュメント: Color Scheme

デプロイメント

現状はGitHub Pagesでのデプロイ方法を公式として提供しています。

公式ドキュメント: Deployment

メイン機能

メイン機能の利用方法をベストプラクティス的に紹介します。

内部リンク

Scrapファイル(マークダウン)内では別Scrapのタイトルを [[]] で指定することで内部リンクを貼ることができます。

❯ tree scraps
scraps
├── Overview.md
└── Usage.md
Overview.md
See [[Usage]] for detail.

[[]] で指定したタイトルの別Scrapが存在しない場合、そのタイトルはタグとして扱われます。タグはCLIから確認可能です。

❯ scraps tag
CLI Usage(4) https://boykush.github.io/scraps/scraps/cli-usage.html
Content(3) https://boykush.github.io/scraps/scraps/content.html
Getting Started(3) https://boykush.github.io/scraps/scraps/getting-started.html
Appearance(1) https://boykush.github.io/scraps/scraps/appearance.html
Deployment(1) https://boykush.github.io/scraps/scraps/deployment.html

公式ドキュメント: Internal Links, Tag

エイリアス

ナレッジをまとめていると障壁になってくるのが、用語の略称や文脈別の重複をどう扱うかです。

簡単な方法として [[]] 内で [[元タイトル|エイリアス]] のように記述することでエイリアスを指定できます。

サイトにTDDと表示される例

❯ tree scraps
scraps
├── テスト駆動開発.md
└-- テスト駆動開発(書籍).md
テスト駆動開発(書籍).md
[[テスト駆動開発|TDD]]について書かれた本

上記の動的なエイリアス指定ではなく静的なマスタとしてエイリアスを定義したい場合は、エイリアスを貼るのみに特化したScrapページを作成することを推奨します。

Scrapsの方針

ナレッジオタクの方であれば、ここまで読んでCosense(旧Scrapbox)やObsidianとの関連を考えると思いますが、Scrapsはこの後紹介するような方針に従って、なるべく独自の路線で機能拡張をしていけるように心がけています。

メインの軸としてはScrapsが軽量であることです。

他ツールへの役割委譲

Scrapsが依存する唯一の必須ツールは git です。例として更新日時にはgitのコミット日時を利用します。その他はオプショナルに各ツールを推奨し役割委譲をしたいと考えています。

また標準デプロイメントにGitHub Pagesを用意しているようにGitHub上での運用を推奨しています。GitHub編集ページによってブラウザ上での共同編集を容易にするようなイメージです。

SSGなので当たり前ではあるのですが他ツールへの役割委譲はScrapsが軽量になりうる所以です。

今後の機能拡張も他ツールに委譲できるかどうかは都度検討していきます。一時GitHub IssueのようなTemplate機能を検討していましたが、他のテンプレート管理ツールに委譲できると考え取りやめました。

現時点で最も大きな課題はLSPの活用によるIDE上での編集体験の向上です。推奨ツールとして marksmanのようなLSPを調査していますが、一部タグ機能とフィットしない仕様があり検討中です。

Scrapページの記述体験

SSGによくある機能なのですが、ページ単位でマークダウンの先頭にメタデータを付与するような機能は現状考えていません。これはできる限りScrapの記述を生マークダウンに近い形で体験してもらうためです。

メタデータで記述しうる機能の具体例として以下のような検討を行っていました。

  • タグは存在しないタイトルの指定とCLIによるデバックによって代替します
  • エイリアスは利用側の指定で動的に行います。静的なエイリアスはメタデータでは提供しません

なるべく軽量に記述できるようにすることでナレッジシェアだけでなく日々の作業メモにも使ってもらえるようなイメージをしています。

パフォーマンス計測

静的サイトのビルドに関してはデバッグオプションを用意しています。分散トレーシングによくあるようなSpanを活用した計測です。

❯ scraps build -v
...
2025-02-09T06:26:27.024978Z  INFO run:render_scraps:render_scrap: scraps::build::cmd: close time.busy=10.1ms time.idle=459ns
2025-02-09T06:26:27.035072Z  INFO run:render_scraps:render_scrap: scraps::build::cmd: close time.busy=10.0ms time.idle=1.62µs
2025-02-09T06:26:27.044775Z  INFO run:render_scraps:render_scrap: scraps::build::cmd: close time.busy=9.68ms time.idle=1.00µs
2025-02-09T06:26:27.054028Z  INFO run:render_scraps:render_scrap: scraps::build::cmd: close time.busy=9.23ms time.idle=959ns
...
2025-02-09T06:26:29.873097Z  INFO run:render_tags:render_tag: scraps::build::cmd: close time.busy=8.93ms time.idle=417ns
2025-02-09T06:26:29.873129Z  INFO run:render_tags: scraps::build::cmd: close time.busy=166ms time.idle=375ns
2025-02-09T06:26:29.879283Z  INFO run:render_css: scraps::build::cmd: close time.busy=6.15ms time.idle=709ns
2025-02-09T06:26:29.891250Z  INFO run:render_search_index: scraps::build::cmd: close time.busy=12.0ms time.idle=334ns
2025-02-09T06:26:29.891811Z  INFO run: scraps::cli::cmd::build: close time.busy=8.08s time.idle=2.75µs
-> Created 288 scraps
Done in 8.81 secs

自身のナレッジサイトではScrap300件弱に対して 8.81sec程度ですv0.18.4にて2.64sec程度まで改善をしました)。なるべく自身が一番のヘビーユーザーになり性能劣化が起きないよう注視していきます。

まとめ

ページング、検索など不自由なく利用するための最低限の機能が揃ってきたタイミングだったため本記事を公開しました。

自身も活用しながら機能拡張をしているのですが、「こうゆう機能欲しい!」というリクエスト等あればぜひ本記事のコメント欄かGitHub Issue(よしなに英訳残すので日本語でも大丈夫です)でお寄せください!

Scrapの方針だけ読むと堅苦しく見えるかもしれませんがどちらかというと実装方針で意識すべき関心だと思っているので、機能要望はお気軽に意見をもらえたら嬉しいです。

GitHubで編集を提案

Discussion

YAMAMOTO YujiYAMAMOTO Yuji

Wikiというと本来は、原則誰でもその場で更新できるウェブサイトのことを指すと思っていますが、静的サイトジェネレーターだとさすがにWikiにはできないのではないでしょうか。まあ、世の中には「Wikiと名乗っているのに限られた人しか編集できないウェブサイト」もあると伺っているので、その辺から意味が変質しているのは認識しておりますが...。

KushKush

コメントありがとうございます!厳密な定義のご指摘助かります。混乱を招くような用語を記載してしまいすみません。

確かに現時点では共同編集を気軽にできるような機能は揃っておりませんので今後の方向性も考えた上で本記事の修正・ツールの表現方法を検討します。

今後の方向性は考え中ですが、元々の気持ちを表明すると個人的には積極的に共同編集を行うツールとして活用してもらいたいと考えていました。GitHub上での運用を必須としSSGからGitHub編集ページへのリンクを飛ばすような機能も候補にはあります。その上で、

例として標準デプロイメントにGitHub Pagesを用意しているようにGitHub上での運用(権限管理等)を推奨しています。

にある権限管理の例は矛盾しているように見え混乱を招いてしまっていると思います。

改めましてナレッジシェアを行うようなツールとして定義の誤用には気をつけたいと思います。コメントによるご指摘ありがとうございました。

※追記: 記事修正差分 https://github.com/boykush/zenn/commit/e8e2afa3ecaebdbdbda2683d2e81942fa21332d1