🎉

Zenn-cliで、好きなファイル名と場所で管理したい!ハードリンクで解決?実験してみた

に公開

Zenn CLI、サブディレクトリの記事でFront Matterエラー?なんで?

Zenn と GitHub を連携させて記事を管理してるんだけど、なんか変なエラーが出たんだよね。

articles/Leaning-AI/20250328_001_simple-qa/20250328_001_simple-qa.md の FrontMatter が見つかりませんでした

いやいや、ちゃんと Front Matter 書いてるって!なんで見つからないのさ?
どうも Zenn CLIくんは、articles ディレクトリの 直下 にある <slug>.md っていうファイルしか、記事としてちゃんと見てくれないっぽい…?

こうしたい!Zenn の記事管理

僕としてはさ、記事ファイルはこんな感じで管理したいわけ。

  • 分かりやすいディレクトリ構造 (例: Leaning-AI/テーマごと/)
  • 内容が推測できるファイル名 (例: ステップ1-Gradioで翻訳.md)
  • 画像も記事ファイルと同じフォルダに置きたい

articles ディレクトリを開いたら f367f77c52fb4b.md みたいなランダム文字列のファイルがズラーッと並んでて、「えっと、編集したいのどれだっけ…?」ってなるのは、正直言ってナンセンスだと思うんだよね。Obsidianとかで管理してると特に!

というわけで、なんとかして Zenn CLI を手懐けて、自由なファイル/ディレクトリ管理を実現できないか、ちょっと実験してみることにした!

実験開始!目指せ自由なファイル管理

まずは基本のおさらい。

  1. npx zenn new:article で記事ファイルを作る。今回は slug f367f77c52fb4b ができたとする。
  2. 生成された <slug>.md ファイルの中身(特にFront Matterの slug)を確認。
  3. 記事ファイル自体は、自分が管理しやすいディレクトリに、分かりやすい名前で置く。 (例: articles/articles-test/zenn-ganba.md)

この状態で、Zenn CLI に記事として認識させる方法を探るぞ!

実験1:サブディレクトリ + 自由ファイル名 + slug指定

まず試したのは、分かりやすい場所に置いたファイル (articles/articles-test/test-front-matter.md) の Front Matter に、ちゃんと slug: f367f77c52fb4b を書く作戦。

---
title: "テスト記事"
emoji: "🎉"
type: "tech"
topics: ["zenn-cli","Front Matter","bug","test"]
published: true
slug : "f367f77c52fb4b" # slugはちゃんと書いた!
---

articles ディレクトリの構成はこんな感じ。

% tree articles
articles
├── 8d387a81078462.md # これは元々あったやつ
├── Leaning-AI        # 僕が整理したいディレクトリ
│   └── 20250328_001_simple-qa
│       ├── 20250328_001_simple-qa.md # エラーが出た元ファイル
│       └── images
│           ├── Screen Shot 2025-03-29 at 0.20.54.png
│           ├── Screen Shot 2025-03-29 at 0.49.37.png
│           └── Screen Shot 2025-03-29 at 1.35.08.png
├── articles-test     # 実験用ディレクトリ
│   └── test-front-matter.md # ★今回のテスト対象ファイル
└── bef721a313f5b1.md # これも元々あったやつ

結果は… ダメ! Zenn CLI はこのファイルを記事として認識してくれなかった。うーん、やっぱり articles 直下じゃないとダメなのか…?

実験2:サブディレクトリ + slugファイル名

じゃあ、サブディレクトリの中でもファイル名を <slug>.md (f367f77c52fb4b.md) にしたらどうだ?

% mv articles/articles-test/test-front-matter.md articles/articles-test/f367f77c52fb4b.md
% tree articles
articles
├── 8d387a81078462.md
├── Leaning-AI
│   └── 20250328_001_simple-qa
│       ├── 20250328_001_simple-qa.md
│       └── images
│           ├── Screen Shot 2025-03-29 at 0.20.54.png
│           ├── Screen Shot 2025-03-29 at 0.49.37.png
│           └── Screen Shot 2025-03-29 at 1.35.08.png
├── articles-test
│   └── f367f77c52fb4b.md # ★ファイル名をslugにした!
└── bef721a313f5b1.md

結果… zennの連携ページ で「更新されたファイルはありません」的なメッセージ。これもダメ! 悲しい…。やっぱり articles直下 にないとダメっぽいな。

実験3:シンボリックリンクで偽装作戦!

こうなったら、articles ディレクトリ直下に「見せかけ」のファイルを作ってやろう! シンボリックリンクの出番だ。

まず、実験用のファイル名を分かりやすい zenn-ganba.md に戻して、articles 直下に <slug>.md という名前でシンボリックリンクを貼ってみる。

# まずファイル名を戻す
% mv articles/articles-test/f367f77c52fb4b.md articles/articles-test/zenn-ganba.md
# シンボリックリンク作成! articles 直下に f367f77c52fb4b.md というリンクを作る
% ln -s articles-test/zenn-ganba.md articles/f367f77c52fb4b.md

ディレクトリ構造はこうなったはず。

% tree articles
articles
├── 8d387a81078462.md
├── Leaning-AI
│   └── 20250328_001_simple-qa
│       ├── 20250328_001_simple-qa.md
│       └── images
│           ├── Screen Shot 2025-03-29 at 0.20.54.png
│           ├── Screen Shot 2025-03-29 at 0.49.37.png
│           └── Screen Shot 2025-03-29 at 1.35.08.png
├── articles-test
│   └── zenn-ganba.md # ★本体ファイルはここ
├── bef721a313f5b1.md
└── f367f77c52fb4b.md -> articles-test/zenn-ganba.md # ★articles直下にリンク!

これでどうだ! articles 直下に <slug>.md があるように見えるだろ!

…と思ったら、また あのエラー が!!

articles/f367f77c52fb4b.md の FrontMatter が見つかりませんでした

なんでやねん! リンク先にはちゃんと Front Matter あるのに!
うーん、シンボリックリンクだと、リンク先のファイルの中身(Front Matter)までは見てくれないのかな…?

実験4:最終手段?ハードリンク!

シンボリックリンクがダメなら、もう一つのリンク、ハードリンク ならどうだ?
ハードリンクは、ファイルの実体(データ)に対して別の名前をつけるような仕組みだったはず。これなら Zenn CLI も騙されてくれるかも?

# まずさっきのシンボリックリンクを削除
% rm articles/f367f77c52fb4b.md
# 今度こそ!ハードリンクを作成!
% ln articles/articles-test/zenn-ganba.md articles/f367f77c52fb4b.md

ディレクトリ構造はシンボリックリンクの時と似てるけど、-> がないのがハードリンクの特徴だね。

% tree articles
articles
├── 8d387a81078462.md
├── Leaning-AI
│   └── 20250328_001_simple-qa
│       ├── 20250328_001_simple-qa.md
│       └── images
│           ├── Screen Shot 2025-03-29 at 0.20.54.png
│           ├── Screen Shot 2025-03-29 at 0.49.37.png
│           └── Screen Shot 2025-03-29 at 1.35.08.png
├── articles-test
│   └── zenn-ganba.md # ★本体ファイル
├── bef721a313f5b1.md
└── f367f77c52fb4b.md # ★articles直下にハードリンク!

これで zennの連携ページ をチェックしてみると…

おっしゃー!動いた!!

エラーが出ずに、ちゃんと記事として認識された! articles 直下にハードリンクで作った <slug>.md があれば、本体のマークダウンファイルがサブディレクトリにあっても、Zenn CLI は記事として読んでくれるみたいだ!

まとめ:ハードリンクで自由を手に入れる(かも)

というわけで、今回の実験で分かったこと。

  1. Zenn CLI は(今のところ?)articles ディレクトリ 直下 にある <slug>.md ファイルしか記事として認識してくれないっぽい。
  2. サブディレクトリに置いたファイルは、ファイル名が <slug>.md でも、Front Matter に slug を書いてもダメ。
  3. articles 直下に シンボリックリンク (<slug>.md) を置いてもダメ。(Front Matter が見つからないエラー)
  4. articles 直下に ハードリンク (<slug>.md) を置き、リンク先をサブディレクトリ内の本体ファイルにすれば 認識される!

これで、僕がやりたかった 「ファイル自体は分かりやすい場所と名前で管理しつつ、Zenn CLI にも記事として認識させる」 ことが実現できそうだ! これなら Obsidian での管理も捗るぞ!

今後の記事執筆フローはこんな感じかな。

  1. 好きな場所に好きな名前で .md ファイルを作る。
  2. npx zenn new:article を実行して slug を生成する。
  3. 作った .md ファイルの Front Matter に生成された slug を書く。
  4. articles ディレクトリ直下に、ln <本体ファイルのパス> articles/<生成されたslug>.md コマンドでハードリンクを作成する。
  5. Git に push!

これで快適 Zenn ライフが送れる…はず!

ただ、一つ気になるのは 画像 の扱いだよね。記事ファイルと同じ場所に画像を置いて、相対パスで ![alt](./images/hoge.png) みたいに書きたいけど、ハードリンクで articles 直下から参照されるとパスがずれちゃう問題が起きそう…。

そしてハードリンクって別のPCでgit cloneしてもそのまま機能したっけ?
ただの別々のファイルになってしまうようなら、この作戦も失敗になるな。。。
考えたくないな。後で試そう。

まぁ、画像問題はまた別の機会に考えることにしよう。うん、そうしよう。
とりあえず、ファイル管理の自由度は少し上がったぞ!

Discussion