ToolArc

ブログ記事

  • Next.js
  • series.ts
  • サイト運用
  • Git
  • TypeScript
  • ワークフロー

series.tsのシリーズ判定は先勝ち|移管は同一コミットで完結させる

"Next.jsのブログでシリーズ(Hub/Spoke)をlib/series/series.tsで管理していると、記事のシリーズ移管時に二重所属が静かに起きることがあります。getSeriesForPostが先勝ち仕様であるため、移管は同一コミットで完結させる実装ノウハウを解説します。"

toolarc.jp では、記事がどのシリーズ(Hub/Spoke)に属するかを lib/series/series.ts の配列で管理しています。ある記事を別のシリーズへ移管する作業をしていたとき、「旧シリーズから外す変更」と「新シリーズへ入れる変更」を別々のコミットに分けてしまい、意図しない二重所属の状態を一時的に作ってしまったことがあります。

厄介なのは、この状態になってもビルドはエラーを出さないという点です。原因は、シリーズ判定に使っている関数が「先勝ち」の仕様になっているためでした。

この記事では、同じ仕組みでシリーズ機能を自作している方向けに、なぜ二重所属が静かに起きるのか、どう対策すればよいかを1分で整理します。

今日の結論

  • シリーズ判定の関数(getSeriesForPost 相当)は、配列の先頭から探して最初に一致したシリーズを返す「先勝ち」仕様になりやすい
  • 同じslugが旧・新2つのシリーズ配列に同時に含まれていても、エラーにはならず、どちらか一方が静かに採用される
  • シリーズ移管は「旧配列から外す」「新配列へ入れる」を同一コミットで完結させると、この状態自体が発生しない
  • npm run build 前に、対象slugが1シリーズだけに含まれることを確認する習慣をつける

問題|なぜ二重所属が静かに起きるのか

シリーズ判定の関数は、多くの場合こういった実装になります(toolarc.jp の実コードに近い形です)。

export function getSeriesForPost(postSlug: string) {
  return (
    allSeries.find(
      (s) =>
        s.hubSlug === postSlug || s.spokeSlugOrder?.includes(postSlug),
    ) ?? null
  );
}

Array.prototype.find は、条件に一致する最初の要素が見つかった時点で探索を終えます。そのため、あるslugが allSeries の複数のシリーズの spokeSlugOrder に含まれていても、例外は発生せず、配列内で先に定義されているシリーズだけが返ります。

これが「先勝ち」仕様です。普段は1つのslugが1つのシリーズにしか属さないため問題になりませんが、移管作業中に一時的な二重所属が生まれると、以下のようなことが起こります。

  • ビルドは正常に成功する(エラーが出ないため気づきにくい)
  • 表示されるシリーズが、意図した新シリーズではなく旧シリーズのままになる(配列の並び順次第)
  • レビューで見た目上は問題なく見えるため、そのまま公開されてしまう可能性がある

対策|移管は同一コミットで完結させる

二重所属の状態そのものを作らないようにするのが、もっとも確実な対策です。

  1. 移管対象のslugを洗い出し、旧シリーズの spokeSlugOrder 配列から削除する差分を用意する
  2. 新シリーズの spokeSlugOrder 配列への追加を、同じ変更セット(同一コミット) に含める
  3. 差分を分割コミットにせず、1回のコミットで「旧から外す」「新へ入れる」を完結させる

途中経過をコミットに残したい場合でも、少なくとも main へマージするタイミングまでには、この2つの変更が1つのまとまりとして反映されるようにします。

確認|build前に所属シリーズを1つに絞る

コミット前に、対象slugが1シリーズだけに含まれているかを確認します。

grep -rn "<対象slug>" lib/series/series.ts

出力が1シリーズ分(1箇所)だけであることを確認してから npm run build を実行すると、先勝ち仕様による見えない不整合を防げます。複数箇所にヒットした場合は、コミットする前にどちらか一方に絞り込みます。


確認チェックリスト

  • □ 移管対象のslugを洗い出した
  • □ 旧シリーズ配列からの削除と、新シリーズ配列への追加を同一コミットに含めた
  • □ コミット前に grep で対象slugのヒット数が1箇所だけであることを確認した
  • npm run build が正常に完了し、想定したシリーズ(Hub)側に表示されることを確認した

まとめ・次に読む

Array.prototype.find を使ったシリーズ判定は、実装としてはシンプルですが「先勝ち」であるがゆえに、移管作業を分割コミットにすると不整合が静かに発生します。旧から外す・新へ入れるを同一コミットにまとめ、build前に対象slugの所属を1箇所だけに絞ることで防げます。

サイト構築・運用まわりの実測ログは、シリーズのHub記事 AI初心者がゼロからWebサイトを公開するまでにやったこと・詰まったこと全部まとめ にまとまっています。

同日公開の関連記事: Cursor Agentが意図せず編集したときはgit restoreで戻す


※ 本記事の内容は執筆時点(2026-07-17)の実装・運用ノウハウです。lib/series/series.ts の実装は今後変更される可能性があるため、実際の挙動は都度リポジトリのコードでご確認ください。