Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Hooking up Watchify (Browserify) to Google's Web Starter Kit
/**
*
* Hooking up Watchify with Google's Web Starter Kit
*
* The primary use cases for Browserify/Watchify are:
* - Node.js-style `require`s on the client-side
* - Use of npm modules on the client-side
* - No more new <script> tags for each new script/module
*
* 1. npm install --save-dev vinyl-source-stream browserify watchify gulp-notify
* 2. require the following:
* var source = require('vinyl-source-stream');
* var browserify = require('browserify');
* var watchify = require('watchify');
* 3. create: `watchify` task (see below)
* 4. update: `serve` task with task dependency on `watchify`
* 5. update: `default` run sequence with `watchify` | set var dist to true
* 6. AngularJS + Browserify usage:
* Check out Ben Clinkinbeard's Slides from ng-conf:
* http://benclinkinbeard.com/talks/2014/ng-conf/#/
*/
/* global require:false, console:false */
'use strict';
// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var browserSync = require('browser-sync');
var pagespeed = require('psi');
var reload = browserSync.reload;
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var AUTOPREFIXER_BROWSERS = [
'ie >= 10',
'ie_mob >= 10',
'ff >= 30',
'chrome >= 34',
'safari >= 7',
'opera >= 23',
'ios >= 7',
'android >= 4.4',
'bb >= 10'
];
/**
* BROWSERIFY / WATCHIFY TASK ADDED HERE
*/
var dist = false; // set to true when `default` task is run
gulp.task('watchify', function(){
var bundler = watchify(browserify('./app/scripts/app.js'), {
basedir: './app/scripts', // (roots __dirname)
debug: true
});
var bundle = function() {
return bundler
.bundle({ debug: true })
.on('error', $.notify.onError({
message: 'watchify error: <%= error.message %>'
}))
.pipe(source('bundle.js'))
// destination changes when `dist` is set to true
.pipe(gulp.dest( dist ? 'dist/scripts' : './app/build/' ))
.pipe(reload({stream: true, once: true}));
};
// rebundle on change
bundler.on('update', bundle);
return bundle();
});
// Lint JavaScript
gulp.task('jshint', function () {
return gulp.src('app/scripts/**/*.js')
// taken care of by `watchify` (remove or comment out)
//.pipe(reload({stream: true, once: true}))
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish'))
.pipe($.if(!browserSync.active, $.jshint.reporter('fail')));
});
// Optimize Images
gulp.task('images', function () {
return gulp.src('app/images/**/*')
.pipe($.cache($.imagemin({
progressive: true,
interlaced: true
})))
.pipe(gulp.dest('dist/images'))
.pipe($.size({title: 'images'}));
});
// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
return gulp.src(['app/*','!app/*.html'], {dot: true})
.pipe(gulp.dest('dist'))
.pipe($.size({title: 'copy'}));
});
// Copy Web Fonts To Dist
gulp.task('fonts', function () {
return gulp.src(['app/fonts/**'])
.pipe(gulp.dest('dist/fonts'))
.pipe($.size({title: 'fonts'}));
});
// Automatically Prefix CSS
gulp.task('styles:css', function () {
return gulp.src('app/styles/**/*.css')
.pipe($.changed('app/styles'))
.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
.pipe(gulp.dest('app/styles'))
.pipe($.size({title: 'styles:css'}));
});
// Compile Sass For Style Guide Components (app/styles/components)
gulp.task('styles:components', function () {
return gulp.src('app/styles/components/components.scss')
.pipe($.rubySass({
style: 'expanded',
precision: 10,
loadPath: ['app/styles/components']
}))
.on('error', $.notify.onError({
message: 'styles:components error: <%= error.message %>'
}))
.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
.pipe(gulp.dest('app/styles/components'))
.pipe($.size({title: 'styles:components'}));
});
// Compile Any Other Sass Files You Added (app/styles)
gulp.task('styles:scss', function () {
return gulp.src(['app/styles/**/*.scss', '!app/styles/components/components.scss'])
.pipe($.rubySass({
style: 'expanded',
precision: 10,
loadPath: ['app/styles']
}))
.on('error', $.notify.onError({
message: 'styles:scss error: <%= error.message %>'
}))
.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
.pipe(gulp.dest('.tmp/styles'))
.pipe($.size({title: 'styles:scss'}));
});
// Output Final CSS Styles
gulp.task('styles', ['styles:components', 'styles:scss', 'styles:css']);
// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
return gulp.src('app/**/*.html')
.pipe($.useref.assets({searchPath: '{.tmp,app}'}))
// Concatenate And Minify JavaScript
.pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
// Remove Any Unused CSS
// Note: If not using the Style Guide, you can delete it from
// the next line to only include styles your project uses.
.pipe($.if('*.css', $.uncss({
html: [
'app/index.html',
'app/styleguide/index.html'
],
// CSS Selectors for UnCSS to ignore
ignore: [
'.navdrawer-container.open',
/.app-bar.open/
]
})))
// Concatenate And Minify Styles
.pipe($.if('*.css', $.csso()))
.pipe($.useref.restore())
.pipe($.useref())
// Update Production Style Guide Paths
.pipe($.replace('components/components.css', 'components/main.min.css'))
// Minify Any HTML
.pipe($.if('*.html', $.minifyHtml()))
// Output Files
.pipe(gulp.dest('dist'))
.pipe($.size({title: 'html'}));
});
// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));
// Watch Files For Changes & Reload
// Add: `watchify` task dependency
gulp.task('serve', ['watchify'], function () {
browserSync({
notify: false,
// Run as an https by uncommenting 'https: true'
// Note: this uses an unsigned certificate which on first access
// will present a certificate warning in the browser.
// https: true,
server: {
baseDir: ['.tmp', 'app']
}
});
gulp.watch(['app/**/*.html'], reload);
gulp.watch(['app/styles/**/*.scss'], ['styles:components', 'styles:scss']);
gulp.watch(['{.tmp,app}/styles/**/*.css'], ['styles:css', reload]);
gulp.watch(['app/scripts/**/*.js'], ['jshint']);
gulp.watch(['app/images/**/*'], reload);
});
// Build and serve the output from the dist build
gulp.task('serve:dist', ['default'], function () {
browserSync({
notify: false,
// Run as an https by uncommenting 'https: true'
// Note: this uses an unsigned certificate which on first access
// will present a certificate warning in the browser.
// https: true,
server: {
baseDir: 'dist'
}
});
});
// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
dist = true; // changes Watchify's build destination
// add `watchify` task to the run sequence (below)
runSequence('styles', ['jshint', 'watchify', 'html', 'images', 'fonts', 'copy'], cb);
});
// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
// By default, we use the PageSpeed Insights
// free (no API key) tier. You can use a Google
// Developer API key if you have one. See
// http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
url: 'https://example.com',
strategy: 'mobile'
}));
// Load custom tasks from the `tasks` directory
try { require('require-dir')('tasks'); } catch (err) {}
@thadk

