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'));
});