Last Updated: February 25, 2016
·
4.517K
· optilude

Gulpfile for projects with LESS, Browserify and React

This gulpfile.js provides the following:

  • A js target that builds a JavaScript bundle using browserify
  • A css target that builds a single CSS file using less
  • Support for a --production flag, which will minify sources
  • A watch target that runs watchify for the JavaScript sources and standard gulp.watch() for the LESS sources for robust real-time reloading of both.

Configure it by changing the variables near the top, under the imports.

You need to install a bunch of packages:

$ npm install --save-dev browserify reactify watchify vinyl-source-stream gulp gulp-sourcemaps gulp-util vinyl-buffer gulp-less yargs gulp-if gulp-minify-css gulp-uglify

Then create gulpfile.js as per below:

/*jshint globalstrict:true, devel:true, newcap:false */
/*global require */

/**
 * Build CSS and JavaScript using `gulp`.
 *
 * Main targets are: `js`, `css` and `watch`.
 *
 * Run with `--production` to get minified sources.
 */

"use strict";

var argv = require('yargs').argv,

    gulp       = require('gulp'),
    gutil      = require('gulp-util'),
    gulpif     = require('gulp-if'),

    source     = require('vinyl-source-stream'),
    buffer     = require('vinyl-buffer'),
    sourcemaps = require('gulp-sourcemaps'),
    browserify = require('browserify'),
    watchify   = require('watchify'),
    reactify   = require('reactify'),
    uglify     = require('gulp-uglify'),

    less       = require('gulp-less'),
    minifyCSS  = require('gulp-minify-css');

// Directory where static files are found. Don't forget the slash at the end.
var staticDirectory = './static/',

    // Source and target JS files for Browserify
    jsMainFile      = staticDirectory + 'js/app.jsx',
    jsBundleFile    = 'bundle.js',

    // Source and target LESS files
    cssMainFile     = staticDirectory + 'less/styles.less',
    cssFiles        = staticDirectory + 'less/**/*.less';

// Browserify bundler, configured for reactify with sources having a .jsx extension
var bundler = browserify({
    entries: [jsMainFile],
    transform: [reactify],
    extensions: ['.jsx'],
    debug: !argv.production,
    cache: {}, packageCache: {}, fullPaths: true // for watchify
});

// Build JavaScript using Browserify
gulp.task('js', function() {
    return bundler
        .bundle()
        .pipe(source(jsBundleFile))
        .pipe(buffer())
        .pipe(gulpif(!argv.production, sourcemaps.init({loadMaps: true}))) // loads map from browserify file
        .pipe(gulpif(!argv.production, sourcemaps.write('./'))) // writes .map file
        .pipe(gulpif(argv.production, uglify()))
        .pipe(gulp.dest(staticDirectory));
});

// Build CSS
gulp.task('css', function(){
    return gulp.src(cssMainFile)
        .pipe(less())
        .pipe(gulpif(argv.production, minifyCSS({keepBreaks:true})))
        .pipe(gulp.dest(staticDirectory));
});

// Watch JS + CSS using watchify + gulp.watch

gulp.task('watchify', function() {
    var watcher  = watchify(bundler);
    return watcher
    .on('error', gutil.log.bind(gutil, 'Browserify Error'))
    .on('update', function () {
        watcher.bundle()
        .pipe(source(jsBundleFile))
        .pipe(buffer())
        .pipe(sourcemaps.init({loadMaps: true})) // loads map from browserify file
        .pipe(sourcemaps.write('./')) // writes .map file
        .pipe(gulp.dest(staticDirectory));

        gutil.log("Updated JavaScript sources");
    })
    .bundle() // Create the initial bundle when starting the task
    .pipe(source(jsBundleFile))
    .pipe(gulp.dest(staticDirectory));
});

gulp.task('csswatch', function () {
    gulp.watch(cssFiles, ['css']);
});

gulp.task('watch', ['watchify', 'csswatch']);
gulp.task('default', ['js', 'css']);