This comment has been minimized.

Copy link

@thadk thadk commented Jul 29, 2014

This is great. Do you follow how

   .pipe($.if('*.js', $.uglify({preserveComments: 'some'}))) 

was uglifying main.min.js in the js:build of index.html?

@thadk

This comment has been minimized.

Copy link

@thadk thadk commented Jul 30, 2014

Also, this is generally super fast but If watchify catches a syntax error, it seems to hang up the reload process. How to relax it? Maybe it is just debug: true...

[BS] Reloading Browsers
[BS] Reloading Browsers
[BS] Reloading Browsers
[BS] Reloading Browsers
Watchify Error [Error: Line 10: Unexpected token : (/Users/thadk/gitrepos/node-apps/content_syllabus/app/scripts/syllabus/overview/composite-view.js)]
^C[BS] Exiting...
@wulymammoth

This comment has been minimized.

Copy link
Owner Author

@wulymammoth wulymammoth commented Aug 1, 2014

Specify a different build destination if that seems to be the case. Depending on what sort of a dev you are, you may or may not like the delay that comes with the build process during development or even having a bundle at all, as it can obfuscate code when debugging (if not using source maps).

I think ya got it, Thad! Sorry, didn't see your message. I've also just updated the gulpfile, because it looks like @substack changed the docs. The call to browserify is wrapped by watchify now.

Your process should resume (rebuild) once the error is corrected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.