NDC階層化した辞書サイトをAstroでビルドできるまでの記録

今日は、自作している辞書サイトのビルドがようやく通りました。
ここに至るまで、正直かなり迷子になっていたので、備忘録も兼ねて経緯をまとめておきます。


きっかけは、辞書データの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階層ごとのインデックスページや、検索導線の改善に取り組む予定です。

コメント

タイトルとURLをコピーしました