sevenLee
11/4/2015 - 10:34 AM

Gulp example configuration file for an Express + AngularJS app find the complete explanation at : http://blog.scikr.com/from-grunt-to-gulpj

Gulp example configuration file for an Express + AngularJS app find the complete explanation at : http://blog.scikr.com/from-grunt-to-gulpjs/ simple-angular-gulp: http://blog.jhades.org/what-every-angular-project-likely-needs-and-a-gulp-build-to-provide-it/

////////////////////////////////////////////////////////////////////////////////
/**
 * @name Gulp taskrunner
 * @desc Gulp taskrunner for TickerTags.dashboard
 */

var gulp          = require('gulp'),
    gutil         = require('gulp-util'),
    gulpif        = require('gulp-if'),
    uglify        = require('gulp-uglify'),
    concat        = require('gulp-concat'),
    sass          = require('gulp-ruby-sass'),
    streamqueue   = require('streamqueue'),
    sourcemaps    = require('gulp-sourcemaps'),
    templateCache = require('gulp-angular-templatecache'),
    htmlReplace   = require('gulp-html-replace'),
    runSequence   = require('run-sequence'),
    del           = require('del'),
    es            = require('event-stream');

var config = {
    srcPartials:[
        'app/beta/*.html', 
        'app/header/**/*.html',
        'app/help/*.html',
        'app/login/*.html',
        'app/notificaitons/*.html',
        'app/panels/**/*.html',
        'app/popovers/**/*.html',
        'app/popovers/*.html',
        'app/user/*.html',
        'app/dashboard.html'
    ],
    srcPaths:[
        'beta/', 
        'header/',
        'help/',
        'login/',
        'notificaitons/',
        'panels/',
        'popovers/',
        'popovers/',
        'user/',
        'dashboard.html'
    ],
    destPartials: 'app/templates/'
};

var paths = {
    scripts: [
        'app/templates/*.js',
        'app/authentication/*js',
        'app/header/**/*.js',
        'app/help/*js',
        'app/helpers/*js',
        'app/beta/*.js',
        'app/login/*.js',
        'app/notifications/*.js',
        'app/panels/**/*.js',
        'app/popovers/*.js',
        'app/popovers/**/*.js',
        'app/popovers/**/**/*.js',
        'app/user/*.js',
        'app/*.js']
};

var stxPaths = {
    scripts: ['chartiq/js/stx.js',
              'chartiq/js/stxThirdParty.js',
              'chartiq/js/stxTimeZoneData.js',
              'chartiq/js/stxKernelOs.js',
              'chartiq/js/stxLibrary.js',
              'chartiq/js/stxAdvanced.js']
};

// ////////////////////////////////////////////////
// Log Errors
// // /////////////////////////////////////////////

function errorlog(err){
    console.log(err.message);
    this.emit('end');
}

/** Build Tasks */
/** ------------------------------------------------------------------------- */
////////////////////////////////////////////////////////////////////////////////

// Clear out all files and folders from build folder:
gulp.task('build:cleanfolder', function(cb) {
    del([
        'build/**'
    ], cb);
});

// Task to create build directory for all files:
gulp.task('build:copy', ['build:cleanfolder'], function() {
    return gulp.src('app/**')
    .pipe(gulp.dest('build/'));
});

// Task to remove unwated build files
// list all files and directories here that you don't want to include
gulp.task('build:remove', ['build:copy'], function(cb) {
    del([
        'build/gus.html',
        'build/authentication/',
        'build/beta/*.js',
        'build/header/**/*.js',
        'build/help/*.js',
        'build/helpers/',
        'build/login/*.js',
        'build/notifications/*.js',
        'build/panels/**/*.js',
        'build/popovers/**/*.js',
        'build/popovers/*.js',
        'build/user/*.js',
        'build/app.js'
    ], cb);
});

// 'build/js/!(*.min.js)'

