2

I have set up gulp-watch and LiveReload. It works somehow, but most of the time wrong. It feels like LiveReload is emitting reload event faster, than browser should reload files. I could explain it like this:

  1. Some files has changed in my src directory
  2. It starts to compile
  3. While it is still compiling, browser reloads the page
  4. Sometimes page is already new and correct. Most of the time it is old. Sometimes its only part of the page.
  5. Hit reload and everything is fine.

I think I made some mistake, while integrating gulp-watch and LiveReload. Could you help me finding one?

Here is my gulpfile.js:

var gulp = require('gulp');
var jade = require('gulp-jade');
var sass = require('gulp-sass');
var watch = require('gulp-watch');
var connect = require('gulp-connect');
var favicons = require('gulp-favicons');
var ga = require('gulp-ga');
var postcss      = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var responsive = require('gulp-responsive');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var print = require('gulp-print');

gulp.task('default', ['jade', 'sass', 'js', 'connect', 'watch']);

gulp.task('jade', function() {
  gulp.src('./src/jade/*.jade')
    .pipe(jade())
    .pipe(ga({url: 'auto', uid: config.gaId, tag: 'body',sendPageView: true, minify: false, anonymizeIp: false}))
    .pipe(gulp.dest('./public/'));
});

gulp.task('sass', function () {
  gulp.src('./src/sass/style.scss')
    .pipe(sass({
      includePaths: [
        config.bowerDir + '/bootstrap/scss',
        config.bowerDir + '/font-awesome/scss'
      ],
      outputStyle: 'compressed'
    })
    .on('error', sass.logError))
    .pipe(postcss([ autoprefixer({ browsers: ['last 2 versions'] }) ]))
    .pipe(gulp.dest('./public/css'));
});

gulp.task('connect', function() {
  connect.server({
    root: 'public',
    livereload: true
  });
});

gulp.task('watch', function () {
  gulp.watch(['./src/jade/**/*.jade'], ['jade']);
  gulp.watch(['./src/sass/**/*.scss'], ['sass']);
  gulp.watch(['./src/js/**/*.js'], ['js']);
  watch(['./public/**/*.html', './public/**/*.css', './public/**/*.js']).pipe(connect.reload());
});

gulp.task('js', function () {
  return gulp.src([
    './node_modules/fontfaceobserver/fontfaceobserver.js',
    './bower_components/jquery/dist/jquery.min.js',
    './bower_components/bootstrap/js/dist/util.js',
    './bower_components/bootstrap/js/dist/collapse.js',
    './bower_components/picturefill/dist/picturefill.js',
    './src/js/modernizr.js',
    './src/js/js.js'
    ])
    .pipe(concat({ path: 'js.js'}))
    .pipe(uglify())
    .pipe(gulp.dest('./public/js'));
});

Full source is here https://gist.github.com/dandaka/3e342158763f9ccbd23305eecfd0b69c

Thank you!

dandaka
  • 829
  • 2
  • 9
  • 19

3 Answers3

2

Also besides of @TheFallen's suggestion, you good practice will be to create a separate task and place it at the end of watch tasks.

var gulp = require('gulp');
var runSequence = require('run-sequence');

gulp.task('reload', function() {
   connect.reload();
});

gulp.task('watch', function () {
  gulp.watch(['./src/jade/**/*.jade'], function() {
    runSequence('jade', 'reload');
  })

  gulp.watch(['./src/sass/**/*.scss'], function() {
    runSequence('sass', 'reload');
  });

  gulp.watch(['./src/js/**/*.js'], function() {
    runSequence('js', 'reload');
  });
});

UPD: As @Fencer correctly pointed out, tasks are executed simultaneously which could sometimes lead to the case when page is reloaded before the previous task is completed, I've added run-sequence package usage to avoid this issue.

G07cha
  • 4,009
  • 2
  • 22
  • 39
  • This actually does not work. There is no guarantee that for example the `jade` task will complete before `reload` ist started. All the task defined to run for the watch-event will run concurrently. I tried it. – Fencer Nov 29 '17 at 15:24
  • @Fencer that's indeed an issue which was discussed in one of [StackOverflow's questions](https://stackoverflow.com/questions/37970787/gulp-watch-does-not-run-tasks-in-order) already, you can find out possible solutions for it. – G07cha Nov 29 '17 at 16:33
  • Yes, I am aware of that. But it does not change the fact, that this answer is not a solution to the problem itself. I just wanted to make that clear for other readers and also to provide a working solution (see my answer). The usage of `run-sequence` for Gulp 3 however is a good hint. If you would integrate that in your answer then it would indeed be a proper solution. – Fencer Nov 30 '17 at 14:57
  • @Fencer, thanks for your help! I've updated my answer with your suggestions! – G07cha Nov 30 '17 at 21:18
2

I ran into the same problem recently and both solutions mentioned here did not work as I pointed out in my comments.

Using Gulp 3 the only working solution I could come up with is the following (I did not use gulp-connect though but the actual solution should be generic):

gulp.task('jade', function() {
    var stream = gulp.src('./src/jade/*.jade')
        .pipe(jade())
        .pipe(ga({url: 'auto', uid: config.gaId, tag: 'body',sendPageView: true, minify: false, anonymizeIp: false}))
        .pipe(gulp.dest('./public/'))
        .on('end', function() {
            livereload.reload();
        });
});

...

gulp.task('watch', function () {
    livereload.listen();
    gulp.watch(['./src/jade/**/*.jade'], ['jade']);
    ...
});

I do not know how Gulp works internally, but on('end'...)seems to actually wait until all operations of the stream have finished.

Using Gulp 4 there may be a solution that looks a lot like the one of @Konstantin Azizov.

gulp.task('reload', function() {
    connect.reload();
});

gulp.task('watch', function () {
    gulp.watch(['./src/jade/**/*.jade'], gulp.series('jade', 'reload'));
    ...
});

Or maybe even just:

gulp.task('watch', function () {
    gulp.watch(['./src/jade/**/*.jade'], gulp.series('jade', function() {
        connect.reload();
    }));
    ...
});

Please be aware that I did not test the Gulp 4 solutions. I'm a bit reluctant to switch to version 4 because it has still not officially been released. However it is very tempting.

Fencer
  • 1,026
  • 11
  • 27
1

Place .pipe(connect.reload()) at the end on each of the tasks, like the js for example:

return gulp.src([
    ...
    ])
    .pipe(concat({ path: 'js.js'}))
    .pipe(uglify())
    .pipe(gulp.dest('./public/js'))
    .pipe(connect.reload());

Because right now when it's on the watch watch([...]).pipe(connect.reload()); it will fire when the compilation has started bu not necessarily finished.

thefallen
  • 9,496
  • 2
  • 34
  • 49
  • Works fine. But now it reloads many times. Is there any way for it to reload only once, when all compilation is completed? Thank you. – dandaka Sep 02 '16 at 10:32
  • 1
    @dandaka I'm not sure. I think with the other answer it might reload only once. Also I would suggest browser-sync for live reload instead of gulp-connect, it's worth trying it out. – thefallen Sep 02 '16 at 10:53
  • This also will not work reliably. It depends on how many files `gulp.dest` has to process, because the actual copy process will run asynchronously. So you have a race condition here and the stream may already be at `connect.reload()`while the files are still being copied. – Fencer Nov 29 '17 at 15:28