BrowserSync / browser-sync

Keep multiple browsers & devices in sync when building websites. https://browsersync.io
https://discord.gg/2d2xUThp
Apache License 2.0
12.18k stars 756 forks source link

Gulp: Browser reloads before code was syncing #941

Closed HeikoMamerow closed 8 years ago

HeikoMamerow commented 8 years ago

Hi, sometimes i have this issue with BrowserSnc + Gulp: the Browser reloads before the code is synced.

Here my typical gulpfile:

var gulp = require('gulp');
var postcss = require('gulp-postcss');
var autoprefixer = require('autoprefixer');
var cssnext = require('cssnext');
var precss = require('precss');
var dirSync = require('gulp-directory-sync');
var browserSync = require('browser-sync').create();

gulp.task('css', function () {
    var processors = [
        autoprefixer,
        cssnext,
        precss
    ];
    return gulp.src('./src/*.css')
            .pipe(postcss(processors))
            .pipe(gulp.dest('./build'));
});

gulp.task('sync', function () {
    return gulp.src('src')
            .pipe(dirSync('src', 'build', {ignore: ['stuff', 'css']}, 'nodelete'));
});

gulp.task('browserSync', function () {
    browserSync.init({
        proxy: "webwork/clients/wordpress/website"
    });
});

gulp.task('default', ['browserSync'], function () {
    gulp.watch('src/*.css', ['css']).on('change', browserSync.reload);
    gulp.watch('src/**/*.php', ['sync']).on('change', browserSync.reload);
});

After the second change in code, the reload will start before syncing. This makes the changes only visible after the next change/relaod...

Only this workaround works:

gulp.task('browserSync', function () {
    browserSync.init({
        reloadDelay: 1000,
        proxy: "webwork/clients/wordpress/website"
    });
});

If i use the reloadDelay option. Only this will make the Browser reloading after syncing.

nirazul commented 8 years ago

I have the exact same problem. Really weird because I've been using gulp in my projects for more than a year now.

ghost commented 8 years ago

The reason has not got to do with browser-sync but rather how you have gulp configured. I'm assuming you're using gulp 3.9 (not 4.0).

The reason it's happening is because gulp by default attempts to run all tasks async i.e. in parallel. In other words the watcher will trigger the reload while other tasks are running.

I see nothing in the gulpfile above that indicates implementation of callbacks to ensure tasks are run synchronously. Look into run-sequnece for more info.

marvinhagemeister commented 8 years ago

That is due to the change event listener. It always fires as soon as the files specified in the glob pattern changes which is obviously before any task piping has been done. The proper way to inject or reload BrowserSync with gulp is documented nicely in the docs: https://www.browsersync.io/docs/gulp/

shakyShane commented 8 years ago

@HeikoMamerow Please see the docs as @marvinhagemeister points out, there's an easier way to handle this

GuyPaddock commented 7 years ago

For clarity (since the docs can be a bit dense in this area), it's this section that applies:

Streams are supported in Browsersync, so you can call reload at specific points during your tasks and all browsers will be informed of the changes. Because Browsersync only cares about your CSS when it's finished compiling - make sure you call .stream() after gulp.dest

At first glance, the code below that section is not that straightforward and seems like it just watches for all file changes and then calls browserSync.reload. But, when one pays closer attention to the example, you'll notice that it only does that for HTML files. For SASS files, the reload actually gets triggered by the sass task.

GuyPaddock commented 7 years ago

One other thing to look at: make sure all of the tasks that compile code return the task result (promise).

In other words, make sure this:

gulp.task('sass:dev', function () {
  gulp.src([sassSrc])
    .pipe(sourcemaps.init())
    .pipe(sass(sassConfig).on('error', sass.logError))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(sassDest))
    .pipe(browserSync.stream());
});

Becomes:

gulp.task('sass:dev', function () {
  return gulp.src([sassSrc])
    .pipe(sourcemaps.init())
    .pipe(sass(sassConfig).on('error', sass.logError))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(sassDest))
    .pipe(browserSync.stream());
});

This helps ensure that BrowserSync is only invoked when the compilation "promise" is resolved.

Binaryhat commented 7 years ago

Thank you GuyPaddock. return keyword...! that is it..!