// Task to make the index file production ready
gulp.task('build:index', function() {
  gulp.src('app/index.html')
    .pipe(htmlReplace({
        'stx-js': 'assets/js/libs/chartiq/stx.min.js',
        'app-js': 'assets/js/app.min.js'
    }))
    .pipe(gulp.dest('build/'));
});

gulp.task('build', function(cb) {
    runSequence('build:copy', 'build:remove', 'build:index', cb);
});


/** Main Gulp Tasks */
/** ------------------------------------------------------------------------- */
////////////////////////////////////////////////////////////////////////////////

// App modules
gulp.task('app-js', function() {
    return gulp.src(paths.scripts)
    .pipe(uglify())
    .pipe(concat('app.min.js'))
    .pipe(gulp.dest('app/assets/js'));
});

// Chart IQ
gulp.task('stx-js', function() {
    return gulp.src(stxPaths.scripts)
    .pipe(uglify())
    .pipe(concat('stx.min.js'))
    .pipe(gulp.dest('app/assets/js/libs/chartiq/'));
});

/** HTML Template caching */
/** ------------------------------------------------------------------------- */
// gulp.src(["beta/*.html", "!beta/beta.html"], {base: "beta"})
// return gulp.src(["app/*.html", "app/**/*.html", "app/**/**/*.html"], {base: "app"})
// return gulp.src(config.srcPartials, {base: 'app'})
gulp.task('html-templates', function() {
    return gulp.src(config.srcPartials)
    .pipe(templateCache('templateCache.js', {
        root: updateRoot(config.srcPaths)
    },
    { module:'templateCache', standalone:true })
    ).pipe(gulp.dest(config.destPartials));
});

function updateRoot(paths) {
    for (var i = 0; i < paths.length; i++) {
        // console.log(paths);
        console.log(paths[i]);
        return paths[i];
    }
}

/** Main Styles */
/** ------------------------------------------------------------------------- */
gulp.task('css', function() {
    return sass('bower_components/sass-smacss/sass/dashboard.scss', {
        // noCache: true,
        style: 'compressed' 
    })
    .pipe(sourcemaps.init())
    .on('error', errorlog)
    .pipe(sourcemaps.write('./maps'))
    .pipe(gulp.dest('app/assets/css/'))
});

/** ChartIQ Styles */
/** ------------------------------------------------------------------------- */
gulp.task('stx-css', function() {
    return sass('chartiq/sass/stx.scss', {
        // noCache: true,
        style: 'compressed' 
    })
    .pipe(sourcemaps.init())
    .on('error', errorlog)
    .pipe(sourcemaps.write('./maps'))
    .pipe(gulp.dest('app/assets/css/chartiq/'))
});

/** Development watch */
/** ------------------------------------------------------------------------- */
gulp.task('watch', function() {

    gulp.watch('app/**/**/*.html', ['html-templates']).on('change', function(file) {
        gutil.log(gutil.colors.yellow.bold('HTML updated' + ' (' + file.path + ')'));
    });

    gulp.watch('app/assets/imgs/*.svg').on('change', function(file) {
        gutil.log(gutil.colors.magenta('SVG updated' + ' (' + file.path + ')'));
    });

    gulp.watch('chartiq/sass/*.scss', ['stx-css']).on('change', function(file) {
        gutil.log(gutil.colors.cyan.bold('CSS updated' + ' (' + file.path + ')'));
    });

    gulp.watch('bower_components/sass-smacss/sass/**/*.scss', ['css']).on('change', function(file) {
        gutil.log(gutil.colors.cyan.bold('CSS updated' + ' (' + file.path + ')'));
    });

    gulp.watch('chartiq/js/*.js', ['stx-js']).on('change', function(file) {
        gutil.log(gutil.colors.red.bold('JavaScript updated' + ' (' + file.path + ')'));
    });

    gulp.watch(paths.scripts, ['app-js']).on('change', function(file) {
        gutil.log(gutil.colors.red.bold('JavaScript updated' + ' (' + file.path + ')'));
    });
});

