Skip to content

Instantly share code, notes, and snippets.

@rwasher
Last active April 9, 2016 10:32
Show Gist options
  • Save rwasher/188b42451e64c0981ff8 to your computer and use it in GitHub Desktop.
Save rwasher/188b42451e64c0981ff8 to your computer and use it in GitHub Desktop.
// initial utilities
var gutil = require('gulp-util'); // tools to help, e.g. detect env, colour our output + logging
var changeEvent = function(evt) {
// log
gutil.log('File', gutil.colors.cyan(evt.path.replace(new RegExp('/.*(?=/' + paths.appSrc + ')/'), '')), 'was', gutil.colors.magenta(evt.type));
};
require('autostrip-json-comments'); // https://plus.google.com/+DouglasCrockfordEsq/posts/RK8qyGVaGSr
// 'development' is just default, production overrides are triggered by adding the production flag to the gulp command e.g. `gulp build --production`
var isProduction = (gutil.env.production === true ? true : false);
// pull in local json configs
var paths = require('./gulp-paths.json');
var bowerFiles = require('./bowerfiles.json');
// add absolute pathing to bower stuff, gulp.src globbing is a nightmare so lets do it manually
var types = ['js', 'css', 'fonts']
for(var type in types){
bowerFiles[types[type]].forEach(function(el,idx,array){array[idx]=paths.bower.src+el});
};
// gulp core plugins
// - we stay away from gulp-load-plugins, if we do them specifically it allows this file to be part documentation
var gulp = require('gulp'); // gulp is the boss
var sourcemaps = require('gulp-sourcemaps'); // we'll want sourcemaps on this journey
var runSequence = require('run-sequence'); // sequential tasks. this requires 'return gulp.~' inside tasks for async
var bower = require('gulp-bower'); // so we can bower:install to make sure our dependencies exist, makes it easier on the rest of the team
var size = require('gulp-size'); // weight watchers for code
var gconcat = require('gulp-concat'); // kill all the http requests!
var using = require('gulp-using'); // for debugging
var revall = require('gulp-rev-all'); // fingerprint assets for caching
var path = require('path'); // used to fix some gulp.src pathing for bower (node core)
var del = require('del'); // for cleanup
var fileList = require('gulp-filelist'); // builds manifests in dev when revisions are disabled
// html plugins
var htmlmin = require('gulp-htmlmin'); // html minification
var templateCache = require('gulp-angular-templatecache'); // bundle up the templates for the angular app, for templateCache pre loading
// css plugins
var sass = require('gulp-sass'); // sass for writing css makes us happy (we're from ruby land) - we also get minification here
var autoprefixer = require('gulp-autoprefixer'); // "Can I Use" based CSS anti-prefix superpowers
var cssmin = require('gulp-cssmin'); // for bower css
// js plugins
var uglify = require('gulp-uglify'); // make the js ugly (minify, compress)
var jshint = require('gulp-jshint'); // javascript police
var ngAnnotate = require('gulp-ng-annotate'); // pre-minification step for the ng app
// ---- COMPOSED TASKS
// default
gulp.task('default', function(callback){
runSequence(
'build',
'watch',
callback
);
});
// build
// gulp build (for dev)
// gulp build --production (for production)
gulp.task('build', function(callback){
runSequence(
'clean',
['bower:install', 'lint:js'],
['html', 'js', 'css', 'bower:js', 'bower:css', 'bower:fonts'],
callback
);
});
// ---- HELPER TASKS
// clean up the destination
gulp.task('clean', function() {
return del(paths.dist);
});
// bower:install
// - this is just so that bower install always runs
// - you'll need to run bower prune etc. as the normal bower CLI though
// - see some notes from https://gist.github.com/ktmud/9384509
gulp.task('bower:install', function() {

return bower()
.pipe(gulp.dest(paths.bower.src))
;
});
// watch
// - dist files won't be deleted when removed from src, run clean for that
gulp.task('watch', function() {
gulp.watch(paths.src + paths.html.src, ['html']).on('change', function(evt){
changeEvent(evt);
});
gulp.watch(paths.src + paths.js.src, ['lint:js', 'js']).on('change', function(evt){
changeEvent(evt);
});
gulp.watch(paths.src + paths.css.src, ['css']).on('change', function(evt){
changeEvent(evt);
});
});
// ---- MAIN INDIVIDUAL TASKS
// frontend:html
gulp.task('html', function() {
return gulp.src(paths.src + paths.html.src)
.pipe(htmlmin({
collapseWhitespace: (isProduction ? true : false)
}))
.pipe(templateCache(paths.html.concatFile,{
standalone: true
}))
.pipe(isProduction ? uglify() : gutil.noop())
.pipe(isProduction ? revall() : gutil.noop())
.pipe(size({
title:'html'
}))
.pipe(gulp.dest(paths.dist + paths.html.dist))
.pipe(isProduction ? revall.manifest({
fileName: 'manifest-html.json',
prefix: paths.webPrefix + paths.html.dist
}) : fileList('manifest-html.json',{
absolute: false,
prefix: paths.webPrefix + paths.html.dist
}))
.pipe(gulp.dest(paths.dist))
});
// frontend:js
gulp.task('js', function() {
return gulp.src(paths.src + paths.js.src)
.pipe(isProduction ? sourcemaps.init() : gutil.noop())
.pipe(isProduction ? gconcat(paths.js.concatFile+'.js') : gutil.noop())
.pipe(isProduction ? ngAnnotate() : gutil.noop())
.pipe(isProduction ? uglify({
compress: {
negate_iife: false
},
preserveComments: 'some'
}) : gutil.noop())
.pipe(isProduction ? revall() : gutil.noop())
.pipe(isProduction ? sourcemaps.write(paths.sourcemaps, {
sourceMappingURLPrefix: paths.webPrefix + paths.js.dist + "/"
}) : gutil.noop())
.pipe(size({
title:'js'
}))
.pipe(gulp.dest(paths.dist + paths.js.dist))
.pipe(isProduction ? revall.manifest({
fileName: 'manifest-js.json',
prefix: paths.webPrefix + paths.js.dist
}) : fileList('manifest-js.json',{
absolute: false,
prefix: paths.webPrefix + paths.js.dist
}))
.pipe(gulp.dest(paths.dist))
;
});
// frontend:sass
// - note that we don't currently concat here, ideally frontend/css/all.css.sass will use @import for all other sass and thus be a single file anyway
gulp.task('css', function() {
return gulp.src(paths.src + paths.css.src)
.pipe(isProduction ? sourcemaps.init() : gutil.noop())
.pipe(sass({
errLogToConsole: true,
indentedSyntax: true, // we came from ruby/HAML/SASS land, this is how we do.
outputStyle: (isProduction ? 'compressed' : 'expanded'), // we probably want compact here but libsass doesn't support it? (gulp-sass>node-sass>libsass)
sourcemap: (isProduction ? false : true) // don't write internal sourcemap
}))
.pipe(autoprefixer({
browsers: ['last 2 versions'],
cascade: false // don't bother, we're minifying anyway?
}))
.pipe(isProduction ? revall() : gutil.noop())
.pipe(isProduction ? sourcemaps.write(paths.sourcemaps, {
sourceMappingURLPrefix: paths.webPrefix + paths.css.dist + "/"
}) : gutil.noop())
.pipe(size({
title:'css'
}))
.pipe(gulp.dest(paths.dist + paths.css.dist))
.pipe(isProduction ? revall.manifest({
fileName: 'manifest-css.json',
prefix: paths.webPrefix + paths.css.dist
}) : fileList('manifest-css.json',{
absolute: false,
prefix: paths.webPrefix + paths.css.dist
}))
.pipe(gulp.dest(paths.dist))
;
});
// bower:js
gulp.task('bower:js', function() {

return gulp.src(bowerFiles.js, {base: path.join(process.cwd(), paths.bower.src)}) // https://github.com/sindresorhus/gulp-rev/issues/54#issuecomment-57231019
.pipe(isProduction ? sourcemaps.init() : gutil.noop())
.pipe(isProduction ? gconcat(paths.bower.concatFile+'.js') : gutil.noop())
.pipe(isProduction ? ngAnnotate() : gutil.noop())
.pipe(isProduction ? uglify({
compress: {
negate_iife: false
},
preserveComments: 'some'
}) : gutil.noop())
.pipe(isProduction ? revall() : gutil.noop())
.pipe(isProduction ? sourcemaps.write(paths.sourcemaps, {
sourceMappingURLPrefix: paths.webPrefix + paths.js.dist + paths.bower.dist + "/"
}) : gutil.noop())
.pipe(size({
title:'bower:js'
}))
.pipe(gulp.dest(paths.dist + paths.js.dist + paths.bower.dist))
.pipe(isProduction ? revall.manifest({
fileName: 'manifest-bower-js.json',
prefix: paths.webPrefix + paths.js.dist + paths.bower.dist
}) : fileList('manifest-bower-js.json',{
absolute: false,
prefix: paths.webPrefix + paths.js.dist + paths.bower.dist
}))
.pipe(gulp.dest(paths.dist))
;
});
// bower:css
gulp.task('bower:css', function() {

return gulp.src(bowerFiles.css, {base: path.join(process.cwd(), paths.bower.src)}) // https://github.com/sindresorhus/gulp-rev/issues/54#issuecomment-57231019
.pipe(isProduction ? sourcemaps.init() : gutil.noop())
.pipe(isProduction ? gconcat(paths.bower.concatFile+'.css') : gutil.noop())
.pipe(isProduction ? cssmin({
advanced: false,
relativeTo: paths.webPrefix + paths.css.dist + paths.bower.dist + "/"
}) : gutil.noop())
.pipe(isProduction ? revall() : gutil.noop())
.pipe(isProduction ? sourcemaps.write(paths.sourcemaps, {
sourceMappingURLPrefix: paths.webPrefix + paths.css.dist + paths.bower.dist + "/"
}) : gutil.noop())
.pipe(size({
title:'bower:css'
}))
.pipe(gulp.dest(paths.dist + paths.css.dist + paths.bower.dist))
.pipe(isProduction ? revall.manifest({
fileName: 'manifest-bower-css.json',
prefix: paths.webPrefix + paths.css.dist + paths.bower.dist
}) : fileList('manifest-bower-css.json',{
absolute: false,
prefix: paths.webPrefix + paths.css.dist + paths.bower.dist
}))
.pipe(gulp.dest(paths.dist))
;
});
// bower:fonts
gulp.task('bower:fonts', function() {

return gulp.src(bowerFiles.fonts)
.pipe(size({
title:'bower:fonts'
}))
.pipe(gulp.dest(paths.dist + paths.fonts.dist + paths.bower.dist))
;
});
// linting for js
// - so we get yelled at if our js isn't bad
gulp.task('lint:js', function() {
return gulp.src(paths.src + paths.js.src)
.pipe(jshint.reporter('jshint-stylish'))
.pipe(isProduction ? jshint.reporter('fail') : jshint.reporter('default'))
;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment