夕方のオフィスで、受話器を肩に当てながらモニターの崩れたWeb画面を見つめ、自分の画面では直っているのにと戸惑っている保守運用の担当者

JS・CSSが反映されない|キャッシュバスティングの仕組みと手順

「ボタンの位置、直したって聞いたんですけど、まだずれてますよ」

CSSを1行直してリリースして、自分のブラウザでは確かに直っている。なのに、問い合わせの電話の向こうでは崩れたまま。「お手数ですが、Ctrl+F5で再読み込みしていただけますか」とお願いして、その場はなんとか収まる——こんなやり取り、覚えがありませんか。

これは作業ミスではありません。ブラウザやCDNが、前に読んだJS・CSSをちゃんと覚えているから起きることです。キャッシュは表示を速くするための大事な仕組みなので、止めてしまうのは得策ではありません。必要なのは、「新しい版が出たよ」とブラウザに気づいてもらう仕掛けのほうです。

この記事では、その仕掛け=キャッシュバスティングを、一人運用でも続けられる手順に分けて一緒に整理していきます。

結論:やることは3つです。①HTMLは「毎回確認」、JS・CSSは「長く覚えてよい」と、キャッシュの持たせ方を分ける、②JS・CSSを変えたら、ファイル名かURLが変わるようにする(app.3f9a1c.css や app.css?v=20261002 など)、③反映の確認は自分のブラウザではなく、HTMLが新しいURLを指しているかで確かめる。利用者に再読み込みをお願いしなくても、次にページを開いた時点で新しいJS・CSSが届くようになります。

なお、設定の書き方はWebサーバー・CDN・フレームワークやそのバージョンで違います。ここで挙げる例は考え方をつかむためのものなので、検証環境で挙動を確かめてから本番に入れてください。

何が起きているのか:ブラウザは「URLが同じなら同じファイル」と考える

ブラウザは、一度読み込んだJS・CSS・画像を手元に保存しておき、次に同じURLを見に行くときはそれを使います。サーバーが返す Cache-Control ヘッダーで「何秒まで覚えていてよいか」(max-age)が指定されていれば、その間はサーバーに問い合わせすらしないことがあります。

つまり、こういうことが起きます。

あなたのブラウザで直って見えるのは、開発中に何度も再読み込みしていたり、開発者ツールでキャッシュを無効にしていたりするからです。自分の画面が正しくても、利用者の画面が同じとは限らない。ここが、この問題のいちばん分かりにくいところです。

CDNやリバースプロキシを挟んでいる場合は、ブラウザの手前にもう1か所「覚えている場所」があります。古い値がどこに残るかを順番に切り分ける方法は「直したのに直らない」を切り分ける|キャッシュを疑う順番でまとめているので、いま目の前で起きている問題の調査はそちらも合わせて見てみてください。この記事では、そもそも次から起きにくくする側の手順を扱います。

手順1:HTMLとJS・CSSで、キャッシュの持たせ方を分ける

左側にHTMLのページが毎回サーバーへ確認に行く様子、右側にファイル名に印のついたJS・CSSのファイルがブラウザの棚に長く保管されている様子を並べた図
HTMLは「毎回確認」、名前が変わるJS・CSSは「長く覚えてよい」。この分け方が、キャッシュバスティングの土台になる

最初に決めるのは、ファイルの種類ごとに、どれくらい覚えておいてもらうかです。考え方はシンプルで、2種類に分けます。

nginxなら、たとえばこんな形です。

# HTMLは毎回確認してもらう
location ~* \.html$ {
    add_header Cache-Control "no-cache";
}

# ビルドツールが出力する、ファイル名にハッシュが入ったJS・CSSの置き場は長く覚えてもらう
location /assets/ {
    add_header Cache-Control "public, max-age=31536000, immutable";
}

ここで大切なのは、長く覚えてもらう指定は「名前が変わる仕組み」とセットで入れることです。名前が変わらない style.css に1年の指定を付けると、かえって反映されない期間が長くなってしまいます。まずは今の設定を確かめるところから始めましょう。

# いまJS・CSS・HTMLにどんなキャッシュ指定が付いているかを見る
curl -sI https://example.com/ | grep -i -E "cache-control|etag|last-modified"
curl -sI https://example.com/css/style.css | grep -i -E "cache-control|etag|last-modified"

PHPなどでHTMLをアプリが出している場合は、Webサーバーではなくアプリやフレームワーク側でヘッダーを付けていることもあります。どこで付いているかを一度たどっておくと、あとで迷いません。

手順2:JS・CSSを変えたら、URLが変わるようにする

ここが本題です。キャッシュバスティングとは、中身を変えたときにURLも変えて、ブラウザに「これは初めて見るファイルだ」と思ってもらうことです。やり方は大きく3つあります。自分の現場に合うものを1つ選べば十分です。

やり方A:ビルドツールでファイル名にハッシュを入れる(いちばん手堅い)

ViteやwebpackなどのビルドツールでJS・CSSをまとめている現場なら、中身から計算したハッシュをファイル名に入れる機能があります。Viteは本番ビルドで標準的に assets/index-BkYZ3a8q.js のような名前を出力し、HTML内の参照も自動で書き換えてくれます。webpackなら出力名に [contenthash] を指定します。

