- Gulpでjavascriptのファイルを監視
- JSHintでエラーなどをチェック
- 問題がなければconcatで1つにまとめて、min化
browser-sync
でリロード
という処理を行わせようと思い、Google Web Starter Kitを参考にGulpのタスクを作っていたのですが、下記の問題に当たってしまいました。
- JSHintでエラー/ワーニングがあっても次のタスクが実行されてしまう
- JSHintでエラー/ワーニングがあるとjavascriptファイルを変更しても一切タスクが実行されなくなる (watchされなくなる?)
問題があった元のGulpタスク
使っているプラグインのバージョン
// package.json "devDependencies": { "browser-sync": "^2.9.1", "gulp": "^3.9.0", "gulp-concat": "^2.6.0", "gulp-if": "^1.2.5", "gulp-jshint": "^1.11.2", "gulp-load-plugins": "^0.10.0", "gulp-uglify": "^1.4.0", "jshint-stylish": "^2.0.1", "main-bower-files": "^2.9.0", "run-sequence": "^1.1.2" }
Gulpのタスク
// gulpfile.js var gulp = require("gulp"), $ = require('gulp-load-plugins')(), browserSync = require('browser-sync'), runSequence = require('run-sequence'), concat = require("gulp-concat"), uglify = require("gulp-uglify"), jshint = require("gulp-jshint"), reload = browserSync.reload; // js lint gulp.task('jshint', function () { return gulp.src(devDir + '/js/*.js') .pipe( jshint() ) .pipe( jshint.reporter('jshint-stylish') ) .pipe( $.if(!browserSync.active, jshint.reporter('fail')) ); }); // concat js gulp.task('concat.js', function(cb) { return gulp.src(devDir + '/js/*.js') .pipe( concat('main.js') ) .pipe( gulp.dest( destDir + '/js' ) ); }); // min js gulp.task('uglify', function() { return gulp.src(destDir + '/js/main.js') .pipe(uglify({ preserveComments: 'some' })) .pipe(rename({ extname: '.min.js' })) .pipe(gulp.dest( destDir + '/js' )); }); // Javascript Task gulp.task('js', function(cb) { runSequence('jshint', 'concat.js', 'uglify', reload); // runSequence('jshint', 'concat.js', 'uglify', reload, cb); // ↑ 最後に cb を追加するとエラーで実行できない // browser-syncとrun-sequenceの相性の問題っぽい。 }); // watch gulp.task('default', function() { gulp.watch([devDir + '/js/*.js'], ['js']); });
このタスクの書き方だと、javascriptファイルを変更してJSHintでerror/warningsがあった時も、 次のconcat.js
・uglify
・reload
が実行されてしまい、エラーのあるjsファイルが読み込まれた状態で表示されてしまいます。
その上、JSHintでerror/warningsがあると、次にjavascriptファイルを修正・保存してもナゼかjavascriptのwatchだけが効かなくなってしまいます。
(他にcssやhtmlをwatchしているものは正常に動作し続けます。何故ゆえにぃ!?
とりあえず、監視されなくなってしまうのが一番困るのでまずは
「b. JSHintでエラー/ワーニングがあるとjavascriptファイルを変更しても一切タスクが実行されなくなる (watchされなくなる?)」の問題を解決していきたいと思います。
browserSync.reload のさせ方に問題があった!
色々試してみた結果どうやらbrowserSync.reload()
だけで実行するのが良くないっぽいという事がわかりました。
どちらのオプションが必要なのか今少し理解できていないのですが、{stream: true, once: true}
というオプションを与えて、別途gulp.taskに登録してリロードさせればJSHintでエラー/ワーニングがあってもファイルのwatchがされなくなるという現象を解決することができました。
gulpfile.jsを編集します
var gulp = require("gulp"), $ = require('gulp-load-plugins')(), browserSync = require('browser-sync'), runSequence = require('run-sequence'), concat = require("gulp-concat"), uglify = require("gulp-uglify"), jshint = require("gulp-jshint"); // js lint gulp.task('jshint', function () { return gulp.src(devDir + '/js/*.js') .pipe( jshint() ) .pipe( jshint.reporter('jshint-stylish') ) .pipe( $.if(!browserSync.active, jshint.reporter('fail')) ); }); // concat js gulp.task('concat.js', function(cb) { return gulp.src(devDir + '/js/*.js') .pipe( concat('main.js') ) .pipe( gulp.dest( destDir + '/js' ) ); }); // min js gulp.task('uglify', function() { return gulp.src(destDir + '/js/main.js') .pipe(uglify({ preserveComments: 'some' })) .pipe(rename({ extname: '.min.js' })) .pipe(gulp.dest( destDir + '/js' )); }); // reload を別タスクにする gulp.task('reload', function() { return gulp.src('/') .pipe( browserSync.reload({stream: true, once: true}) ); }); // Javascript Task gulp.task('js', function(cb) { // reloadを別タスクにして実行させる // 別タスクにすると、最後に callback を追加してもエラーにならない! runSequence('jshint', 'concat.js', 'uglify', 'reload', cb); }); // watch gulp.task('default', function() { gulp.watch([devDir + '/js/*.js'], ['js']); });
リロードのタスクの実効のさせ方がちょっとキモチワルイのですが、これでJSHintで問題があってもjavascriptの監視が切れてしまうという問題は解消されました。
もしかしたらrunSequenceの最後にcallbackを追加できたのが良かったのかもしれません。ちょっと原因がハッキリしていないのでアレなのですが...
次に「a. JSHintでエラー/ワーニングがあっても次のタスクが実行されてしまう」の問題にとりかかります。
JSHintの最後の.pipe()の書き方が違った!
Google Web Starter Kitを参考にして書いていたJSHintのタスク ↓
// js lint gulp.task('jshint', function () { return gulp.src(devDir + '/js/*.js') .pipe( jshint() ) .pipe( jshint.reporter('jshint-stylish') ) .pipe( $.if(!browserSync.active, jshint.reporter('fail')) ); });
最後の部分は !browserSync.active
なら jshint.reporter('fail')
を実行するようになっています。
参考にした記事などで.pipe( jshint.reporter('fail') )
とするとJSHintにかかった時にStreamが止まってしまう (gulp コマンドで実行していたwatchなどが終了してしまう)
とあったのをそのまま鵜呑みにしていました。
しかし"gulp-jshint": "^1.11.2"
では、どうやら?この問題は解決されているっぽく、タスクの最後の部分を純粋に.pipe( jshint.reporter('fail') )
とするだけでJSHintで問題があった時だけ次のタスクを実行しないようになっていました!
gulpfile.jsを編集します。
var gulp = require("gulp"), browserSync = require('browser-sync'), runSequence = require('run-sequence'), concat = require("gulp-concat"), uglify = require("gulp-uglify"), jshint = require("gulp-jshint"); // js lint gulp.task('jshint', function () { return gulp.src(devDir + '/js/*.js') .pipe( jshint() ) .pipe( jshint.reporter('jshint-stylish') ) .pipe( jshint.reporter('fail') ); // ← 変更 }); // concat js gulp.task('concat.js', function(cb) { return gulp.src(devDir + '/js/*.js') .pipe( concat('main.js') ) .pipe( gulp.dest( destDir + '/js' ) ); }); // min js gulp.task('uglify', function() { return gulp.src(destDir + '/js/main.js') .pipe(uglify({ preserveComments: 'some' })) .pipe(rename({ extname: '.min.js' })) .pipe(gulp.dest( destDir + '/js' )); }); // reload gulp.task('reload', function() { return gulp.src('/') .pipe( browserSync.reload({stream: true, once: true}) ); }); // Javascript Task gulp.task('js', function(cb) { runSequence('jshint', 'concat.js', 'uglify', 'reload', cb); }); // watch gulp.task('default', function() { gulp.watch([devDir + '/js/*.js'], ['js']); });
これで、JSHintでエラー/ワーニングがあると次のタスクは実行せず、javascriptのwatchが切れたり、Streamが停止したしすることがないgulpタスクを作成することができました!!! 今回はすごくハマってしまいました。
!注意すること
javascript以外の監視しているファイルのタスクでオプションの無いbrowserSync.reload()
が実行されていると、JSHintでエラーがあってもリロードだけが実行されてしまうようになってしまいます。謎です!!
EX: gulpfile.js
// watch gulp.task('default', function() { gulp.watch([devDir + '/js/*.js'], ['js']); // ↓ jadeファイルを変更すると browserSync.reload() が実行される様になっている gulp.watch([devDir + '/jade/**/*.jade', devDir + '/jade/*.jade'], ['jade', browserSync.reload]); });
一度でもjadeを変更してタスクが実行されてしまうと、それ以降javascriptの変更時にJSHintで問題があった時、次のタスクは実行されないのですがナゼか画面のリロードだけが実行されてしまうようになってしまいます。
リロードは全て別に作成したタスクでオプション付きで実行させるようにすれば、この問題は発生しません。
↓
// watch gulp.task('default', function() { gulp.watch([devDir + '/js/*.js'], ['js']); // これなら問題は発生しない gulp.watch([devDir + '/jade/**/*.jade', devDir + '/jade/*.jade'], ['jade', 'reload']); });
感想
ただ、gitHubのチケット上の解決したコメントは1 Jul 2014で、問題があったってblogの日時は2014-07-05なので、どうなんだろう?その後さらにアップデートされて問題が解決したのかな?
少し謎が残っています。。。
もしかして、個別にjaHintでチェックするよりconcatで1つにまとめてJSHintでチェックする方が処理速い?
[参考]
- Google Web Starter Kit の解説2(gulpfile.js編) - とりソレ
- Web Starter Kit で JavaScript のライブラリを利用しようとしたらエラーで gulp のサーバーが止まってしまう場合の対応 - HAM MEDIA MEMO
- jshint.reporter('fail') when used in an async task doesn't fail the build #28
- Gulp JSHintでError Warningsが無い時だけ次のタスクを実行してリロードさせたい(15922)|teratail
TVアニメ/データカードダス「アイカツ!」3rdシーズン挿入歌ミニアルバム2「Colorful Smile」
- アーティスト: AIKATSU☆STARS!,るか・もな from AIKATSU☆STARS!,みほ・みき from AIKATSU☆STARS!,みき・みほ from AIKATSU☆STARS!,れみ from STAR☆ANIS,えり from STAR☆ANIS,もな・るか from AIKATSU☆STARS!,るか・もな・みき from AIKATSU☆STARS!,るか・もな・みき・みほ・ななせ・かな from AIKATSU☆STARS!,空谷泉身,tzk
- 出版社/メーカー: ランティス
- 発売日: 2015/08/26
- メディア: CD
- この商品を含むブログ (3件) を見る