greven
7/14/2016 - 1:40 AM

gulpfile.js for Django client code development with Browserify, Sass and browserSync

gulpfile.js for Django client code development with Browserify, Sass and browserSync

'use strict';

var gulp = require('gulp'),
    argv = require('yargs').argv,
    gutil = require('gulp-util'),
    gulpif = require('gulp-if'),
    del = require('del'),
    notify = require('gulp-notify'),
    exec = require('child_process').exec,
    uglify = require('gulp-uglify');

var sass = require('gulp-sass'),
    postcss = require('gulp-postcss'),
    autoprefixer = require('autoprefixer'),
    sourcemaps = require('gulp-sourcemaps');

var browserSync = require('browser-sync');

var browserify = require('browserify'),
    watchify = require('watchify'),
    buffer = require('vinyl-buffer'),
    source = require('vinyl-source-stream');


// gulp build --production
var production = !!argv.production;
// determine if we're doing a build
var build = argv._.length ? argv._[0] === 'build' : false;
var watch = argv._.length ? argv._[0] === 'watch' : true;


// error handling
var handleError = function(task) {
  return function(err) {
    notify.onError({
      message: task + ' failed, check the logs..',
      sound: false
    }) (err);

    gutil.log(gutil.colors.bgRed(task + ' error:'), gutil.colors.red(err));
  };
};


// --------------------------
// CONFIG
// --------------------------
var paths = {
  src: './static/src',
  dest: './static/build',
  templates: './templates',
  node_modules: './node_modules',
  vendor: '/vendor'

};

// django dev server configuration
var djangoServer = {
    address: "0.0.0.0",
    port: "8000"
};

// node_modules to copy to assets vendor folder
var vendor_files = [
  'semantic-ui-css',
];

// --------------------------
// CUSTOM TASK METHODS
// --------------------------
var tasks = {
  // delete build folder
  clean: function(callback) {
    del([paths.dest], callback);
  },

  // copy vendor files from node_modules
  vendors: function() {
    del([paths.src + paths.vendor]);
    gutil.log(gutil.colors.yellow("Copying vendor files..."));

    // append node_modules dir to list of modules
    var files = vendor_files.map(function(file) {
      return paths.node_modules + '/' + file + '/**/*.*';
    });

    return gulp.src(files, {'base': paths.node_modules}).pipe(gulp.dest(paths.src + paths.vendor));
  },

  // copy asset files to build
  assets: function() {
    // semantic theme assets
    gulp.src(paths.src + paths.vendor + '/semantic-ui-css/themes/**/*.*', {'base': paths.src + paths.vendor + '/semantic-ui-css'})
      .pipe(gulp.dest(paths.dest + '/css'));

    // all other assets
    return gulp.src(paths.src + '/assets/**/*')
      .pipe(gulp.dest(paths.dest + '/assets/'));
  },

  // Sass preprocessing (libsass)
  sass: function() {
    return gulp.src(paths.src + '/scss/*.scss')
      // sourcemaps + sass + error handling
      .pipe(gulpif(!production, sourcemaps.init()))
      .pipe(sass({
        sourceComments: !production,
        outputStyle: production ? 'compressed' : 'nested'
      }))
      .on('error', handleError('SASS'))
      // generate .maps
      .pipe(gulpif(!production, sourcemaps.write({
        'includeContent': false,
        'sourceRoot': '.'
      })))
      // autoprefixer
      .pipe(gulpif(!production, sourcemaps.init({
        'loadMaps': true
      })))
      .pipe(postcss([autoprefixer({browsers: ['last 2 versions']})]))
      // we don't serve the source files
      // so include scss content inside the sourcemaps
      .pipe(sourcemaps.write({
        'includeContent': true
      }))
      // write sourcemaps to a specific directory
      // give it a file and save
      .pipe(gulp.dest(paths.dest + '/css'));
  },

  browserify: function() {
    var bundler = browserify(paths.src + '/js/index.js', {
      debug: !production,
      cache: {}
    });
    // determine if we're doing a build and if so, bypass the livereload
    var build = argv._.length ? argv._[0] === 'build' : false;
    if (watch) {
      bundler = watchify(bundler);
    }
    var rebundle = function() {
      return bundler.bundle()
        .on('error', handleError('Browserify'))
        .pipe(source('build.js'))
        .pipe(gulpif(production, buffer()))
        .pipe(gulpif(production, uglify()))
        .pipe(gulp.dest(paths.dest + '/js/'));
    };
    bundler.on('update', rebundle);
    return rebundle();
  },

  // starts the django development server
  django: function() {
    var runserver = exec("python manage.py runserver " + djangoServer.address + ":" + djangoServer.port);

    gutil.log(gutil.colors.blue("Starting Django runserver http://" + djangoServer.address + ":" + djangoServer.port + "/"));
    runserver.on('close', function(code) {
      if (code !== 0) {
        console.error('Django runserver exited with error code: ' + code);
      } else {
        console.log('Django runserver exited normally.');
      }
    });
  },
};

gulp.task('browser-sync', function() {
  browserSync({
    // server: {
    //   baseDir: paths.dest
    // },
    proxy: djangoServer.address + ":" + djangoServer.port,
    port: process.env.PORT || 3000
  });
});

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

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

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


// --------------------------
// CUSTOM GULP TASKS
// --------------------------
gulp.task('clean', tasks.clean);
gulp.task('vendor', tasks.vendors);
gulp.task('assets', tasks.assets);
gulp.task('sass', tasks.sass);
gulp.task('browserify', tasks.browserify);
gulp.task('django', tasks.django);


// --------------------------
// DEV/WATCH TASK
// --------------------------
gulp.task('watch', ['sass', 'browserify', 'browser-sync', 'django'], function() {
  gutil.log(gutil.colors.bgGreen('Watching for changes...'));

  // watch:sass
  gulp.watch(paths.src + '/scss/**/*.scss', ['reload-sass']);

  // watch:js
  gulp.watch(paths.src + '/js/**/*.js', ['reload-js']);

  // watch:js
  gulp.watch(paths.templates + '/**/*.html', ['reload-templates']);
});


// --------------------------
// BUILD TASK
// --------------------------
gulp.task('build', ['clean', 'assets', 'sass', 'browserify']);

// default task
gulp.task('default', ['watch']);

// gulp (watch) : for development and livereload
// gulp build : for a one off development build
// gulp build --production : for a minified production build