生成対象から外したページが残る
静的サイトのbuildが既存フォルダへページを一枚ずつ書き足すだけだと、ソースからページを削除しても、以前に生成されたHTMLが出力先に残ることがあります。たとえばold-page/index.htmlを生成対象から外しても、新しい一覧からリンクが消えるだけで、出力フォルダにファイルが残る可能性があります。
このサイトのルートは配列で定義し、buildが各ページのHTMLと画像・スタイルなどのassetsを出力します。更新では「現在の全ルートを含む新しい出力一式を作り、その一式に置き換える」形をとり、ルート配列に含まれないHTMLを次の出力から取り除きます。
出力の更新方法を比べる
表は横にスクロールできます。
| 方法 | よい点 | 注意点 |
|---|---|---|
| 既存フォルダへ上書き | 処理が単純で、毎回同じ出力先を使える | 新しい生成対象にない古いファイルを残しやすい |
| 出力先を先に削除して再生成 | 古いページが残らない | build途中で失敗すると、前回の正常な出力も失う |
| 別の場所で一式を作り置き換える | 生成中は現行出力を保持し、完了後に一式を切り替えられる | 同じファイルシステム上でのrenameと、置き換え時の復旧が必要 |
このサイトでは、前回の出力を残したまま生成できる三つ目の方法を選びました。上書きだけでは古いファイルを残しやすく、先に削除する方法では生成失敗時に確認できるページも失うためです。
新しい出力一式へ入れ替える
replaceBuildOutputは出力種別をdistかreleaseに限定し、対象をプロジェクト直下のフォルダだけに絞ります。対象がシンボリックリンクや通常ファイルなら処理を止めます。build関数には一時フォルダを渡し、ページ、画像、スタイル、robotsやsitemapを含む新しい一式をそこへ書き出します。
- 一時出力を作る
同じプロジェクト内に一時フォルダを用意し、今回の全ファイルを書きます。生成に失敗した場合はこの途中ファイルを消し、以前の出力には手を触れません。
- 既存の出力を退避する
生成が完了したら、前回の
distまたはreleaseを一時的な退避先へ名前変更します。 - 新しい一式に切り替える
完成した一時フォルダを出力先の名前へ変更し、成功した後で退避した古い一式を削除します。新しい出力へ旧HTMLや旧assetsをコピーしないため、現在の生成対象だけが残ります。
前回フォルダの退避と新フォルダの配置は別々のrename処理です。一つの原子的な置き換えや、配信を止めずに必ず切り替わる保証とは説明しません。
残存ファイルがないか確かめる
確認用テストは、旧ページ・旧アセットが新出力からなくなり、別の出力種別やソースファイルがそのままであることを確認します。レンダーが途中で失敗するケースでは、前回の完成出力が残り、途中の一時フォルダが取り除かれることを検査します。初回出力と連続する2回の出力、許可されないパスやファイルが出力名にある場合も確かめます。
- サンプルを決めた配置で保存
- Node.js標準テストを動かす
Node.js 24系を用意し、作業フォルダで
node --test --test-isolation=none tests/build-output.test.mjsを実行します。追加パッケージのインストールは不要です。 - テスト結果を読む
旧ファイルの除去、失敗時の前回出力保持、初回・再実行、危険な出力先の拒否を個別に確認します。
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を変更せずに、入れ替え動作を検査します。