var gulp = require('gulp'),
    webserver = require('gulp-webserver'),
    del = require('del'),
    sass = require('gulp-sass'),
    karma = require('gulp-karma'),
    jshint = require('gulp-jshint'),
    sourcemaps = require('gulp-sourcemaps'),
    spritesmith = require('gulp.spritesmith'),
    browserify = require('browserify'),
    source = require('vinyl-source-stream'),
    buffer = require('vinyl-buffer'),
    uglify = require('gulp-uglify'),
    gutil = require('gulp-util'),
    ngAnnotate = require('browserify-ngannotate');

var CacheBuster = require('gulp-cachebust');
var cachebust = new CacheBuster();

/////////////////////////////////////////////////////////////////////////////////////
//
// cleans the build output
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('clean', function (cb) {
    del([
        'dist'
    ], cb);
});

/////////////////////////////////////////////////////////////////////////////////////
//
// runs bower to install frontend dependencies
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('bower', function() {

    var install = require("gulp-install");

    return gulp.src(['./bower.json'])
        .pipe(install());
});

/////////////////////////////////////////////////////////////////////////////////////
//
// runs sass, creates css source maps
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('build-css', ['clean'], function() {
    return gulp.src('./styles/*')
        .pipe(sourcemaps.init())
        .pipe(sass())
        .pipe(cachebust.resources())
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest('./dist'));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// fills in the Angular template cache, to prevent loading the html templates via
// separate http requests
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('build-template-cache', ['clean'], function() {
    
    var ngHtml2Js = require("gulp-ng-html2js"),
        concat = require("gulp-concat");
    
    return gulp.src("./partials/*.html")
        .pipe(ngHtml2Js({
            moduleName: "todoPartials",
            prefix: "/partials/"
        }))
        .pipe(concat("templateCachePartials.js"))
        .pipe(gulp.dest("./dist"));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// runs jshint
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('jshint', function() {
    gulp.src('/js/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// runs karma tests
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('test', ['build-js'], function() {
    var testFiles = [
        './test/unit/*.js'
    ];

    return gulp.src(testFiles)
        .pipe(karma({
            configFile: 'karma.conf.js',
            action: 'run'
        }))
        .on('error', function(err) {
            console.log('karma tests failed: ' + err);
            throw err;
        });
});
/////////////////////////////////////////////////////////////////////////////////////
//
// Build a minified Javascript bundle - the order of the js files is determined
// by browserify
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('build-js', ['clean'], function() {
    var b = browserify({
        entries: './js/app.js',
        debug: true,
        paths: ['./js/controllers', './js/services', './js/directives'],
        transform: [ngAnnotate]
    });

    return b.bundle()
        .pipe(source('bundle.js'))
        .pipe(buffer())
        .pipe(cachebust.resources())
        .pipe(sourcemaps.init({loadMaps: true}))
        .pipe(uglify())
        .on('error', gutil.log)
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest('./dist/js/'));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// full build (except sprites), applies cache busting to the main page css and js bundles
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('build', [ 'clean', 'bower','build-css','build-template-cache', 'jshint', 'build-js'], function() {
    return gulp.src('index.html')
        .pipe(cachebust.references())
        .pipe(gulp.dest('dist'));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// watches file system and triggers a build when a modification is detected
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('watch', function() {
    return gulp.watch(['./index.html','./partials/*.html', './styles/*.*css', './js/**/*.js'], ['build']);
});

/////////////////////////////////////////////////////////////////////////////////////
//
// launches a web server that serves files in the current directory
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('webserver', ['watch','build'], function() {
    gulp.src('.')
        .pipe(webserver({
            livereload: false,
            directoryListing: true,
            open: "http://localhost:8000/dist/index.html"
        }));
});

/////////////////////////////////////////////////////////////////////////////////////
//
// launch a build upon modification and publish it to a running server
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('dev', ['watch', 'webserver']);

/////////////////////////////////////////////////////////////////////////////////////
//
// generates a sprite png and the corresponding sass sprite map.
// This is not included in the recurring development build and needs to be run separately
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('sprite', function () {

    var spriteData = gulp.src('./images/*.png')
        .pipe(spritesmith({
            imgName: 'todo-sprite.png',
            cssName: '_todo-sprite.scss',
            algorithm: 'top-down',
            padding: 5
        }));

    spriteData.css.pipe(gulp.dest('./dist'));
    spriteData.img.pipe(gulp.dest('./dist'))
});

/////////////////////////////////////////////////////////////////////////////////////
//
// installs and builds everything, including sprites
//
/////////////////////////////////////////////////////////////////////////////////////

gulp.task('default', ['sprite','build', 'test']);
// Gulp example configuration file for an Express + AngularJS app
// find the complete explanation at blog.scikr.com
//
// usage: `gulp serve` for development and `gulp build` for production
//
// run the following command to get all packages needed:
// npm install --save-dev gulp main-bower-files gulp-inject gulp-livereload gulp-watch gulp-nodemon streamqueue gulp-uglify gulp-concat gulp-ng-annotate gulp-rev gulp-rimraf run-sequence gulp-filter gulp-minify-css

// call the node packages
var gulp = require('gulp'),
  bowerFiles = require('main-bower-files'),
  inject = require('gulp-inject'),
  livereload = require('gulp-livereload'),
  watch = require('gulp-watch'),
  nodemon = require('gulp-nodemon'),
  streamqueue = require('streamqueue');

// jsfiles() streams all the js files (with exceptions) into a single stream for future injection
function jsfiles() {
  return streamqueue({ objectMode: true },
    // first streams vendor files from Bower (with a filter for exceptions)
    gulp.src(bowerFiles(), {read: false}).pipe(gulpFilter(['*.js', '!bootstrap-sass-official', '!bootstrap.js', '!json3', '!es5-shim'])),
    // then streams the app files
    gulp.src(['./client/+(app|components|services)/**/*.js'], {read: false})
  );
}

// cssfiles() streams all the css files (with exceptions) into a single stream for future injection
function cssfiles() {
  return streamqueue({ objectMode: true },
    // first streams vendor files from Bower (with a filter for exceptions)
    gulp.src(bowerFiles(), {read: false}).pipe(gulpFilter(['*.css', '!bootstrap-sass-official', '!bootstrap.js', '!json3', '!es5-shim'])),
    // then streams the app files
    gulp.src(['./client/+(app|components|services)/**/*.css'], {read:false})
  );
}

// create the inject task that inject successively ALL CSS stream, and ALL JS stream into index.html
gulp.task('inject', function(){
  return gulp.src('./client/index.html')
    .pipe(inject(jsfiles(), {relative:true}))
    .pipe(inject(cssfiles(), {relative:true}))
    .pipe(gulp.dest('./client/'));
});

gulp.task('watch', ['inject'], function() {
  // start the livereload server
  livereload.listen();
  // reload the browser when changes to any file in ./client/
  // dont forget to put the app.use(require('connect-livereload')()); in your express app
  gulp.watch('./client/**').on('change', livereload.changed);
});

// the serve task that we use for development
gulp.task('serve', ['watch'], function(){
  // nodemon starts the node app with monitoring of all files in the server folder (livereload takes care of the client)
  nodemon({
  script: 'server/app.js', // the app script
  watch: ['server/**/*.js'], // file to watch for reloading
  env: { 'PORT':3000 } })  // any environment variables
  .on('restart', function () {
    setTimeout(function() {livereload.changed();}, 1000);
    console.log('restarted!');
  });
});


/*
  Now for the distribution part:
*/

var uglify = require('gulp-uglify'),
  concat = require('gulp-concat'),
  ngAnnotate = require('gulp-ng-annotate'),
  rev = require('gulp-rev'),
  rimraf = require('gulp-rimraf'),
  runSequence = require('run-sequence'),
  gulpFilter = require('gulp-filter'),
  minifyCSS = require('gulp-minify-css');


gulp.task('build', function(callback) {
  // runSequence is a cool way of choosing what must run sequentially, and what in parallel
  // here, the task clean will run first alone, then all the builds in parallel, then the copies in parallel, then the injection in html
  runSequence(
    'clean',
    ['build-scripts', 'build-scripts-bower', 'build-styles', 'build-styles-bower'],
    ['copy-server', 'copy-assets', 'copy-client'],
    'build-html',
    callback);
});

// clean the dist folder
gulp.task('clean', function(){
  return gulp.src('./dist/**/*.*', {read:false})
    .pipe(rimraf());
});

// concatenate, annotate (for angular JS) and minify the js scripts into one single app.js file, then copy it to dist folder
gulp.task('build-scripts', function() {
  return gulp.src(['./client/app/**/*.js', './client/components/**/*.js', './client/services/**/*.js'])
    .pipe(concat('app.js')) // concatenate all js files
    .pipe(ngAnnotate()) // annotate to ensure proper dependency injection in AngularJS
    .pipe(uglify()) // minify js
    .pipe(rev()) // add a unique id at the end of app.js (ex: app-f4446a9c.js) to prevent browser caching when updating the website
    .pipe(gulp.dest('./dist/public/app')); // copy app-**.js to the appropriate folder
});

// same as above, with the bower files (no need to ngannotate)
gulp.task('build-scripts-bower', function() {
  return gulp.src(bowerFiles())
    .pipe(gulpFilter(['*.js', '!bootstrap-sass-official', '!bootstrap.js', '!json3', '!es5-shim']))
    .pipe(concat('vendor.js'))
    .pipe(uglify())
    .pipe(rev())
    .pipe(gulp.dest('./dist/public/app'));
});

// yet another concat/minify task, here for the CSS
gulp.task('build-styles',function() {
  return gulp.src(['./client/app/**/*.css', './client/components/**/*.css', './client/services/**/*.css'])
    .pipe(concat('app.css'))
    .pipe(minifyCSS())
    .pipe(rev())
    .pipe(gulp.dest('./dist/public/app'));
});

// and for vendor CSS
gulp.task('build-styles-bower', function() {
  return gulp.src(bowerFiles())
    .pipe(gulpFilter(['*.css', '!bootstrap-sass-official', '!json3',  '!es5-shim']))
    .pipe(concat('vendor.css'))
    .pipe(minifyCSS())
    .pipe(rev())
    .pipe(gulp.dest('./dist/public/app'));
});

// simple task to copy the server folder to dist/server
gulp.task('copy-server', function(){
  return gulp.src('./server/**/*.*')
    .pipe(gulp.dest('./dist/server'));
});

// copying the assets (images, fonts, ...)
gulp.task('copy-assets', function() {
  return gulp.src('./client/assets/**/*.*')
    .pipe(gulp.dest('./dist/public/assets'));
});

// copying the html files
gulp.task('copy-client', function(){
  return gulp.src('./client/**/**/*.+(html|txt|ico)')
    .pipe(gulp.dest('./dist/public/'));
});

// queues app.js and vendor.js
function buildjs() {
  return streamqueue({ objectMode: true },
      gulp.src('app/vendor*.js', {read:false, 'cwd': __dirname + '/dist/public/'}),
      gulp.src('app/app*.js', {read:false, 'cwd': __dirname + '/dist/public/'})
    );
}

// queues app.css and vendor.css
function buildcss() {
  return streamqueue({ objectMode: true },
      gulp.src('app/vendor*.css', {read:false, 'cwd': __dirname + '/dist/public/'}),
      gulp.src('app/app*.css', {read:false, 'cwd': __dirname + '/dist/public/'})
    );
}

// injection of both js files and css files in index.html
gulp.task('build-html', function() {
  return gulp.src('./client/index.html')
    .pipe(inject(buildjs(), {relative:false}))
    .pipe(inject(buildcss(), {relative:false}))
    .pipe(gulp.dest('./dist/public'));
});