Obsidian → Hugo の運用方法
このノートを作成した経緯
最近, Obsidian というツールを使って, ノートをとっています.
ノートの中には, 公開してもいいかなと思えるものもありました.
そこで, Obsidian でとったノートを楽に公開できるような運用方法について考えてみました.
その最中にいろいろと考慮するポイントがあり楽しかったので, このノートを作成しました.
よりシンプルな方法を Obsidian → Hugo の運用方法 2 で説明しています.
運用方法
↓の3つを使用します.
- Obsidian フォルダ: Obsidian vault を格納するフォルダ
- Obsidian 記法で書かれたマークダウンファイルを格納している
- ブログ用フォルダ: Hugo を管理するフォルダ
- 通常のマークダウン記法で書かれたマークダウンファイルとブログの設定情報を格納するファルダ
- Vercel
そして, 公開は↓のステップで行います.
- Obsidian でノートをとる
- 変換ツールを使用してノートを Obsidian フォルダからブログ用フォルダにエクスポート
- Hugo × Vercel で記事を投稿
以下でその詳細を説明します.
Obsidian のフォルダ構成
.
|-- .obsidian
|-- _template
|-- private
|-- notes
|-- static
|-- public
|-- notes
|-- static
-
.obsidian
: Obsidian の各種設定を格納するフォルダ. 自動で作成されます. -
_template
: テンプレートファイルを格納するフォルダ. Obsidian の template プラグインや templater プラグインで使用されます. -
private/notes
: 非公開 (通常) のマークダウンファイルを格納するフォルダ -
private/static
: 非公開の画像などの静的ファイルを格納するフォルダ -
public/notes
: 公開するマークダウンファイルを格納するフォルダ -
public/static
: 公開する画像などの静的ファイルを格納するフォルダ
特徴は, 公開するコンテンツと非公開のコンテンツ, マークダウンファイルと静的ファイルでフォルダ分けしていることです.
マークダウンファイルだけを管理するのであれば, わざわざフォルダ分けしなくても, yaml フロントマターで publish: true/false
や draft: true/false
を設定し, 後述するツールを使うことによってエクスポートするファイルを振り分けることも可能です.
ただ, 静的ファイルを同様に扱うのは難しいので, フォルダ分けによって公開/非公開を管理する方針をとっています.
また, このようにフォルダを分けておくことで, 公開用のノートが非公開のノートを参照することによる無効なリンクができてしまったり, 非公開の静的ファイルが間違って公開されてしまったりといったことが起きにくくなるのもメリットだと思います.
また, Obsidian でノートをとるだけであれば, 必ずしもマークダウンファイルと静的ファイルをフォルダ分けしなくてもよいのですが, Hugo ではこれらを別々のフォルダに分けて管理するようになっているので, Hugo へのエクスポートのしやすさも考えて, それにならっています.
さらに, 静的ファイルとマークダウンファイルをフォルダ分けすることで, 私には副次的なメリットがありました.
それは, スマホと PC との間の Obsidian ファイル群の同期にとってです.
私は, Android スマホを使用しており, ファイル群の同期には FolderSync というアプリケーションを使用しています. FolderSync を使うことでスマホのローカルフォルダとクラウドストレージ内のフォルダを同期することができます.
ただ, Obsidian vault 全体を同期すると, スマホのストレージを圧迫することになってしまいます.
そこで, マークダウンファイルを格納する private/notes
と public/notes
だけを FolderSync で同期することで, 画像ファイルといった容量が大きめのファイルをスマホに保存せずに済むようになります. (スマホで静的ファイルを確認できなくなりますが...)
ちなみに余談ですが, 私はFolderSync では .obsidian
も同期していません. これはスマホと PC でプラグインを使い分けられるようにするためです.
これまた余談ですが, 私は private/notes
と public/notes
以下はフォルダ分けしていません.
Obsidian では豊富な検索機能とタグ機能が提供されているため, 本文の内容でフォルダ分けする必要性を今は感じていないためです.
ずぼらな自分は, 一階層のフォルダにノートをボンボン放り込み, カテゴリー分けは全てタグで行っています.
基本的には, フォルダ分けは↑で説明したような, ファイルの 種類 や公開/非公開といった 状態 に従うのが自分には合っている気がします.
Hugo のフォルダ構成
.
|-- config
|-- layouts
|-- assets
|-- themes
|-- static
|-- obsidian
|-- public
|-- notes
|-- static
-
config
,layouts
,assets
,themes
: デフォルト + テーマのカスタマイズなどに関するもの -
static
: ロゴやファビコンなどブログ特有の静的ファイルを格納するフォルダ (Hugo のデフォルトで静的ファイルを格納するフォルダ) -
obsidian/public
: Obsidian のpublic
フォルダを後述するツールによってエクスポートしてきたフォルダ. 名前の通り,public/static
には Obsidian フォルダのpublic/static
がそのまま入っており,public/notes
には Obsidian フォルダのpublic/notes
内のマークダウンファイルがよしなに変換されたのちに出力されています.
Hugo 側で適切にコンテンツを処理できるようにいくつかの設定変更が必要です.
以下では自分が採用している設定変更を説明します.
Hugo のデフォルトではマークダウンファイルは content
ディレクトリ, 静的ファイルは static
に格納することになっています.
obsidian/public/notes
をマークダウンファイルの格納先, obsidian/public/static
を静的ファイルの格納先として Hugo に認識させるため, ↓の設定変更を行います.
contentDir = "obsidian/public/notes"
staticDir = ["static", "obsidian/public/static"]
またリンク周りについても設定変更が必要です.
例えば, 変換後のリンクが [sample](public/notes/abc.md)
だった場合, これを URL では qawatake.com/notes/abc
のような形式にしたいです.
そのためには, 3つの場所をいじらなければいけません.
layouts/_default/_markup/render-link.html
lauouts/_default/_markup/render-image.html
config/_default/config.toml
{{- $url := urls.Parse .Destination -}}
{{- $scheme := $url.Scheme -}}
<a href="
{{- if eq $scheme "" -}}
{{- if strings.HasSuffix $url.Path ".md" -}}
{{- $destination := strings.TrimPrefix "public/notes" .Destination -}}
{{- relref .Page $destination | safeURL -}}
{{- else -}}
{{- .Destination | safeURL -}}
{{- end -}}
{{- else -}}
{{- .Destination | safeURL -}}
{{- end -}}"
{{- with .Title }} title="{{ . | safeHTML }}"{{- end -}}>
{{- .Text | safeHTML -}}
</a>
- GitHub - zoni/obsidian-export: Rust library and CLI to export an Obsidian vault to regular Markdown の README を参考にし, 修正を加えています.
-
strings.TrimPrefix "public/notes"
で余分なpublic/notes
を取り除く処理をしています.
{{- $url := urls.Parse .Destination -}}
{{- $scheme := $url.Scheme -}}
<img src="
{{- if eq $scheme "" -}}
{{- strings.TrimPrefix "public/static" .Destination | safeURL -}}
{{- else -}}
{{- .Destination | safeURL -}}
{{- end -}}"
{{- with .Title }} title="{{ . | safeHTML }}"{{- end -}}
{{- with .Text }} alt="{{ . | safeHTML }}"
{{- end -}}
/>
-
render-link.html
と同様にpublic/static
を取り除く処理を記載しています.
[permalinks]
'/' = '/notes/:filename/'
- ↑の記述を末尾に追加しました
- この設定がないままだと,
obsidian/public/notes/abc.md
というパスはqawatake.com/abc
という URL になってしまいます. - この設定を足すことで,
notes
という名前空間を作ることができます.
Hugo フォルダ作成の意義
これを読まれている方の中には, わざわざ Obsidian フォルダとブログ用フォルダを分ける必要性を感じられない方もいらっしゃるかもしれません. 私がこの二つを分けた理由は↓の2つです.
- 公開するノートをチェックするのに
git diff
やgit status
を使いたい.
しかし, Obsidian フォルダでは毎日それなりの量のファイルが新規作成されているため, フォルダ分けしないと,こうしたコマンドの出力結果が汚れて使いにくくなってしまう. - ブログ固有設定と Obsidian ノートの変更事項をまとめて同じ場所で管理するのが気持ち悪い.
一方で, 中には, 「どうせ Obsidian フォルダとブログ用フォルダを分けるのであれば, Obsidian に頼らず Hugo だけで記事を作成すればいいのでは?というか, note とかはてなブログを使えばいいのでは?」と思われる方もいらっしゃるかもしれません.
私がそうしなかった理由は, あくまでブログは公開できる「ノート」であって, 他のノートと同じように自分が参照できるようにしたいからです.
もし ブログの記事を Obsidian の外部で作成すると, それを自分が参照したくなったとき, 私は Obsidian の外部に情報を探しに行かなくてはいけなくなります. また, ブログの記事に修正を加えるときも, Obsidian の外側に修正を加えにいかなくてはいけなくなります.
私は, このように自分のまとめる情報がいろいろなところにバラバラと散らばるのが気に入りません.
どこに何があったか思い出すのも面倒くさいので, できれば情報は全部 Obsidian に入れておきたいです.
Obsidian フォルダからブログ用フォルダにエクスポート
Obsidian でとったノートをそのまま Hugo で処理できたら嬉しいのですが, 記法の違いなどがあるため, それは叶いません.
例えば, Obsidian には
- 内部リンク (
[[]]
) - 埋め込み (
![[]]
) - タグ (
#todo
), - コメント (
%% comment %%
)
などの記法がありますが, これは通常のマークダウンでは解釈できません.
また, Hugo では yaml フロントマターでタイトルやタグを設定することでブログの構成に役立てることができますが, これらをわざわざ手動で設定するのはめんどくさがりな私には億劫です.
したがって, ↓のような処理を自動的に行ってほしくなります.
- Obsidian 独自の内部リンクや埋め込みの記法を通常のマークダウンのリンク記法に変換する.
- 本文中のタグを削除 + フロントマターに設定する.
- Obsidian 記法のコメントを削除する.
- 本文中からタイトルを取得してフロントマターに設定する.
これを実現するために, obsdconv というプログラムを作成しました.
例えば,
obsdconv -src /path/to/obsidian_vault -dst /path/to/hugo -link -rmtag -cptag -cmmt -title
を実行することで /path/to/obsidian_vault
内のファイルが↑で述べたように処理されて /path/to/hugo
に出力されます.
これまでに述べてきたフォルダ構成に従うと, より具体的なコマンドは↓のようになります.
obsdconv -src /path/to/obsidian_folder -dst /path/to/blog_folder/obsidian -link -rmtag -cptag -cmmt -title
obsdconv
はエクスポート用の変換機能を他にも備えているので, 詳細は qawatake - qawatake/obsdconv: convert obsidian markdowns in multiple ways を御覧ください.
Hugo × Vercel で記事を投稿
ここまでで, Hugo の設定変更, マークダウンファイルの変換ができたので, あとは Vercel にデプロイすれば完了です.
ここから先は別に考えることも特にないので省略します.
おまけ: obsdconv を使ったノート管理
↑で述べたとおり, 私は Obsidian フォルダ内のファイルをエクスポートするのに obsdconv
というプログラムを使用していますが, ここでは, それ以外の obsdconv
の使い方を説明します.
皆さんは Obsidian で新規作成するファイルにどういった名前をつけているでしょうか.
私はずぼらなので, zettelkasten プラグインに任せて 211205-234426
のように現在時刻をそのままファイル名にしています.
しかし, これでは Obsidian のすてきな機能の一つである内部リンク [[]]
を非常に使いにくくなってしまいます.
毎回参照したいファイルを全文検索で見つけてきて, ファイル名をコピペして [[211205-234630]]
のように記載しなければいけないからです.
obsdconv
を使用すれば, zettelkasten プラグインを使いつつ, この面倒を回避することができます.
obsdconv
のオプションに -alias
があります.
これは, マークダウンファイルの中から H1 の内容を見つけてそれを フロントマターの aliases
フィールドに追加してくれるというものです.
例えば, ↓のようなマークダウンファイルがあるとします.
# This is a sample file #sample
↓のコマンドを実行します.
obsdconv -src sample.md -dst sample.md -alias
変換後のファイルは↓のようになります.
---
aliases:
- This is a sample file
---
# This is a sample file #sample
このように, H1 の内容から余分なタグなどを取り除いてできた文字列 (ここでは This is a sample file
) がエイリアスとして設定されるわけです.
エイリアスに This is a sample file
があれば, 他のファイルでこのファイルを参照したいときに, [[sample
などと入力すれば, [[211205-235433 | This is a sample file]]
が自動補完されるはずです.
obsdconv
と zettelkasten を使えば, 「ファイル名に日本語やスペースや記号を入れたくないけど, ファイル名どうしようかな」みたいな余計なことは考えずに, 内部リンクの恩恵を受けられるわけです.
Discussion