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