PostCSSでCSSの中の画像URLのcache busteringを行う方法


CSSの中で背景画像を指定したいとき、次のように書く。

background-image: url('/img/stamp-blank.png');

でもこのままだと、例えば画像の配信で何かしらのキャッシュが設定されていた場合(Cache-ControlのHTTPヘッダーなど)に、画像を変更してもキャッシュが使用されてすぐに変更をクライアント側に反映できない。

そこでcache busteringを行う。URLの末尾に何かしらのクエリーストリングなどを付けて別のURLにすることで、ブラウザーのキャッシュを回避する方法だ。

background-image: url('/img/stamp-blank.png?version=20180611');

上のように変更すれば、新しい画像がブラウザーに読み込まれるようになる。

でも画像の変更があるたびにいちいちCSSをいじるのは面倒なので、自動化したい。そこでPostCSSのプラグインであるPostCSS Cachebusterを使ってみる。

導入は簡単に yarn add -D postcss-cachebuster なり npm install --save-dev postcss-cachebuster なりで。

CSSのプリプロセッサーとしてSassを、タスクランナーにgulp.jsを使っている場合の gulpfile.js だと、こんな感じになる(例ではautoprefixerも使っている)。webpackなどでも同様の記述が可能。

gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass');
const moduleImporter = require('sass-module-importer');
const postcss = require('gulp-postcss');
const cachebuster = require('postcss-cachebuster');
const autoprefixer = require('autoprefixer');

const paths = {
  sass: ['assets/sass/**/*.scss', 'assets/sass/**/*.sass'],
};

gulp.task('sass', () => {
  gulp.src(paths.sass)
    .pipe(sass({
      outputStyle: 'compressed',
      importer: moduleImporter(),
    }))
    .on('error', (err) => {
      return console.log(err.stack);
    })
    .pipe(postcss([
      cachebuster({
        type: 'checksum',
        imagesPath: '/public',
      }),
      autoprefixer({
        browsers: ['last 2 versions', 'ie >= 11', 'Android >= 4'],
        cascade: false,
        remove: false,
      }),
    ]))
    .pipe(gulp.dest('public/css'));
});

実行すると、次のようにCSSとして出力される。

background-image: url("/img/stamp-blank.png?vcf88ba6129bc045a4937410004e6106b");

typechecksum を指定することで、画像ファイルのMD5ハッシュが付加されるようになる(指定しない場合は mtime となり、ファイルの更新時刻ベースの文字列が付加される)。

詳しい使い方はリポジトリーのREADMEを読むか、それほど長いコードではないので処理の中身を読んだ方が早いと思う。