【タスクランナー】もうキャッシュのせいなんて言わせない。CSS・JavaScript・画像・PDFなど全ての読み込みファイルにパラメータをつけてファイル出力する方法
前回の記事でタスクランナーのススメを書いたが、少しアップデートしたので紹介する。
前回のタスクランナーの記事
hiromode.hatenablog.com
内容としては
・PUG削除
・HTMLのパラメータ付与の上出力
を追加した。
理由はPUGの書き方を習得するのが面倒だし、
HTMLキャッシュを防ぐためにパラメータを付与するためということに尽きる。
コピペでできるように順番にコードを記載する。
今回の環境
MacOS内にvirtualbox,CentOS7をインストール済み。
またnode.jsはインストールされているものとする。
前提条件
キャッシュさせたくないところ(パラメータにするところ)に__NOCACHE__と記載する。
別に他の文字列でもいいが、変える場合はindex.html内と併せて必ず後述するgulpfile.js内の文字列も変更すること。
一例としてindex.htmlを記載しておく
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>テンプレート</title> <link rel="stylesheet" href="css/style.css?__NOCACHE__"> <script src="js/app.js?__NOCACHE__"></script> </head> <body> <header> index </header> <img src="img/a.png?__NOCACHE__"> </body> </html>
モジュールをインストール
エラー通知
npm install gulp-notify --save-dev
エラーでも監視継続
npm install gulp-plumber--save-dev
SassをCSSコンパイル
npm install gulp-sass --save-dev
ベンダープレフィックス付与
npm install gulp-autoplefixer --save-dev
JS圧縮
npm install gulp-uglify --save-dev
PugをHTML変換
npm install gulp-pug --save-dev
変更したファイルのみ検知
npm install gulp-changed-in-place --save-dev
変更したファイルのみ検知
npm install gulp-replace --save-dev
赤が前回記事からアップロードした分
モジュールをインストール成功すると下記のようなファイルができている。
(※下記は一例であり、インストールしたものによって変わる。一度できたらpackage.jsonはコピーして使える)
package.json
{ "name": "sample", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "babel": "^6.23.0", "babel-preset-es2015": "^6.24.1", "gulp": "^3.9.1", "gulp-autoprefixer": "^6.0.0", "gulp-changed-in-place": "^2.3.0", "gulp-if": "^2.0.2", "gulp-notify": "^3.2.0", "gulp-plumber": "^1.2.0", "gulp-pug": "^4.0.1", "gulp-replace": "^1.0.0", "gulp-sass": "^4.0.2", "gulp-uglify": "^3.0.1", "gulp-webserver": "^0.9.1" }, "babel": { "presets": [ "es2015" ] } }
下記をインストールディレクトリに作成。
gulpfile.js
// gulpプラグインの読み込み var gulp = require('gulp'); var notify = require("gulp-notify"); // エラー時の通知 var plumber = require('gulp-plumber'); // エラーでもファイル監視(watch)を続ける var sass = require("gulp-sass"); //SassをCSSに var autoprefixer = require("gulp-autoprefixer"); //Sassにベンダープレフィックスをつける var uglify = require('gulp-uglify'); //JSの圧縮 var replace = require('gulp-replace'); var changedInPlace = require('gulp-changed-in-place');//変更した場合のみ処理 //var browserSync = require('browser-sync').create() //var babelify = require('babelify'); //var browserify = require('browserify'); //var buffer = require('vinyl-buffer'); //var source = require('vinyl-source-stream'); //var sourcemaps = require('gulp-sourcemaps'); //var uglify = require('gulp-uglify'); //var destDir = './public' // 出力先 // // ////ES6変換 //gulp.task('es6', () => { // browserify({entries: 'src/main.js', debug: true}) // .transform(babelify) // .bundle() // .on('error', err => console.log('Error : ' + err.message)) // .pipe(source('main.js')) // .pipe(buffer()) // .pipe(sourcemaps.init({loadMaps: true})) // .pipe(uglify()) // .pipe(sourcemaps.write('./')) // .pipe(gulp.dest(destDir)) // .pipe(browserSync.reload({stream: true})) //}) //scssにベンダープレフィックスをつけて圧縮してコンパイル gulp.task('scss', function() { gulp.src('./scss/**/*.scss') .pipe(plumber()) .pipe(autoprefixer({ // ベンダープレフィックスの付与 browsers: ['last 3 version', 'ie >= 10','iOS >= 9.3', 'Android >= 4.4'], // (ベンダープレフィックスを付与する)対応ブラウザの指定 cascade: false // 整形しない })) .pipe(sass({outputStyle: 'expanded'})) .pipe(gulp.dest('./css')); // cssディレクトリに書き出す }); //jsを圧縮 gulp.task('js', function() { //実行するファイル gulp.src('./js/**.js') //pipeでつなぐ .pipe(plumber())//エラーでもファイル監視継続watch .pipe(uglify())// 圧縮 .pipe(gulp.dest('./js/min'));//圧縮したファイルを出力 }); //HTMLファイルのビルド(タイムスタンプをパラメーターとして付与、置換する) gulp.task('build', function() { ts = Date.now(); //実行するファイル gulp.src(['./**/*.html','!./build/*']) //pipeでつなぐ .pipe(plumber())//エラーでもファイル監視継続watch .pipe(changedInPlace()) .pipe(replace(/__NOCACHE__/g, ts))//置換 .pipe(gulp.dest('./build'));//ディレクトリに書き出す }); // 自動監視化 gulp.task('watch', function(){ gulp.watch('./scss/**/*.scss',{interval: 500}, ['scss']); gulp.watch('./js/**/*.js', {interval: 500}, ['js']); gulp.watch('./**/*.htm*', {interval: 500}, ['build']); }); gulp.task('default', ['watch']);
実行
npx gulp
あとはbuildフォルダができて、更新するたびに新しいパラメータに置換されて
フォルダ階層も保ったままindex.htmlなどが出力されるので、それを公開サーバーなどにアップロードしたり納品したりする。
2019/4/18追記
バージョンを上げてしまうと上記gulpfile.jsの記述がエラーになってしまう様子。
その場合は下記のように変更すると動く。
// キャッシュパラメータを付与 gulp.task('build', function () { ts = Date.now(); return gulp.src(['./**/*.html', '!./build/*']) .pipe(plumber()) .pipe(changedInPlace()) .pipe(replace(/__NOCACHE__/g, ts)) .pipe(gulp.dest('./build')); }); // 自動監視化 gulp.task('watch', function () { gulp.watch('./**/*.htm*', { interval: 500 }, gulp.task('build')); }); gulp.task('default', gulp.task('watch'));
P.S.
ちなみにPHPの場合は簡単で、下記のようにファイルの更新日時をとってくるようにすれば良い。
src="$ファイルパス?ver="
//記述例 <img src="/img/example.png?ver=<?php echo filemtime($_SERVER['DOCUMENT_ROOT'].'/img/example.png'); ?>">
・既存のPHPを一括置換で対応させる場合
//検索: src="((.*)png)" //置換: src="$1?ver=<?php echo filemtime($_SERVER['DOCUMENT_ROOT'].'$1'); ?>"
注意点:一行に複数該当箇所があると正しく置換できない。
・既存のWordpressの場合
//検索: src=".*?>((.*)png)" //置換: src="<?php echo get_template_directory_uri(); ?>$1?ver=<?php echo filemtime($_SERVER['DOCUMENT_ROOT'].'/wp/wp-content/themes/xxxxxxxxxxxxx$1'); ?>"