ログオフ
開発2026-06-20

静的データと DB の二重ソースは、新規の DB 分が一覧から孤児になる

一覧やトップを静的ファイルだけで描き、詳細ページだけ DB を見る構成にすると、DB に足した新規コンテンツがどこからもリンクされず孤児になる。一覧側を静的+DB のマージに寄せて解決する。

DB に新しい記事を足したのに、サイトのどこからもたどり着けない。ページ自体は開けるのに、一覧にもトップにも関連リンクにも出てこない。データソースが二重になっているのが原因だった。

事象

  • DB に追加した新規コンテンツの詳細ページは、直接URLを叩けば開ける
  • だが一覧・トップ・関連リンクのどこにも出てこない
  • 内部リンクが 0 なので、回遊もされないしクローラーにも見つかりにくい

原因

データの読み元が 2 つに割れていた。

  • 一覧・トップ・関連:静的ファイル(例:data/articles.ts)だけを読んで描画
  • 詳細ページ:DB を優先して描画

この構成だと、DB にだけ足した新規分は、詳細ページには存在するのに一覧側の静的データには載っていない。結果、どこからもリンクされない「孤児」になる。

// ❌ 一覧は静的データonlyを読む
import { articles } from '@/data/articles';
export function listArticles() {
  return articles; // DBの新規分が入らない
}

気づきにくいのは、詳細ページが普通に開けてしまうからだ。「ページはあるのに導線がない」状態は、ぱっと見では正常に見える。

解決策

一覧側を「静的 + DB のマージ」に寄せる。小さな fetch ヘルパーにまとめておくと、トップ・一覧・関連・sitemap が同じソースを共有できる。

// ✅ 静的 + DB をマージして返す
export async function fetchAllArticles() {
  const fromDb = await db.getPublishedArticles();
  const merged = new Map<string, Article>();

  // 静的を入れてから DB で上書き(slug衝突は DB 優先)
  for (const a of staticArticles) merged.set(a.slug, a);
  for (const a of fromDb) merged.set(a.slug, a);

  return [...merged.values()].sort(
    (a, b) => +new Date(b.date) - +new Date(a.date)
  );
}

slug がぶつかったら DB を優先、最後に日付の降順で並べる。これで新規 DB 分も一覧に出るし、内部リンクが張られる。

補足

  • sitemap も同じマージ結果から生成する。一覧と sitemap がずれると、片方にしか出ないページが生まれる
  • 「詳細は開けるのに一覧に出ない」は、データソースが割れているサインとして覚えておくといい

※ 本記事にはアフィリエイトリンクが含まれます。

開発 一覧へ