Skip to content

Instantly share code, notes, and snippets.

@cesarandreu
Created September 2, 2014 19:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cesarandreu/9f6158959493f3565065 to your computer and use it in GitHub Desktop.
Save cesarandreu/9f6158959493f3565065 to your computer and use it in GitHub Desktop.
Gulpfiles
'use strict';
var gulp = require('gulp'),
_ = require('lodash'),
path = require('path'),
runSequence = require('run-sequence'),
mergeStream = require('merge-stream'),
streamqueue = require('streamqueue'),
// gutil = require('gulp-util'),
// debug = require('gulp-debug'),
mincss = require('gulp-minify-css'),
uglify = require('gulp-uglify'),
sourcemaps = require('gulp-sourcemaps'),
rev = require('gulp-rev'),
revCollector = require('gulp-rev-collector'),
autoprefixer = require('gulp-autoprefixer'),
image = require('gulp-image'),
clone = require('gulp-clone'),
concat = require('gulp-concat'),
injector = require('gulp-inject'),
preprocess = require('gulp-preprocess'),
ngannotate = require('gulp-ng-annotate'),
htmlmin = require('gulp-htmlmin'),
templateCache = require('gulp-angular-templatecache'),
rimraf = require('gulp-rimraf'),
rename = require('gulp-rename'),
jade = require('gulp-jade'),
coffee = require('gulp-coffee'),
sass = require('gulp-sass'),
gulpif = require('gulp-if'),
configuration = require('./configuration'),
files = require(configuration.files);
// Appends './app' to all files
var prefixedFiles = {};
_(['scripts', 'application', 'templates', 'styles', 'images', 'fonts', 'others'])
.map(function (name) {
prefixedFiles[name] = _.map(files[name], function (file) {
return path.join(configuration.app, file);
});
});
// TASKS START HERE
// Removes build folder
gulp.task('clean', function () {
return gulp
.src(configuration.buildDirectory, {read: false})
.pipe(rimraf({force: true}));
});
// Removes output folder (../../public)
gulp.task('clean-output', function () {
return gulp
.src(configuration.output, {read: false})
.pipe(rimraf({force: true}));
});
// Renders main.html application, injects .js/.css files
gulp.task('application', function () {
var renamedScripts = gulp.src('../build/scripts/scripts-*.js', {base: configuration.buildDirectory});
var renamedStyles = gulp.src('../build/styles/styles-*.css', {base: configuration.buildDirectory});
// Removes './app' in filepath and returns the script/style tag
var scriptTag = _.template('<script src="<%= filepath %>"></script>');
var styleTag = _.template('<link rel="stylesheet" href="<%= filepath %>">');
function transformScript(filepath) {
return scriptTag({filepath: filepath.replace(path.resolve(configuration.buildDirectory), '')});
}
function transformStyle(filepath) {
return styleTag({filepath: filepath.replace(path.resolve(configuration.buildDirectory), '')});
}
return gulp
.src(prefixedFiles.application, {base: configuration.app})
.pipe(gulpif(/\.jade$/, jade({
pretty: true,
doctype: 'html',
locals: configuration.locals
})))
.pipe(injector(renamedScripts, {transform: transformScript}))
.pipe(injector(renamedStyles, {transform: transformStyle}))
.pipe(preprocess({
context: configuration.context
}))
.pipe(gulp.dest(configuration.buildDirectory));
});
gulp.task('assets', function () {
// Get all images
// Save to /img folder
// Rev and save to /img folder
// Get the rev manifest
var images = gulp
.src(prefixedFiles.images, {base: configuration.app})
.pipe(image())
.pipe(gulp.dest(configuration.buildDirectory))
.pipe(rev())
.pipe(gulp.dest(configuration.buildDirectory))
.pipe(rev.manifest());
// Get css styles
var css = gulp.src(prefixedFiles.styles.concat('!/**/*.scss'), {base: configuration.app});
// Get sass styles
// Compile sass
var scss = gulp
.src(prefixedFiles.styles.concat('!/**/*.css'), {base: configuration.app})
.pipe(sass({
errLogToConsole: true,
includePaths: [path.join(process.cwd(), configuration.app, 'styles/')]
}));
// Queue sass and css afterward
// Apply prefixes for older browsers
// Minify styles
// Concatenate files
var styles = streamqueue({ objectMode: true }, scss, css)
.pipe(autoprefixer(['last 2 versions', '> 5%']))
.pipe(mincss())
.pipe(concat('/styles/styles.css'));
// Merge styles stream with cloned images-manifest stream
// Replace image links in css
// Rev and save to /styles folder
styles = mergeStream(styles, images.pipe(clone()))
.pipe(revCollector())
.pipe(rev())
.pipe(gulp.dest(configuration.buildDirectory));
// Get all templates
// Compile jade files
// Minify html
// Aply preprocessor
var templates = gulp
.src(prefixedFiles.templates, {base: configuration.app})
.pipe(gulpif(/\.jade$/, jade({
pretty: false,
doctype: 'html',
locals: configuration.locals
})))
.pipe(rename(function () {
// DO NOT REMOVE
// Removing this breaks template cache url
}))
.pipe(htmlmin({
removeEmptyAttributes: true,
removeRedundantAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true
}))
.pipe(preprocess({
context: configuration.context
}));
// Merge templates stream with cloned images-manifest stream
// Replace image links in templates
// Save templates to /template and /views
// Convert all templates into angularjs injectable strings
templates = mergeStream(templates, images.pipe(clone()))
.pipe(revCollector())
.pipe(gulp.dest(configuration.buildDirectory)) // should also copy over templates
.pipe(templateCache({
module: configuration.module
}))
.pipe(rename(function (file) {
// Renames from ./templates.js to ./scripts/templates.js
file.dirname = path.join(file.dirname, 'scripts');
return file;
}));
// Get all scripts
var scripts = gulp.src(prefixedFiles.scripts, {base: configuration.app});
// Compile coffeescript
// Apply preprocessor
// Apply ngannotate
// Merge scripts stream with javascript-ified templates
// UglifyJS will concatenate and minify everything
// Rev (only js files, so it'll ignore source maps) and save to /scripts folder
scripts = mergeStream(scripts, templates)
.pipe(gulpif(/\.coffee$/, coffee({
bare: true
})))
.pipe(gulpif(function (file) {
return file.path.indexOf('bower_components') === -1;
}, preprocess({
context: configuration.context
})))
.pipe(gulpif(function (file) {
return file.path.indexOf('bower_components') === -1;
}, ngannotate({
add: true,
single_quotes: true
})))
.pipe(gulp.dest(configuration.buildDirectory))
.pipe(sourcemaps.init())
.pipe(concat('/scripts/scripts.js'))
.pipe(uglify())
.pipe(sourcemaps.write('/', {sourceRoot: '/'}))
.pipe(gulpif(/\.js$/, rev()))
.pipe(gulp.dest(configuration.buildDirectory));
return mergeStream(scripts, styles);
});
// Copies other files
gulp.task('copy', function () {
var fileList = []
.concat(prefixedFiles.fonts)
.concat(prefixedFiles.others);
return gulp
.src(fileList, {base: configuration.app})
.pipe(gulp.dest(configuration.buildDirectory));
});
gulp.task('copy-output', function () {
return gulp
.src(path.join(configuration.buildDirectory, '/**/*'))
.pipe(gulp.dest(configuration.output));
});
gulp.task('build:production', function(cb) {
process.env.NODE_ENV = 'production';
runSequence('build', cb);
});
gulp.task('build', function (cb) {
runSequence(
'clean',
['assets', 'copy'],
'application',
'clean-output',
'copy-output',
cb
);
});
gulp.task('default', ['build']);
'use strict';
var gulp = require('gulp'),
runSequence = require('run-sequence'),
gutil = require('gulp-util'),
// debug = require('gulp-debug'),
livereload = require('gulp-livereload'),
express = require('express'),
httpProxy = require('http-proxy'),
morgan = require('morgan'),
path = require('path'),
_ = require('lodash'),
injector = require('gulp-inject'),
autoprefixer = require('gulp-autoprefixer'),
preprocess = require('gulp-preprocess'),
newer = require('gulp-newer'),
rimraf = require('gulp-rimraf'),
rename = require('gulp-rename'),
jade = require('gulp-jade'),
templateCache = require('gulp-angular-templatecache'),
coffee = require('gulp-coffee'),
sass = require('gulp-sass'),
gulpif = require('gulp-if'),
openurl = require('openurl'),
url = require('url'),
configuration = require('./configuration'),
files = require(configuration.files);
// Appends './app' to all files
var prefixedFiles = {};
_(['scripts', 'application', 'templates', 'styles', 'images', 'fonts', 'others'])
.map(function (name) {
prefixedFiles[name] = _.map(files[name], function (file) {
return path.join(configuration.app, file);
});
});
// TASKS START HERE
// Removes .build folder
gulp.task('clean', function () {
return gulp
.src(configuration.devDirectory, {read: false})
.pipe(rimraf({force: true}));
});
// Compiles coffeescript, applies preprocessor
gulp.task('scripts', function () {
return gulp
.src(prefixedFiles.scripts, {base: configuration.app})
.pipe(newer({
dest: configuration.devDirectory,
ext: '.js'
}))
.pipe(gulpif(/\.coffee$/, coffee({
bare: true
// sourceMap: true
})))
.pipe(gulpif(function (file) {
return file.path.indexOf('bower_components') === -1;
}, preprocess({
context: configuration.context
})))
.pipe(gulp.dest(configuration.devDirectory));
});
// Renders main.html application, injects .js/.css files
gulp.task('application', function () {
// Renames .coffee files to .js for injector
var renamedScripts = gulp
.src(prefixedFiles.scripts, {read: false})
.pipe(rename({extname: '.js'}));
// Renames .scss/.less files to .css for injector
var renamedStyles = gulp
.src(prefixedFiles.styles, {read: false})
.pipe(rename({extname: '.css'}));
// Removes './app' in filepath and returns the script/style tag
var scriptTag = _.template('<script src="<%= filepath %>"></script>');
var styleTag = _.template('<link rel="stylesheet" href="<%= filepath %>">');
function transformScript(filepath) {
return scriptTag({filepath: filepath.replace(path.resolve(configuration.app), '')});
}
function transformStyle(filepath) {
return styleTag({filepath: filepath.replace(path.resolve(configuration.app), '')});
}
return gulp
.src(prefixedFiles.application, {base: configuration.app})
.pipe(newer({
dest: configuration.devDirectory,
ext: '.html'
}))
.pipe(gulpif(/\.jade$/, jade({
pretty: true,
doctype: 'html',
locals: configuration.locals
})))
.pipe(injector(renamedScripts, {transform: transformScript}))
.pipe(injector(renamedStyles, {transform: transformStyle}))
.pipe(preprocess({
context: configuration.context
}))
.pipe(gulp.dest(configuration.devDirectory));
});
// Compiles views and templates jade files
gulp.task('templates', function () {
return gulp
.src(prefixedFiles.templates, {base: configuration.app})
.pipe(newer({
dest: configuration.devDirectory,
ext: '.html'
}))
.pipe(gulpif(/\.jade$/, jade({
pretty: true,
doctype: 'html',
locals: configuration.locals
})))
.pipe(preprocess({
context: configuration.context
}))
.pipe(gulp.dest(configuration.devDirectory))
.pipe(templateCache({
module: configuration.module
}))
.pipe(rename(function (file) {
// Renames from ./templates.js to ./scripts/templates.js
file.dirname = path.join(file.dirname, 'scripts');
return file;
}))
.pipe(gulp.dest(configuration.devDirectory));
});
// Compiles sass and css files
gulp.task('styles', function () {
return gulp
.src(prefixedFiles.styles, {base: configuration.app})
.pipe(newer({
dest: configuration.devDirectory,
ext: '.css'
}))
.pipe(gulpif(/\.css$/, autoprefixer()))
.pipe(gulpif(/\.scss$/, sass({
errLogToConsole: true,
sourceComments: 'map'
})))
.pipe(gulp.dest(configuration.devDirectory));
});
// Copies other files
gulp.task('copy', function () {
var fileList = []
.concat(prefixedFiles.images)
.concat(prefixedFiles.fonts)
.concat(prefixedFiles.others);
return gulp
.src(fileList, {base: configuration.app})
.pipe(newer({
dest: configuration.devDirectory
}))
.pipe(gulp.dest(configuration.devDirectory));
});
gulp.task('watch', function () {
var copyList = []
.concat(prefixedFiles.images)
.concat(prefixedFiles.fonts)
.concat(prefixedFiles.others),
lr = livereload();
// watchStyles = []
// .concat(prefixedFiles.styles)
// .concat(_.map(configuration.watch.styles, function (file) {
// return path.join(configuration.app, file);
// }));
gulp.watch(prefixedFiles.scripts, ['scripts']);
gulp.watch(prefixedFiles.templates, ['templates']);
gulp.watch(prefixedFiles.styles, ['styles']);
gulp.watch(prefixedFiles.application, ['application']);
gulp.watch(copyList, ['copy']);
gulp.watch([
configuration.devDirectory + '/{,**/}*.{html,css,js}',
'!' + configuration.devDirectory + '/bower_components/{,**/}*',
'!' + configuration.devDirectory + '/scripts/viewer/*',
'!' + configuration.devDirectory + '/img/{,**/}*'
])
.on('change', function (file) {
lr.changed(file.path);
});
});
gulp.task('server', function (done) {
var app = express(),
proxy = httpProxy.createProxyServer({});
proxy.on('error', function (e) {
gutil.log(gutil.colors.red('Proxy error:'), e);
});
app.use(morgan('dev'));
app.use(require('connect-livereload')());
app.use(express.static(path.resolve(__dirname, configuration.devDirectory)));
app.use(express.static(path.resolve(__dirname, configuration.reqDirectory)));
app.use(function (req, res, next) {
if (configuration.server.proxy.regex.test(req.url)) {
// this gets ignored
// res.setHeader('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
// res.header('Cache-Control', 'no-cache, no-store, must-revalidate');
// res.header('Pragma', 'no-cache');
// res.header('Expires', 0);
proxy.web(req, res, {target: configuration.server.proxy.url});
} else {
next();
}
});
app.use(function (req, res) {
gutil.log('Responding with', gutil.colors.cyan(configuration.main));
res.sendfile(path.resolve(__dirname, configuration.devDirectory, configuration.main));
});
app.listen(configuration.server.port, function () {
// Lets gulp know the task is done
done();
});
});
gulp.task('open', function () {
openurl.open(url.format({
protocol: 'http',
hostname: 'localhost',
port: configuration.server.port
}));
});
gulp.task('serve', function (cb) {
runSequence(
'clean',
['scripts', 'templates', 'styles', 'application', 'copy'],
'server',
'watch',
'open',
cb
);
});
gulp.task('default', ['serve']);
// Ran this to rename .js.coffee to .cofee
// rename 's/.js.coffee$/.coffee/' *.js.coffee
'use strict';
var gulp = require('gulp'),
request = require('request'),
runSequence = require('run-sequence'),
karma = require('karma').server,
batch = require('gulp-batch'),
spawn = require('child_process').spawn,
exec = require('child_process').exec,
_ = require('lodash'),
protractor = require('gulp-protractor').protractor,
glob = require('glob'),
webdriverUpdate = require('gulp-protractor').webdriver_update;
// bundle exec rake integration:prepare
gulp.task('rails:prepare', function (done) {
var child = exec('bundle exec rake integration:prepare', {
pwd: '../..'
});
child.stdout.on('data', function (data) {
console.log('prepare:', data.replace(/(\r\n|\n|\r)/gm,''));
});
child.stderr.on('data', function (data) {
console.log('prepare:', data.replace(/(\r\n|\n|\r)/gm,''));
});
child.on('close', function (code) {
done(code);
});
});
// bundle exec rake integration:run
gulp.task('rails:run', function (done) {
var child = spawn('bundle', ['exec', 'rake', 'integration:run'], {
pwd: '../..'
});
child.stderr.on('data', function (data) {
console.log('server:', data.toString().replace(/(\r\n|\n|\r)/gm,''));
});
child.stdout.on('data', function (data) {
console.log('server:', data.toString().replace(/(\r\n|\n|\r)/gm,''));
});
process.on('exit', function () {
child.kill('SIGINT');
});
process.on('SIGINT', function () {
process.exit(2);
});
function isReady (count) {
request('http://localhost:4000/', function (err, res) {
if (count > 100) {
done(count);
} else if (!err && res.statusCode === 200) {
done();
} else {
setTimeout(function () {
isReady(++count);
}, 250);
}
});
}
console.log('Trying to start rails server on port 4000...');
isReady(0);
});
gulp.task('rails', function (done) {
runSequence(
'rails:prepare',
'rails:run',
done
);
});
gulp.task('protractor:full', function () {
return gulp.src('../test/e2e/**/*_spec.*')
.pipe(protractor({
configFile: '../protractor.full.conf.js'
}));
});
gulp.task('protractor:circle', function () {
var CIRCLE_TOTAL = _.parseInt(process.env.CIRCLE_NODE_TOTAL) || 1,
CIRCLE_INDEX = _.parseInt(process.env.CIRCLE_NODE_INDEX) || 0;
var files = _.chain(glob.sync('../test/e2e/**/*_spec.*'))
.sortBy(function (name) {
return name;
})
.filter(function (file, idx) {
return idx % CIRCLE_TOTAL === CIRCLE_INDEX;
})
.value();
console.log('Files:', files);
return gulp.src(files)
.pipe(protractor({
configFile: '../protractor.circle.conf.js'
}));
});
gulp.task('protractor:live', function () {
gulp.watch('../test/e2e/**/*_spec.*', batch(function (events, done) {
events
.pipe(protractor({
args: process.env.DEBUG === 'true' ? ['debug'] : [],
configFile: '../protractor.live.conf.js'
})).on('error', function () {
done();
}).on('end', function () {
done();
});
}));
});
gulp.task('webdriver:update', webdriverUpdate);
gulp.task('webdriver:start', function () {
var child = spawn('../node_modules/.bin/webdriver-manager', ['start']);
child.stderr.on('data', function (data) {
console.log('webdriver:', data.toString().replace(/(\r\n|\n|\r)/gm,''));
});
child.stdout.on('data', function (data) {
console.log('webdriver:', data.toString().replace(/(\r\n|\n|\r)/gm,''));
});
process.on('exit', function () {
child.kill('SIGINT');
});
process.on('SIGINT', function () {
process.exit(2);
});
});
gulp.task('webdriver:live', function () {
var child = spawn('../node_modules/.bin/webdriver-manager', ['start']);
process.on('exit', function () {
child.kill('SIGINT');
});
process.on('SIGINT', function () {
process.exit(2);
});
});
gulp.task('e2e:full', ['webdriver:start', 'protractor:full']);
gulp.task('e2e:live', ['webdriver:live', 'protractor:live']);
gulp.task('e2e:circle', ['protractor:circle']);
gulp.task('karma:live', function (done) {
// Paths are all relative to this file's location
var files = _.map(require('../app/files.js').scripts, function (file) {
return '../devbuild' + file;
});
files.push('../app/bower_components/angular-mocks/angular-mocks.js');
files.push('../test/unit/**/*.js');
console.log('FILES', files);
var config = require('../karma.conf.js')();
config.reporters = ['progress'];
config.singleRun = false;
config.files = files;
config.basePath = '';
karma.start(config, function (exitCode) {
done(exitCode);
process.exit(exitCode);
});
});
gulp.task('karma:full', function (done) {
// Paths are all relative to this file's location
var files = _.map(require('../app/files.js').scripts, function (file) {
return '../build' + file;
});
files.push('../app/bower_components/angular-mocks/angular-mocks.js');
files.push('../test/unit/**/*.js');
console.log('FILES', files);
var config = require('../karma.conf.js')();
config.reporters = ['progress'];
config.singleRun = true;
config.files = files;
config.basePath = '';
karma.start(config, function (exitCode) {
done(exitCode);
process.exit(exitCode);
});
});
gulp.task('karma:circle', function (done) {
var CIRCLE_TOTAL = _.parseInt(process.env.CIRCLE_NODE_TOTAL);
var CIRCLE_INDEX = _.parseInt(process.env.CIRCLE_NODE_INDEX);
// Paths are all relative to this file's location
var files = _.map(require('../app/files.js').scripts, function (file) {
return '../build' + file;
});
files.push('../app/bower_components/angular-mocks/angular-mocks.js');
files = files.concat(
_.chain(glob.sync('../test/unit/**/*.js'))
.sortBy(function (name) {
return name;
})
.filter(function (file, idx) {
return idx % CIRCLE_TOTAL === CIRCLE_INDEX;
})
.value()
);
console.log('FILES', files);
var config = require('../karma.conf.js')();
config.reporters = ['dots'];
config.singleRun = true;
config.files = files;
config.basePath = '';
karma.start(config, function (exitCode) {
done(exitCode);
process.exit(exitCode);
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment