Skip to content

Instantly share code, notes, and snippets.

@evaisse
Last active April 19, 2017 11:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save evaisse/2c9feac19496928ad1fd62459cff8122 to your computer and use it in GitHub Desktop.
Save evaisse/2c9feac19496928ad1fd62459cff8122 to your computer and use it in GitHub Desktop.
An Angular-seed tailored gulpfile, with ng-annotate, template pre-compile, html/css/js min, sourcemaps for css & js, revision & cache busting.
/**
* @author Emmanuel VAÏSSE <evaisse@gmail.com>
* @see https://gist.github.com/evaisse/2c9feac19496928ad1fd62459cff8122
*
* An Angular-seed (https://github.com/angular/angular-seed) tailored gulpfile, provide :
*
* - ng-annotate, prevengt loosing angular injection $annotation syntax against minification
* - angular template pre-compile
* - html/css/js minification
* - sourcemaps for css & js
* - css autoprefixer
* - assets url revision hash & cache busting
*
* Todos:
* - assets optim (images, svg, ...)
*
* How to Use:
*
* 1 — Install NPM required gulp build dependencies
*
* npm install --save-dev gulp gulp-htmlmin gulp-useref gulp-rename \
* gulp-cache-bust gulp-ng-annotate gulp-uglify gulp-cssnano \
* lazypipe gulp-sourcemaps gulp-if gulp-autoprefixer \
* gulp-angular-templatecache del gulp-rev gulp-rev-replace \
* gulp-filter gulp-concat gulp-insert
*
* 2 — Prepare your index{-async}.html file
*
* In your HTML entry point you should wrap js & css files into "useref" comments to specificy
* merge groups
*
* <!-- build:css css/combined.css -->
* <link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/normalize.css">
* <link rel="stylesheet" href="bower_components/html5-boilerplate/dist/css/main.css">
* <link rel="stylesheet" href="app.css">
* <!-- endbuild -->
*
* <!-- build:js js/head.js -->
* <script src="bower_components/html5-boilerplate/dist/js/vendor/modernizr-2.8.3.min.js"></script>
* <!-- endbuild -->
*
* 3 — Build
*
* run `gulp`, that's all.
* Build output will remains in ./dist
*
*/
var gulp = require('gulp');
var htmlmin = require('gulp-htmlmin');
var useref = require('gulp-useref');
var gulpRename = require('gulp-rename');
var cacheBuster = require('gulp-cache-bust');
var ngAnnotate = require('gulp-ng-annotate');
var uglify = require('gulp-uglify');
var cssnano = require('gulp-cssnano');
var lazypipe = require('lazypipe');
var sourcemaps = require('gulp-sourcemaps');
var gulpif = require('gulp-if');
var autoprefixer = require('gulp-autoprefixer');
var templateCache = require('gulp-angular-templatecache');
var del = require('del');
var rev = require('gulp-rev');
var revReplace = require('gulp-rev-replace');
var filter = require('gulp-filter');
var concat = require('gulp-concat');
var insert = require('gulp-insert');
var fs = require('fs');
// compressTasks is a sub process used by useRef (below) that
// compresses (takes out white space etc) the javascript and
// css files
var compressTasks = lazypipe()
.pipe(sourcemaps.init, { loadMaps: true })
.pipe(function() {
return gulpif('*.js', ngAnnotate());
})
.pipe(function() {
return gulpif('*.js', uglify());
})
.pipe(function() {
return gulpif('*.css', autoprefixer());
})
.pipe(function() {
return gulpif('*.css', cssnano({
zindex: false
}));
});
/**
* Helper func to fetch main module name regarding first app.js file
* then regarding the ng-app attributes
* @return {String} main module name
*/
var guessMainModuleName = function () {
var res,
htmlContent,
appContent;
appContent = fs.readFileSync('./app/app.js', { encoding: 'utf-8' });
res = appContent.match(/angular\.module\(["']([a-z0-9\-_]+)['"]/i);
if (res) {
return res[1];
}
htmlContent = fs.readFileSync(
fs.exists('./app/index-async.html') ? './app/index-async.html' : './app/index.html',
{ encoding: 'utf-8' }
);
res = htmlContent.match(/ng-app=\"([a-z0-9\-_]+)\"/i);
if (res) {
return res[1];
}
return "myApp";
};
// remove old dist dir
gulp.task('cleanup-dist', [], function() {
return del([
'dist',
// we don't want to clean this file though so we negate the pattern
'!dist/mobile/deploy.json'
]);
});
// copy all assets in dist
gulp.task('cleanup', ['cleanup-dist'], function() {
return gulp.src('./app/**/*.*').pipe(gulp.dest('dist'));
});
/**
* Create $templateCache from the html templates
* @return {Stream}
*/
gulp.task('templateCache', ['cleanup'], function() {
return gulp
.src('app/**/templates/*.html')
.pipe(htmlmin({ collapseWhitespace: true, removeComments: true }))
.pipe(templateCache({
module: guessMainModuleName(),
standalone: false
}))
.pipe(gulp.dest('app/cache'));
});
gulp.task("useref", ['templateCache'], function() {
var jsFilter = filter("**/*.js", { restore: true });
var cssFilter = filter("**/*.css", { restore: true });
var angularTemplateFilter = filter('app/**/templates/*.html', { restore: true });
var indexHtmlFilter = filter(['**/*', '!**/index.html'], { restore: true });
function relativeIfMap(filename) {
if (filename.indexOf('.map') > -1) {
// console.log(filename);
return filename.replace('js/', '').replace('css/', '');
}
return filename;
}
return gulp.src("app/index.html")
.pipe(sourcemaps.init())
.pipe(useref({
collapseWhitespace: true,
removeComments: true
},
lazypipe().pipe(compressTasks)
))
.pipe(gulpif('app/index.html', htmlmin()))
.pipe(sourcemaps.write('.'))
.pipe(indexHtmlFilter)
.pipe(rev()) // Rename the concatenated files (but not index.html)
.pipe(indexHtmlFilter.restore)
.pipe(revReplace({
modifyUnreved: relativeIfMap,
modifyReved: relativeIfMap
})) // Substitute in new filenames
.pipe(gulp.dest('dist'));
});
gulp.task("default", ['useref'], function () {
return gulp
.src('./dist/index.html')
.pipe(htmlmin({ collapseWhitespace: true, removeComments: true }))
.pipe(gulp.dest('dist'));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment