今日は、自作している辞書サイトのビルドがようやく通りました。
ここに至るまで、正直かなり迷子になっていたので、備忘録も兼ねて経緯をまとめておきます。
きっかけは、辞書データのNDC階層化でした
もともとこの辞書サイトは、Markdownで用語を管理し、Astroで静的サイトとして生成していました。
語数が1000語を超えてきたあたりで、管理や導線の限界を感じ、NDC(日本十進分類法)に基づいてフォルダ階層を整理することにしました。
結果として、Markdownファイルは次のようなパスになりました。
src/content/dictionary/0/00/002/kaigi-saimoku.md
URLもそれに合わせて、
/term/0/00/002/kaigi-saimoku
という多段構造になります。
設計としては筋が良いはずでしたが、ここからが本当の戦いでした。
画像パス問題とOneDriveの罠
最初に詰まったのは、画像参照でした。
- 相対パスで画像を指定していたため
- ファイルをNDC階層に移動した瞬間に
- ImageNotFoundエラーが大量発生
しかも、作業ディレクトリが OneDrive 配下だったため、
PowerShellでの一括置換中に ファイルロックエラーも頻発しました。
最終的に採った方針は、次の3点です。
- 画像はすべて
src/assets/配下で一元管理 - Markdownからは
/assets/...の絶対パスのみ使用 - 画像が存在しない場合は、参照を削除する
このルールに切り替えたことで、画像周りは一気に安定しました。
Astroの動的ルーティングで完全に迷子になる
次に立ちはだかったのが、Astroの動的ルーティングです。
NDC階層をURLに反映したため、
単純な [slug].astro では対応できなくなりました。
ここで学んだ重要なポイントは次の通りです。
- 多段URLは
[...slug].astroを使う getStaticPaths()のparamsは 必ず文字列を返す- Content Collectionsでは
entry.slugではなくentry.idが正
特に、
TypeScript
slug: entry.id.split(“/”)
“
その他の行を表示する
としてしまうと、
Expected a string, received object
というエラーで即落ちます。
正解はこれでした。
TypeScript
slug: entry.id
その他の行を表示する
NDC階層を含んだ文字列そのものを渡し、
ページ側で必要に応じて split("/") します。
entry.render() は存在しない問題
さらに追い打ちをかけてきたのが、TypeScriptエラーでした。
TypeScript
const { Content } = await entry.render();
その他の行を表示する
これは もはや存在しないAPIでした。
Astro Content Collectionsでは、Markdownは事前にレンダリングされており、
本文は entry.rendered.html としてアクセスするのが正解です。
Plain Text
astro は完全にはサポートされていません。構文ハイライトは Plain Text に基づいています。
{entry.rendered?.html && (
<Fragment set:html={entry.rendered.html} />
)}
その他の行を表示する
この修正で、型エラーとビルドエラーが一気に消えました。
そして、ようやくビルドが通った
すべてを直し終え、キャッシュを消してから npm run build。
エラーは出ず、/term/0/00/002/kaigi-saimoku/index.html が無事に生成されました。
正直、この瞬間はかなり嬉しかったです。
振り返り
今回の作業で学んだことは多くありました。
- URL設計とファイル構成は最初に固めるべき
- AstroのContent Collectionsは「便利だがルールが厳密」
- 公式の型定義は、最大のヒント
- エラー文は意外と正直
そして何より、
「全部を一気に直そうとしないで、1エラーずつ潰す」ことの大切さを改めて感じました。
次は、NDC階層ごとのインデックスページや、検索導線の改善に取り組む予定です。


コメント