If you are trying to code something and can’t find a great solution on the internet, you are either:
- doing something wonderfully exotic and novel, blazing a new trail for future developers to follow, or
- doing something you shouldn’t be doing
Unfortunately I’m always in the latter camp. This time I am trying to get Browsersync to rebuild my Browserify bundle each time I make changes to any of the JavaScript files.
I’m pretty sure the watchify module is the correct way to do this. But I’m not a front end dev. I wouldn’t even consider myself a JavaScript dev. And I have a list of stupid reasons why I just don’t feel like learning one more module. Mix all of that with a healthy dose of stubbornness and I’m going with what my project already has: gulp and Browsersync.
Note: this example uses Gulp 4. If you would like to go ahead with watchify, I recommend this quick 3 minute video.
The solution
Here’s the gulpfile:
const gulp = require('gulp');
const browserify = require('browserify');
const source = require('vinyl-source-stream');
const browserSync = require('browser-sync').create();
// browserify task to create bundle.js which index.html uses
gulp.task('browserify', function() {
return browserify('js/scripts.js')
.bundle()
//Pass desired output filename to vinyl-source-stream
// This is the file that index.js is looking for
.pipe(source('js/bundle.js'))
.pipe(gulp.dest('./'))
.pipe(browserSync.stream());
});
// browser-sync task to watch for changes and reload when necessary
gulp.task('browser-sync', function() {
browserSync.init({
server: {
baseDir: "./"
}
});
gulp.watch("*.html").on("change", browserSync.reload);
gulp.watch("./js/scripts.js", gulp.series('browserify'));
});
gulp.task('build', gulp.series('browserify', 'browser-sync'));
First there is a Browserify task that bundles scripts.js
into bundle.js
. A key piece of code is the last line,
.pipe(browserSync.stream())
It comes from this video mentioned earlier. This line sends the new bundle.js
that Browserify made to a special Browsersync stream. From there, Browsersync looks at each file that comes through and decides what to do. This task alone triggers reloads when a new bundle.js
is made.
But how do we rebuild the bundle?
JavaScript changes don’t mean anything if the Browserify bundle.js
is not regenerated.
This brings us to the Browsersync task. The first half is initialization. The more interesting stuff is at the end. For html file changes, Browsersync is configured to do a normal browserSync.reload
. However, for changes to JavaScript, Browsersync calls the Browserify task defined above.
In doing so, a new bundle.js
is made. Because bundle.js
is routed to the BrowserSync stream, Browsersync sees the changed JavaScript file and automatically reloads.
That’s it! The gulpfile tells Browserify to make a new bundle each time it sees changes to the JavaScript, and Browsersync reloads every time Browserify creates a new bundle.