ユーザーのブラウザで最新のCSS/JavaScriptを反映させる方法
何度更新ボタン押してもCSSが反映されない!
HTML/CSSでサイト画面を作っているとよく遭遇する現象ですね。
CSSやJavaScriptなどの静的ファイルに発生する現象です。
今回は、自分も含めたユーザーがサイトにアクセスした際に、常に最新のCSS/JavaScriptが反映される方法について解説します!
- 何度更新ボタン押しても最新のCSS/JavaScriptが反映されない
最新のCSSなどが画面に反映されない原因
原因はみなさんが今見ているブラウザに保存されたキャッシュ(ブラウザキャッシュ)が読み込まれているためです。
キャッシュ(ブラウザキャッシュ)とは、簡単に説明すると以前にアクセスしたサイトの情報を一時的にブラウザに保存して、再度アクセスした際にその保存された情報を取り出して表示する機能です。
サイトへのアクセスを素早く行うために、ブラウザにキャッシュが残っていると、最新の情報よりもキャッシュを優先して読み込むため、このような現象が発生します。
ブラウザに残ったキャッシュはいくつかの手段で削除することが可能なので、自分が遭遇した場合は問題ないのですが、サイトにアクセスしている他のユーザーの場合はサイトが最新かどうか判断ができず、必ずしもキャッシュを削除してくれるとは限りません。
ブラウザキャッシュを制御することで、サイトの表示スピードを早くでき、かつ適切に最新情報を反映できるようになります。
ブラウザキャッシュの制御
ブラウザキャッシュの制御については、一般的にHTTPヘッダー内に含まれる情報(Cache-Control / Expires / Last-Modified / ETag)を用いて、キャッシュの利用や破棄のタイミングを適切に制御します。
今回ご紹介するのは上記とは異なる方法になります。
さっと実行することが可能である反面、保存されているキャッシュを強制的に破棄する方法となるため、余計なリクエスト送信が増える方法になります。
ユーザーが少ない小規模サイトだったり、一時的な利用にとどめ、HTTPヘッダーで適切に制御するようにしましょう。
キャッシュバスティング(Cache Busting)
キャッシュバスティング(Cache Busting)とは、その名の通りキャッシュを破壊するという手法です。
ブラウザキャッシュにおけるバスティングは、一般的には参照するリソース(今回の場合はCSS/JavaScriptなどの静的ファイル)のURLにキャッシュバスターと呼ばれるパラメータを付与する、という方法になります。
具体的な方法は、主に以下の3点です。
- ファイル名に付与する
https://sample.com/style.v2.css
- ファイルのディレクトリ名に付与する
https://sample.com/v2/style.css
- クエリ文字列に付与する
https://sample.com/style.css?ver=2
ファイル名やディレクトリ名の変更は、更新するたび手動で変更をする必要があるため、今回はJavaScriptを使って自動でクエリ文字列を付与する方法をご紹介します。
JavaScriptを使ってクエリ文字列を自動的に付与する
CSSファイルに付与する
<script>
var element = document.createElement('link')
element.setAttribute('rel', 'stylesheet')
element.setAttribute('href', 'css/style.css?ver=' + new Date().getTime())
document.getElementsByTagName("head")[0].appendChild(element)
</script>
まず、<link>
要素を element
変数に格納します。
document.createElement('link')
続いて、その element
(<link>
要素)の rel
属性に 'stylesheet'
という文字列の値を設定します。
element.setAttribute('rel', 'stylesheet')
次に、同じく element
(<link>
要素)の href
属性に キャッシュバスターのクエリ文字列を付与したCSSファイルのパスを設定します。
element.setAttribute('href', 'css/style.css?ver=' + new Date().getTime())
クエリ文字列は、URLやパスの最後に ?キー=値
という形で付与することができます。
今回は ver
(versionの略)というキーに対して、new Date().getTime()
を使ってUNIXタイムスタンプを値として設定しています。
こうすることで、クエリ文字列が1秒毎に変化するため、実質、常に最新のキャッシュバスターが自動で付与される形になります。
ここまでで element
変数に格納されている <link>
要素は以下のようになっています。
<link rel="stylesheet" href="css/style.css?ver=1639118828461">
最後に<head>
タグの子要素として element
(<link>
要素)を追加して完了です。
document.getElementsByTagName("head")[0].appendChild(element)
JavaScriptファイルに付与する
<script>
var element = document.createElement('script')
element.setAttribute('src', 'js/script.js?ver=' + new Date().getTime())
document.getElementsByTagName("body")[0].appendChild(element)
</script>
やっていることはCSSファイルとほとんど同じです。
CSSファイルでは<link>
要素でしたが、JavaScriptの場合は <script>
要素を使いますので、それを格納した element
変数を作ります。
さらにCSSファイルではパスの設定は href
属性でしたが、JavaScriptファイルでは src
属性にキャッシュバスターを付与したJavaScriptファイルのパスを設定します。
最後にCSSファイルでは <head>
要素でしたが、JavaScriptファイルでは <body>
要素の子要素に element
(<script>
要素)を追加する、という流れです。
注意点
上記の方法では、キャッシュバスターを秒単位で変更する仕組みになっています。
該当のファイルの内容が変更されてようがされていまいが関係なく、画面を読み込むたびにキャッシュバスターが変更されるため、常に該当ファイルを読み込む(サーバーへリクエストが送信される)状態です。
はじめにお伝えしたように、変更がない場合でもキャッシュされることなくサーバーへリクエストを送信しているため、無駄なリクエストを行なっていることになります。
あまり多用せず、CSSファイルなどの調整が完了したら、キャッシュバスティングのスクリプトは削除するかコメントアウトして実行されないようにしておきましょう。
以上になります。
今回は手軽にキャッシュを破棄し、最新のデータを読み込む方法をご紹介しました。
また別の機会に、キャッシュについてより詳しくお伝えできればと思います。