UNPKG

pho-devstack

Version:

Automated workflow for front-end developers in one tasty bowl of code

273 lines (223 loc) 8.38 kB
'use strict'; var chalk = require('chalk'); var extend = require('node.extend'); var mergeStream = require('merge-stream'); var path = require('path'); var through = require('through2'); var vinylSourceStream = require('vinyl-source-stream'); // we later iterate through this plugin object, plugin lazy loading has to be disabled var $ = require('gulp-load-plugins')({ config: require.resolve('./package.json'), lazy: false }); var stylish = require('jshint-stylish'); var defaultConfig = require('./config'); var testRunner = require('./lib/test-runner'); var Cache = require('./cache'); var files = require('./lib/get-files'); module.exports = function(gulp, userConfig) { var originalConfig = extend(true, {}, defaultConfig, userConfig); var config = extend(true, {}, originalConfig); var srcMarkupFiles = [ path.join(config.src.markupDir, config.src.markupFiles), '!' + path.join(config.src.markupDir, '{bower_components,bower_components/**}') ]; var cache = new Cache(); var getFolders = function(base, folders) { return gulp.src(folders.map(function(item) { return path.join(base, item); }), { base: base }); }; var isPluginEnabled = function(name) { return originalConfig[name] && originalConfig[name].enabled; }; var handleError = function(err, name) { if (isPluginEnabled('plumber')) { config.plumber.errorHandler(err, name); } else { throw err; } }; // remove "enabled" key from config for (var configName in config) { if (config.hasOwnProperty(configName) && config[configName].hasOwnProperty('enabled')) { delete config[configName].enabled; } } // start livereload server early if (isPluginEnabled('livereload')) $.livereload.listen(); var cdn = config.substituter.cdn || ''; // setup gulp-substituter js and css keys if (config.substituter) { if (!config.substituter.js) { config.substituter.js = function() { return files(path.join(config.dist.scriptDir, config.dist.scriptFiles), function(name) { return '<script src="' + cdn + 'scripts/' + name + '"></script>'; }); }; } if (!config.substituter.css) { config.substituter.css = function() { return files(path.join(config.dist.styleDir, config.dist.styleFiles), function(name) { return '<link rel="stylesheet" href="' + cdn + 'styles/' + name + '">'; }); }; } } // disabled gulp plugins are replaced with stream that passes everything through for (var pluginName in $) { if ($.hasOwnProperty(pluginName)) { if (!isPluginEnabled(pluginName)) { $[pluginName] = through.obj; } } } var browserify = isPluginEnabled('watch') ? require('watchify') : require('browserify'); config.browserify.entries = './' + path.join(config.src.scriptDir, config.src.scriptMain); var bundler = browserify(config.browserify); // apply browserify transforms from config // hack with Array.prototype.reverse() is used, because V8 iterates over objects in reversed order // https://code.google.com/p/v8/issues/detail?id=164 Object.keys(config.browserify.transforms).reverse().forEach(function (transform) { if (config.browserify.transforms[transform]) bundler.transform(transform); }); var scriptsDependencies = []; if (isPluginEnabled('jshint')) scriptsDependencies.push('jshint'); if (isPluginEnabled('jscs')) scriptsDependencies.push('jscs'); gulp.task('scripts', scriptsDependencies, function(cb) { if (cache.isClean('scripts')) { return cb(); } cache.setClean('scripts'); gulp.src(path.join(config.dist.scriptDir, config.dist.scriptFiles), { read: false }) .pipe($.clean()) .on('end', function() { bundler.bundle(config.browserify) .on('error', function(err) { handleError(err, 'browserify'); cb(); }) .pipe(vinylSourceStream(config.dist.scriptMain)) .pipe($.plumber(config.plumber)) .pipe($.rename({ suffix: '-' + Date.now().toString() })) .pipe(gulp.dest(config.dist.scriptDir)) .on('end', cb); }); }); gulp.task('jshint', function() { return gulp.src(path.join(config.src.scriptDir, config.src.scriptFiles)) .pipe($.jshint(config.src.jshint)) .pipe($.jshint.reporter(stylish)); }); gulp.task('jscs', function(cb) { return gulp.src(path.join(config.src.scriptDir, config.src.scriptFiles)) .pipe($.jscs()) .on('error', function(err) { handleError(err); cb(); }); }); gulp.task('styles', function(cb) { if (cache.isClean('styles')) { return cb(); } cache.setClean('styles'); var spriteFilter = $.filter('**/*.png'); var cssFilter = $.filter('**/*.css'); gulp.src(path.join(config.dist.styleDir, config.dist.styleFiles), { read: false }) .pipe($.clean()) .on('end', function() { gulp.src(path.join(config.src.styleDir, config.src.styleMain)) .pipe($.plumber(config.plumber)) .pipe($.less(config.less)) .pipe($.base64(config.base64)) .pipe($.spritesPreprocessor(config.spritesPreprocessor)) .pipe(spriteFilter) .pipe(gulp.dest(config.dist.spriteDir)) .pipe(spriteFilter.restore()) .pipe(cssFilter) .pipe($.rename({ suffix: '-' + Date.now().toString() })) .pipe(gulp.dest(config.dist.styleDir)) .on('end', cb); }); }); var indexDependencies = ['scripts', 'styles', 'images'].concat(config.indexDependencies); gulp.task('index', indexDependencies, function() { var streams = []; if (cache.isDirty('markups') || isPluginEnabled('rename')) { cache.setClean('markups'); var markupStream = gulp.src(srcMarkupFiles) .pipe($.plumber(config.plumber)) .pipe($.substituter(config.substituter)) .pipe($.htmlmin(config.htmlmin)); streams.push(markupStream); } if (config.copy.length) { streams.push(getFolders(config.src.markupDir, config.copy)); } if (streams.length) { return mergeStream.apply(null, streams).pipe(gulp.dest(config.dist.markupDir)); } }); gulp.task('images', function() { return gulp.src([path.join(config.src.imageDir, '**/*'), '!' + path.join(config.src.imageDir, 'sprites/**/*')]) .pipe($.plumber(config.plumber)) .pipe($.newer(config.dist.imageDir)) .pipe($.imagemin(config.imagemin)) .pipe(gulp.dest(config.dist.imageDir)); }); gulp.task('test', ['index'], function() { testRunner.karma(); }); gulp.task('testContinuous', ['index'], function() { testRunner.karmaWatch(); }); gulp.task('e2e', ['index'], function() { if (isPluginEnabled('e2e')) { testRunner.casper(path.join(config.src.specDir, config.src.e2eDir)); } }); var defaultDependencies = ['index'].concat(config.defaultDependencies); if (isPluginEnabled('karma')) { if (isPluginEnabled('watch')) defaultDependencies.push('testContinuous'); else defaultDependencies.push('test'); } gulp.task('default', defaultDependencies, function() { if (!isPluginEnabled('watch')) { return; } // watchify has its own watcher bundler.on('update', function() { cache.setDirty('scripts'); gulp.start('index'); }); gulp.watch(path.join(config.src.styleDir, config.src.styleFiles), ['index']) .on('change', function() { cache.setDirty('styles'); }); gulp.watch(srcMarkupFiles, ['index']) .on('change', function() { cache.setDirty('markups'); }); gulp.watch([ path.join(config.src.specDir, config.src.specFiles), path.join(config.src.imageDir, '**/*') ], ['index']); if (isPluginEnabled('livereload')) { $.livereload.listen(); gulp.watch(path.join(config.dist.markupDir, config.dist.markupFiles), $.livereload.changed); if (!isPluginEnabled('rename')) { // markup is not changed when rename is disabled, we can livereload gulp.watch([ path.join(config.dist.scriptDir, config.dist.scriptFiles), path.join(config.dist.styleDir, config.dist.styleFiles) ], $.livereload.changed); } } }); return { $: $, cache: cache, config: config } };