[Astro #02] 500件の記事移行とトラブル対処:カテゴリー統合とMDXエラー

はじめに

Astroへの移行作業の備忘録メモ。

前回の記事:

スクリーンショット:

動画(PC):

1. 情報アーキテクチャの再定義:10のプロトコル

1.1 カテゴリーから「プロトコル」への進化

以前の環境(Hugo)では、その場の直感で増やしてきたカテゴリーが80種類以上に達していました。これは「検索性」を著しく損なうだけでなく、サイト全体のアイデンティティをぼやけさせる要因でした。

今回の移行では、カテゴリーを単なる分類項目ではなく、「lainというシステムを構成する通信プロトコル」と定義し、以下の10項目に絞り込みました。

プロトコル名 統合された主な旧カテゴリ 役割と設計思想
💻 DEV_CODE JavaScript, React, CSS, Web制作 プログラミング実務と技術解説の核。
🧠 HUMAN_X_AI ChatGPT, AIアート, LLM, 自動化 人間とAIの境界線を探る、当サイトの最重要課題。
📐 MATH_PROX 数学, ノイズ, プロシージャル 「Noise 入門」等、論理と数式による表現。
🎮 CREATIVE_3D Unity, Three.js, Babylon.js 空間構築とインタラクティブ性の記録。
💾 RETRO_LOG MSX, C64, SID音源, エミュレータ デジタル考古学。過去の技術への敬意。
⚖️ PHILOSOPHY 実存主義, サルトル, 自己探求 技術の根底にある「なぜ」を問う思考。
📝 TECH_CULTURE 開発者伝説, ガジェット, 考察 技術を取り巻く文化や歴史のログ。
🛠️ TOOLS_SYSTEM Git, VS Code, Linux, Astro 開発環境そのものを磨くための記録。
🎨 CREATIVE_ART イラスト, 創作, デザイン 視覚的なアウトプット全般。
📁 OTHER_LOGS 雑記, 日記, 未分類 既存の枠に収まらない「予備」の領域。

1.2 Node.jsによる一括置換処理

532件のMDXファイルを一つずつ手作業で書き換えるのは現実的ではありません。そこで、以下のロジックで動作する「カテゴリー・リマッパー・スクリプト」を自作し、一気にクレンジングを行いました。

  • マッピング辞書の定義: 80の旧カテゴリを10の新プロトコルへ紐付けるMapを作成。
  • Frontmatterの解析: gray-matter ライブラリを使用し、各ファイルの categories フィールドを抽出。
  • 一括置換: 旧カテゴリが含まれている場合、対応する新プロトコルへ書き換え。重複は排除。
  • フォールバック: 該当しないマイナーなカテゴリーは自動的に 📁 OTHER_LOGS へ収容。

1.3 「1件のみ」のカテゴリーの救済

統計をとった結果、記事数が1件しか存在しない「孤立カテゴリー」が全体の約40%を占めていました。 これらはサイドバーに表示される際、UIを煩雑にするだけの「ノイズ」となるため、あえて独立させず、上位概念のプロトコルに内包させることで、「情報の密度」を均一化しました。

インサイト:
この整理により、サイドバーの「件数表示」が、lainさんの現在の関心事(DEV_CODEやHUMAN_X_AIの圧倒的な多さ)を視覚的に正しく反映するようになりました。

2. MDXパースエラーの自動回避(波括弧エスケープ)

2.1 MDXの仕様という名の「罠」

MDXは Markdown の中に JSX を記述できる強力なフォーマットですが、標準の挙動として「本文中の { } をJavaScriptの式(Expression)として評価しようとする」性質があります。

  • 問題の例: 「座標オブジェクト { x: 0, z: 0 } を定義します」という一文。
  • MDXの解釈: 「x: 0, z: 0 というJSを実行しよう」とする → 構文エラー(Syntax Error)でビルド停止。

特にプロシージャル生成やアルゴリズムを扱う記事では、地の文でデータ構造を説明する際に波括弧が頻出するため、532件のうち相当数が「地雷原」と化していました。

2.2 スクリプトによる「外科的エスケープ」のロジック

手作業での修正を諦め、Node.jsによる一括変換スクリプトを実装しました。この処理で最も重要だったのは「コードブロック内(```)は無視し、地の文だけを書き換える」という精密さです。

処理のフロー:

  1. Frontmatterの保護: gray-matter等で記事本文(Content)のみを抽出。
  2. コードブロックの退避: 正規表現で ``` で囲まれた部分を一時的に変数に退避させ、変換対象から除外。
  3. 実体参照への置換:
    • { → {
    • } → }
  4. 結合: 退避させていたコードブロックを元に戻し、ファイルを保存。

技術的ポイント:
HTML実体参照(Entity Reference)に変換することで、ブラウザ上では正しく { } と表示されつつ、MDXのパーサー(compiler)はこれをJSの式として認識しなくなるため、安全にビルドをパスできます。

2.3 「Noise 入門」シリーズでの効果

この処理が最も威力を発揮したのは、lainさんのライフワークである「Noise 入門」のアーカイブです。

  • Before: Math.floor({val} * 255) のような記述が随所にあり、ビルド時に「val is not defined」等のエラーを連発。
  • After: Math.floor({val} * 255) となり、Astroはこれを単なる文字列として扱い、表示上は完璧な技術解説として復元。

2.4 自動化による副産物

このスクリプトを構築したことで、今後新しい記事を書く際も「MDXの仕様を気にして書き方を変える」必要がなくなりました。「自由に書き、ビルド前にスクリプトを通す」というワークフローが確立されたのは、中長期的なメンテナンスにおいて大きな勝利と言えます。

3. データクレンジングと整合性チェック

3.1 Viteによる「アセット参照の厳格化」への対応

Astro(Vite)は、フロントマターに記載された画像パスを単なる「文字列」としてではなく、ビルド時に最適化すべき「リソース(モジュール)」として扱おうとします。

  • 旧環境の問題: Hugoでは画像パスが空だったり、拡張子(.webp)しか書かれていなくても、実行時に404エラーが出るだけでビルド自体は通っていました。
  • 新環境の挙動: Viteは「.webpという名前のファイルが見つからない」と判断した時点で、ビルドプロセスを即座に強制終了(Fatal Error)させます。

532件の中に潜んでいた「画像パスの記述不備」が、システム全体のデプロイを阻む大きな壁となっていました。

3.2 ターミナルの悲鳴:2つのエラーファイルの特定

ビルドログに残されたスタックトレースを解析し、ビルドを停止させていた「汚染ファイル」を特定しました。

  1. 特定手法: astro build を実行し、Viteがエラーを吐いた箇所のファイルパスを特定。
  2. 不備の内容: フロントマターの image: 項目が .webp という拡張子のみの文字列になっており、実体ファイルが存在しない状態でした。
  3. 処置: 記事自体の価値と整合性を天秤にかけ、不完全なデータとしてこれら2件をアーカイブから除外(または修正)。

このプロセスにより、ビルド時に赤字で表示されるエラーメッセージが消え、安定したデプロイ環境が構築されました。

3.3 532件の「純粋なデータベース」の誕生

最終的に、532件のMDXファイルがAstroのコンテンツコレクション(Content Collections)として正しく認識されました。

  • スキーマ定義の適用: Astroの src/content/config.ts で定義した厳格なZodスキーマ(タイトル、日付、カテゴリ、タグの型チェック)を全てのファイルがパスしている状態です。
  • データとしての再定義: これにより、単なるテキストファイルの集まりが、プログラムから型安全(Type-Safe)に呼び出せる「純粋なデータベース」へと変貌を遂げました。

インサイト:
532件という数字は、単なる記事件数ではありません。それは「lainというシステム」が現在保有している、エラーのない、クリーンな思考の断片の総数なのです。

4. UI/UX:ターミナル・ミニマリズムの実装

データの正常化という「裏側」が整い、いよいよユーザーの目に触れる「インターフェース」に魂を吹き込むフェーズです。

今回のUI刷新のテーマは、装飾を削ぎ落とし、純粋にデータと対話するための「ターミナル・ミニマリズム」。

4.1 視覚的拡張:95vw の地平線

一般的なブログレイアウトによく見られる「中央に細長く配置されたコンテンツエリア」をあえて放棄しました。

  • 設計思想: ターミナル(コンソール)画面がそうであるように、情報は画面の端から端まで広がるべきであるという考えから、max-width: 95vw を採用。
  • 効果: サイドバーと記事リストが横に広く並ぶことで、視線の移動距離を最適化。532件という膨大なリストをスクロールする際の「圧迫感」を「情報の広野」へと変貌させました。

4.2 データ構造の可視化:進化したブログカード

個々の記事カードは、もはや単なる「リンク」ではなく、「データのメタ情報(プロパティ)を表示するセル」として再設計されました。

  • 1行レイアウトの採用: カード下部に CATEGORY(左)と TAGS(右)を対極に配置。
  • 英語ラベルへの統一: カテゴリー ではなく CATEGORY、タグ ではなく TAGS。言語を英語に寄せることで、システムログのような硬質でプロフェッショナルな質感を演出しています。
  • 情報の階層化: ユーザーが「どの領域(プロトコル)の、どの技術(タグ)について」語っているのかを一目で判別できる、高い視認性を実現しました。

4.3 システムの心拍:動的集計サイドバー

532件の記事から、現在のカテゴリー分布をリアルタイムに抽出するロジックを実装しました。

  • リアルタイム・カウント: Astroの getCollection APIを利用し、ビルド時に全記事のフロントマターを走査。カテゴリーごとの投稿数を動的に集計します。
    • 例: 💻 DEV_CODE (221)
  • フィルタリング・プロトコル: サイドバーのカテゴリーをクリックすることで、瞬時にそのプロトコルに属する記事のみが抽出される仕組み。
  • 実装の意義: 自分の活動がどの分野に偏っているのか、あるいはどの分野が成長しているのかを、lainさん自身が「システムの管理者」として俯瞰できるようになりました。

インサイト: このUIは、単なる「ブログ」ではなく、lainさんの脳内ライブラリにアクセスするための「ダッシュボード」に近い存在です。装飾を排し、データそのものをデザインの主役に据えることで、532件のアーカイブは「過去の遺産」から「現役のデータベース」へと昇華されました。

5. 開発環境(VS Code)の強化

5.1 MDX for Visual Studio Code:構文の「視覚化」と「防護」

MDXは Markdown と JSX が混在する特殊なフォーマットです。標準のエディタ設定では、セクション2で触れた「波括弧」などの特殊な構文が正しく認識されず、記述ミスを見逃すリスクがありました。

  • シンタックスハイライトの覚醒: Markdownの文章構造と、JSXのロジック部分を明確に色分け。これにより、地の文に紛れ込んだ「予期せぬJS式」を即座に視認できるようになりました。
  • インテリセンス(補完)の恩恵: コンポーネントのプロパティや、フロントマターの型定義に基づいた補完が効くようになり、532件の記事をリファクタリングする際のタイポ(入力ミス)を激減させました。

5.2 Astro Essentials Extension Pack:Astro専用のOSを組み込む

Astro独自の .astro ファイルやプロジェクト構造を扱うための「標準装備」です。これがあることで、VS CodeはAstroプロジェクトの「意図」を理解します。

  • Language Server Protocol (LSP): src/content/config.ts で定義したスキーマと連動。フロントマターに不備があればエディタ上で赤線が走り、ビルド前に「未然にエラーを防ぐ」体制が整いました。
  • コンポーネントの高速移動: 記事内で使用している独自コンポーネント(例えば、特別なスタイルの引用やブログカード)の定義場所へ、ショートカット一つでジャンプ。開発の「手数を減らす」ための必須装備です。

5.3 532件を支える「インフラとしてのVS Code」

今回、これらの拡張機能を導入した最大の目的は、「メンテナンスコストの最小化」です。

  • スケーラビリティの確保: 10件の記事なら手作業で目視確認できますが、532件では不可能です。ツールの力で「機械的に正しさを保証」する仕組みを作ったことが、今回の環境構築における真の勝利と言えます。
  • Gitとのシナジー: GitLens 等を併用することで、膨大なアーカイブの中で「いつ、どの記事に外科手術(リファクタリング)を施したか」の履歴が、ターミナル感あふれるUIで可視化されました。

インサイト:
これで、lainさんの手元には「532件の記憶を、安全かつ高速に編集・拡張するためのコックピット」が完成しました。赤いデバッグ境界線が走るブラウザ画面と、完璧にハイライトされたエディタ。この対比こそが、現在の「構築中」の美学を支えています。