生成対象から外したページが残る

静的サイトのbuildが既存フォルダへページを一枚ずつ書き足すだけだと、ソースからページを削除しても、以前に生成されたHTMLが出力先に残ることがあります。たとえばold-page/index.htmlを生成対象から外しても、新しい一覧からリンクが消えるだけで、出力フォルダにファイルが残る可能性があります。

このサイトのルートは配列で定義し、buildが各ページのHTMLと画像・スタイルなどのassetsを出力します。更新では「現在の全ルートを含む新しい出力一式を作り、その一式に置き換える」形をとり、ルート配列に含まれないHTMLを次の出力から取り除きます。

出力の更新方法を比べる

表は横にスクロールできます。

方法よい点注意点
既存フォルダへ上書き処理が単純で、毎回同じ出力先を使える新しい生成対象にない古いファイルを残しやすい
出力先を先に削除して再生成古いページが残らないbuild途中で失敗すると、前回の正常な出力も失う
別の場所で一式を作り置き換える生成中は現行出力を保持し、完了後に一式を切り替えられる同じファイルシステム上でのrenameと、置き換え時の復旧が必要

このサイトでは、前回の出力を残したまま生成できる三つ目の方法を選びました。上書きだけでは古いファイルを残しやすく、先に削除する方法では生成失敗時に確認できるページも失うためです。

新しい出力一式へ入れ替える

replaceBuildOutputは出力種別をdistreleaseに限定し、対象をプロジェクト直下のフォルダだけに絞ります。対象がシンボリックリンクや通常ファイルなら処理を止めます。build関数には一時フォルダを渡し、ページ、画像、スタイル、robotsやsitemapを含む新しい一式をそこへ書き出します。

  1. 一時出力を作る

    同じプロジェクト内に一時フォルダを用意し、今回の全ファイルを書きます。生成に失敗した場合はこの途中ファイルを消し、以前の出力には手を触れません。

  2. 既存の出力を退避する

    生成が完了したら、前回のdistまたはreleaseを一時的な退避先へ名前変更します。

  3. 新しい一式に切り替える

    完成した一時フォルダを出力先の名前へ変更し、成功した後で退避した古い一式を削除します。新しい出力へ旧HTMLや旧assetsをコピーしないため、現在の生成対象だけが残ります。

前回フォルダの退避と新フォルダの配置は別々のrename処理です。一つの原子的な置き換えや、配信を止めずに必ず切り替わる保証とは説明しません。

残存ファイルがないか確かめる

確認用テストは、旧ページ・旧アセットが新出力からなくなり、別の出力種別やソースファイルがそのままであることを確認します。レンダーが途中で失敗するケースでは、前回の完成出力が残り、途中の一時フォルダが取り除かれることを検査します。初回出力と連続する2回の出力、許可されないパスやファイルが出力名にある場合も確かめます。

  1. サンプルを決めた配置で保存

    出力切替モジュールを作業フォルダへ、テストをその中のtestsフォルダへ置きます。

  2. Node.js標準テストを動かす

    Node.js 24系を用意し、作業フォルダでnode --test --test-isolation=none tests/build-output.test.mjsを実行します。追加パッケージのインストールは不要です。

  3. テスト結果を読む

    旧ファイルの除去、失敗時の前回出力保持、初回・再実行、危険な出力先の拒否を個別に確認します。

Node.js v24.19.0で出力切替テスト4件が成功しました。これは一時フォルダ内のモジュール単体テストであり、サイト全体のbuild/check結果やホスティング先の更新を表すものではありません。

入れ替え処理の限界

テストが再現するのは、一つのローカルな一時プロジェクト内のファイル入れ替えです。前回出力の保持を確かめるテストはrender関数の失敗を使い、退避後の二つ目のrename自体を失敗させるシミュレーションまでは含みません。rename間に出力先が一時的に存在しない時間もあり得るため、無停止配信や複数プロセス間の同時切り替え保証ではありません。

ローカル生成物を入れ替える検証は、ホスティング先へのアップロード、CDNキャッシュや別の公開コピーの削除を確認するものではありません。公開先の更新と旧URLの扱いは別途確認します。

実装とテスト

  • build.mjs — ページルート・HTML・assetsを構成。
  • build-output.mjs — 出力一式を準備し、入れ替える処理。
  • tests/build-output.test.mjs — 正常時・失敗時の出力更新を検査。

テストには一時ディレクトリを作り、各ケースの後で範囲内を削除するfixtureがあります。実際の公開用ファイルや既存のdist/releaseを変更せずに、入れ替え動作を検査します。