Gulp browser-sync only works once
Asked Answered
C

6

13

I'm trying out Gulp on one of my projects and I wanted to run it like I used to with Grunt watch. Meaning, it has to watch less files and js files, lint, merge, compile and refresh the browser once all that is done.

I managed to make it work with gulp-browser-sync but for some reason it only works once. I do a change to my .less file and the browser reloads. Then, a second change, it does compile but no reload happens.

Here's the log:

[BS] Serving files from: ./
[09:47:26] Starting 'css-clean'...
[09:47:26] Finished 'css-clean' after 16 ms
[09:47:26] Starting 'styles'...
[BS] 1 file changed (styles.min.css)
[09:47:27] Finished 'styles' after 624 ms
[09:47:27] Starting 'styles-watch'...
[BS] Reloading Browsers...

And when I hit save a second time:

[09:47:31] Starting 'css-clean'...
[09:47:31] Finished 'css-clean' after 3.39 ms
[09:47:31] Starting 'styles'...
[BS] 1 file changed (styles.min.css)
[09:47:32] Finished 'styles' after 362 ms

As for the JS, it works all the time. No issues whatsoever, even after the styles task is done, the JS changes are still triggering the reload properly. Really is only the styles that has issues.

Here's the gulpfile.js

var gulp = require('gulp'),
    autoprefixer = require('gulp-autoprefixer'),
    less = require('gulp-less'),
    minifycss = require('gulp-minify-css'),
    concat = require('gulp-concat'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    rename = require('gulp-rename'),
    notify = require('gulp-notify'),
    path = require('path'),
    streamqueue = require('streamqueue'),
    clean = require('gulp-clean'),
    browserSync = require('browser-sync').create(),
    reload = browserSync.reload;


// Clean the CSS folder
gulp.task('css-clean', function () {
    return gulp.src(['dist/css'], {read: false})
        .pipe(clean());
});

// Clean the CSS folder
gulp.task('js-clean', function () {
    return gulp.src(['dist/js'], {read: false})
        .pipe(clean());
});


// Generate the CSS styles, clean before hand
gulp.task('styles', ['css-clean'], function() {
  return streamqueue({ objectMode: true },
            gulp.src(['./bower_components/uikit/less/uikit.less']),
            gulp.src(['./src/less/main.less'])
        )
    .pipe(concat('styles.less'))
    .pipe(less({
      paths: [ path.join(__dirname, 'less', 'includes') ]
    }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(gulp.dest('dist/css'))
    .pipe(rename({suffix: '.min'}))
    .pipe(minifycss())
    .pipe(gulp.dest('dist/css'))
    .pipe(browserSync.reload({stream:true}));
});

// create a task that ensures the `styles` task is complete before
// reloading browsers
gulp.task('styles-watch', ['styles'], browserSync.reload);



// Lint Task
gulp.task('lint', function() {
    return gulp.src('src/js/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});


// Generate the scripts, clean before hand
gulp.task('scripts', ['js-clean', 'lint'], function() {
  return streamqueue({ objectMode: true },
            gulp.src(['./bower_components/jquery/dist/jquery.js']),
            gulp.src(['./bower_components/modernizer/modernizr.js']),
            gulp.src(['./bower_components/uikit/js/uikit.js']),
            gulp.src(['./src/js/plugin.js']),
            gulp.src(['./src/js/main.js'])
        )
    .pipe(concat('scripts.js'))
    .pipe(gulp.dest('dist/js'))
    .pipe(rename({suffix: '.min'}))
    .pipe(uglify())
    .pipe(gulp.dest('dist/js'))
    .pipe(browserSync.reload({stream:true}));
});

// create a task that ensures the `scripts` task is complete before
// reloading browsers
gulp.task('scripts-watch', ['scripts'], browserSync.reload);


// Lint Task
gulp.task('alldone', ['scripts'], function() {
    return gulp.src('src/js/*.js')
               .pipe(notify({ message: 'Gulp tasks are completed!!' }));
});


// Static server
gulp.task('browsersync', function() {
    browserSync.init({
        server: {
            baseDir: "./"
        }
    });

    gulp.watch("src/less/*.less", ['styles-watch']);
    gulp.watch('src/js/*.js', ['lint', 'scripts-watch']);
    gulp.watch("*.html").on('change', reload);
});


// Default Task
gulp.task('default', ['css-clean', 'js-clean', 'styles', 'lint', 'scripts', 'alldone']);

// Build Task
gulp.task('build',   ['css-clean', 'js-clean', 'styles', 'lint', 'scripts', 'alldone']);

Thanks for your help!

Cascabel answered 22/4, 2015 at 14:41 Comment(0)
J
26

For me in Gulp 4, the anonymous function didn't solve the issue, What I did was wrap the browserSync.reload() in a function with a done callback:

function reload(done) {
  browserSync.reload();
  done();
}

gulp.watch(['scripts/**/*.js','!scripts/main.min.js'], gulp.series(buildScripts, reload));
Jumpoff answered 7/7, 2016 at 8:55 Comment(2)
Yes! This wrapped up a lot of trial and error. Thank youNappie
This simple tweak was easy to implement and worked like a charm. Thank you PaulDacha
B
23

How about directly use

.pipe(browserSync.stream())

I once had the same problem while changing '.jade' files which it only reloaded once. Then I wrapped browserSync.reload in an anonymous function like

gulp.task('templates-watch', ['templates'], function() {
    browserSync.reload();
});

It works for me. I don't know if there is something special about browserSync.reload. How about have a try. :)

Broida answered 25/5, 2015 at 12:27 Comment(3)
Anonymous function made all the difference! +1 millionRamey
That's because browserSync.reload function take argument. github.com/BrowserSync/browser-sync/issues/…Gwennie
yeah for some reason if you use it as a callback directly it works only once! someone should probably report that to browsersyncAuto
A
1

I know this is not the right way to do things, but after some trial and error I figured out that using an undefined function after browserSync.reload()

gulp.watch("./**/*.php", function () {
    browserSync.reload();
    done();
});

leads to a reference error in my log which triggers to reload the browser:

ReferenceError: done is not defined 
    at ...
    at ...
    at asyncRunner (...)
    at processTicksAndRejections (...)
[Browsersync] Reloading Browsers...
Aviary answered 4/5, 2020 at 8:47 Comment(0)
G
0

Are you sure the CSS is not changed in the browser? New styles are loaded without requiring to reload the page. At least that is what my gulp setup is doing.

Try changing the .less file, and see if the change is actually visible in the browser.

Glacial answered 22/4, 2015 at 14:48 Comment(1)
It's not updated as my test is changing the background color of the navbar and I don't see it in the browser until I refresh the page myself the second time.Cascabel
C
0

My situation is a little different, but it might be similar enough to be helpful to you or someone else. I have gulp + browserSync set up like this:

.task('serve', ['clean', 'lint', 'sass', 'js', 'server'], function () {
  return gulp.watch([paths.js, paths.html, paths.sass], 
    ['lint', 'sass', 'js', browserSync.reload]);
})

This would start up and open the page once. If I made a change to the HTML page and save it, I could see lint, sass, js, and browserSync.reload run, but the browser didn't refresh. My HTML was very simple; this:

<!doctype html>
<html>
TEST
</html>

I changed the HTML to this finally and it started working:

<!doctype html>
<html>
<head>
    <title>TEST</title>
</head>
<body>
HELLO-TEST
</body>
</html>
Coolie answered 1/7, 2015 at 17:32 Comment(0)
P
0

I am facing same issue.looks there is issue with 'asyncDone' function inside node_modules. here is file path: /node_modules/glob-watcher/index.js

following is only dirty hack for temp fix. you may have issues sometimes. but worked for me.

function onChange() {
  console.log("onChange running: ", running);

  /** existing code */

  // keeping this function at it worked for me.
  setTimeout(() => {
     runComplete({msg: "test"});
  }, 2000);
}
Piroshki answered 3/1, 2020 at 6:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.