中身が変わればハッシュが変わり、変わらなければ同じ名前のまま。変えたファイルだけが新しく読み込まれ、変えていないファイルはキャッシュがそのまま効くので、いちばん無駄がありません。

すでにビルドツールを使っているのに、設定でハッシュを外している現場もあります。まずは出力されたファイル名を見てみてください。

やり方B:URLにバージョンを付ける(ビルドツールがない現場で)

ビルドツールがなく、HTMLやテンプレートに <link> を直接書いている現場では、URLの後ろにバージョンを付ける方法が手軽です。

<link rel="stylesheet" href="/css/style.css?v=20261002">
<script src="/js/app.js?v=20261002"></script>

数字を手で書き換えると、ほぼ確実に「上げ忘れ」が起きます。PHPのテンプレートなら、ファイルの更新時刻を自動で付けると手間がなくなります。

<?php $v = filemtime(__DIR__ . '/css/style.css'); ?>
<link rel="stylesheet" href="/css/style.css?v=<?= $v ?>">

ただし、この方法には気をつけたい点が2つあります。

やり方C:ファイル名そのものを変える

style.css を style.v2.css にする、のようにファイル名を手で変える方法もあります。仕組みはいらない一方で、参照している箇所をすべて書き換える必要があり、書き換え漏れが起きやすいやり方です。ほかの2つが難しいときの、一時的な手段と考えておくのがよいと思います。

古いファイルはすぐに消さない

ファイル名を変える方式(AとC)では、リリース直後に古いファイルを消さないようにしておきます。古いHTMLを開いたままの利用者や、CDNにまだ古いHTMLが残っている間は、古いJS・CSSを読みに来るからです。消してしまうと、その間だけ画面が崩れたり、ボタンが動かなかったりします。「次のリリースのときに、前々回の分を消す」くらいの間隔で十分です。

手順3:反映の確認は「HTMLが新しいURLを指しているか」で見る

リリースしたら、確認です。ここでも、自分のブラウザで見て直っていれば完了、にはしないのがポイントです。

確かめるのは2つだけです。

# 1) 本番のHTMLが、新しいURL(ハッシュ・バージョン)を指しているか
curl -s https://example.com/ | grep -o -E 'href="[^"]+\.css[^"]*"|src="[^"]+\.js[^"]*"'

# 2) その新しいURLのファイルが、ちゃんと返ってくるか(200になるか)
curl -sI "https://example.com/assets/index-BkYZ3a8q.css" | head -1

1で古いURLのままなら、HTML自体が古い(テンプレートの反映漏れ、HTMLのキャッシュ、CDN)ということです。2で 404 なら、JS・CSSのファイルが反映先に届いていません。どちらで止まっているかが分かれば、次の一手が決まります。

ブラウザで見るなら、シークレットウィンドウや開発者ツールの「ネットワーク」タブで、読み込まれているファイル名を見るのが確実です。

具体例:「スーパーリロードしてください」をやめた現場

ある社内システムの保守担当の、よくある流れです。

変わったのは、利用者の操作でも、担当者の注意力でもありません。「新しい版ができた」ことがURLで伝わるようになったことです。

影響:URLで新しい版を伝えると、何が変わるか

明日やること

  1. 今のキャッシュ指定を curl -sI で見る。HTMLとJS・CSSそれぞれに、どんな Cache-Control が付いているかを書き出します。
  2. JS・CSSの参照のされ方を確かめる。ファイル名にハッシュが入っているか、?v= が付いているか、何も付いていないかを見ます。
  3. 自分の現場に合うやり方を1つ選ぶ。ビルドツールがあればA、なければBから始めるのがおすすめです。
  4. リリース手順書に確認コマンドを1行足す。「HTMLが新しいURLを指しているか」を curl で見る行です(リリース手順書の作り方)。
  5. CDNを使っていれば、クエリ文字列の扱いを確認する。?v= 方式を選ぶなら、ここだけは先に見ておきましょう。

今日やるのは、1の「今のキャッシュ指定を見る」だけでも十分です。どこで覚えられているかが分かるだけで、次のリリースの見通しがずいぶん変わります。

JS・CSS反映(キャッシュバスティング)チェックリスト

全部そろっていなくても大丈夫です。「HTMLは毎回確認」と「JS・CSSはURLが変わる」の2つがあれば、反映されない問題の多くは起きにくくなります。

よければ、こちらも

朝の明るいオフィスで、きれいに整って表示されたWeb画面を見ながら、静かな電話の横でほっとした笑顔を浮かべている保守運用の担当者

「スーパーリロードしてください」とお願いしてきたのは、利用者の画面をなんとか直そうとしてきた証拠です。その気づかいを、これからは仕組みのほうに任せてしまいましょう。

キャッシュは敵ではなく、サービスを速くしてくれる味方です。URLをひとつ変えるだけで、その味方と上手に付き合えるようになります。まずは今の設定を、curl で一度のぞいてみてください。

ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。

関連用語