クエリ文字列を利用したCSSのキャッシュバスティング

あなたのサイトを訪れる人が使っているブラウザは、静的ファイルのコピーをローカルにキャッシュして保存します。 そのため、サイトを更新しても、変更点を見られない可能性があるのです。これではやっかいなので、 キャッシュをクリアしてブラウザに静的アセットの最新版をダウンロードするような、キャッシュバスティング戦略が必要となります。

クエリ文字列を利用すると、ブラウザにファイルの新しいバージョンがあることを通知できます。 私は以下のようにCSSファイルにバージョンを追加していました。

<link href="{{ STATIC_URL }}css/base.css?v=1.4" rel="stylesheet" type="text/css">

しかし、この方法では、毎回クエリ文字列を手動で変更するのを忘れがちになります。 ですので、CSSのバージョン付けを自動化しようと、別の方法を探すことにしました。

Djangoがやってくれます

クエリ文字列を追加する代わりに、ファイル名自体を変更してもキャッシュバスティングは機能します。 Djangoには ManifestStaticFilesStorage があり、ファイルのコンテンツのMD5ハッシュ値をファイル名に付加できるのです。例えば、 css/base.css ファイルが css/base.e352ca3230fc.cssという風にも保存されるのです。

ManifestStaticFilesStorage を有効にするには、以下の条件を満たしている必要があります。

  • the STATICFILES_STORAGE の設定が 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'となっていること。
  • DEBUG の設定が Falseであること。
  • • 全ての静的ファイルが管理コマンドの collectstatic で集められていること。
# settings.py
DEBUG = False
...
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

それから static というテンプレートタグを追加して、任意の相対パスのURLが、設定済みの STATICFILES_STORAGEを利用して生成されるようにします。

<!-- base.html -->
{% load static from staticfiles %}
...
<link href="{% static 'css/base.css' %}" rel="stylesheet" type="text/css">

このような変更を行うと collectstaticの実行時に静的なファイル名が自動的にハッシュ付きのものに置き換わります。

django-storagesのManifestFilesMixinサポート

Xoxzo では S3BotoStorageを利用していますので ManifestStaticFilesStorageを利用するためには、特別なmixinが必要です。 django-storagesManifestFilesMixinをサポートしているので、 ストレージのクラスへの追加が可能になります。

# storage.py
from storages.backends.s3boto import S3BotoStorage as S3BotoStorageOrig
from django.contrib.staticfiles.storage import ManifestFilesMixin

class S3BotoStorage(S3BotoStorageOrig):
    ...

class ManifestS3Storage(ManifestFilesMixin, S3BotoStorage):
    pass
# settings.py
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATICFILES_STORAGE = 'storage.ManifestS3Storage'

おめでとうございます!

これでハッシュ化されたCSSファイルが使えるようになりました!

<link href="../css/base.e352ca3230fc.css" rel="stylesheet" type="text/css">

朴 慧晶

ユーザー·エクスペリエンス

2016年11月入社。ソウル国立大学にて、ビジュアル・デザインを専攻。前職ではiOSアプリのUIデザインを手がける。デザインにも、WEB開発にも興味あり。美しいUIと整然としたWEB、そしてPythonとDjangoを愛す。