Skip to content

Instantly share code, notes, and snippets.

@paulhhowells
Last active May 12, 2016 10:46
Show Gist options
  • Save paulhhowells/41f9105e10a2327ff8d2bcd4c7c9a992 to your computer and use it in GitHub Desktop.
Save paulhhowells/41f9105e10a2327ff8d2bcd4c7c9a992 to your computer and use it in GitHub Desktop.
Gulp file for an Angular 1.x project
/*
A typical project directory structure would be similar to:
project/
- app/ # all the source angular files in here
- dist/ # compiled files saved here
--- app.js
--- app.min.js
- doc/ # generated documentation saved here
- node_modules/ # generated by npm install
- test/
--- karma.phantomjs.conf.js
--- report/
- .eslintrc.js
- .gitignore
- gulpfile.js
- index.html
- package.json
- README.md
*/
const
gulp = require('gulp'),
plug = require('gulp-load-plugins')(),
del = require('del'),
KarmaServer = require('karma').Server;
const PATH = {
app : 'app/**/!(*spec|*test).js',
appDoc : 'app/index.ngdoc',
coverage : 'test/report/coverage',
distribution : 'dist',
doc : 'doc',
lib : 'lib/**/!(*spec|*test).js',
tmp : 'tmp'
};
/*
* Run unit tests once and exit
*/
gulp.task('test', ['clean-coverage'], function (done) {
var karma = new KarmaServer({
configFile : __dirname + '/test/karma.phantomjs.conf.js',
singleRun : true,
reporters : ['progress', 'coverage'],
coverageReporter : {
// Specify a common output directory
dir : 'report/coverage',
reporters : [
// Reporters not supporting the `file` property
{ type : 'html', subdir : 'report-html' },
{ type : 'lcov', subdir : 'report-lcov' },
{ type : 'json', subdir : 'report-json' }
],
// Do not minify instrumenter output.
instrumenterOptions: {
istanbul : { noCompact : true }
}
}
}, done)
.on('error', function (err) {
throw err;
})
.start();
return karma;
});
gulp.task('clean-dist', function (callback) {
del([PATH.distribution], callback);
});
gulp.task('clean-coverage', function (callback) {
del([PATH.coverage], callback);
});
gulp.task('clean-tmp', ['angular'], function (callback) {
del([PATH.tmp], callback);
});
gulp.task('doc', ['readme'], function () {
// Read about how to write ngdocs at:
// https://github.com/angular/angular.js/wiki/Writing-AngularJS-Documentation
// https://github.com/idanush/ngdocs
// https://github.com/idanush/ngdocs/wiki/API-Docs-Syntax
var options = {
scripts : [
'../../node_modules/angular/angular.min.js',
'../../node_modules/angular/angular.min.js.map',
'../../node_modules/angular-route/angular-route.min.js',
'../../node_modules/angular-route/angular-route.min.js.map',
'../../node_modules/angular-animate/angular-animate.min.js',
'../../node_modules/angular-animate/angular-animate.min.js.map'
],
html5Mode : false,
title : 'Project Name',
startPage : '/api'
};
var sections = {
api: {
glob : [PATH.app, PATH.appDoc], //['app/**/*.js', '!app/**/*.spec.js'],
// Set the name for the section in the documentation app.
api : true,
title : 'API Documentation X'
},
tutorial : {
glob : ['app/docs/**/*.ngdoc'],
api : true,
title : 'Tutorial X'
},
readme : {
glob: ['README.md'],
title : 'Read Me'
}
};
return plug.ngdocs.sections(sections)
.pipe(plug.ngdocs.process(options))
.pipe(gulp.dest(PATH.doc))
.on('end', function () {
del([PATH.appDoc]);
});
});
gulp.task('readme', function () {
var header = '';
header += '@ngdoc overview\n';
header += '@name index\n';
header += '@description\n';
header += '\n';
return gulp.src('README.md')
.pipe(plug.insert.prepend(header))
.pipe(plug.rename({
basename : 'index',
extname : '.ngdoc'
}))
.pipe(gulp.dest('app/'));
});
// Linting
gulp.task('lint', function () {
var options = {
configFile : '.eslintrc.js'
};
return gulp.src([PATH.app])
.pipe(plug.eslint(options))
.pipe(plug.eslint.format());
});
/*
* Generate app.js and app.min.js
* Combine Angular JavaScript and HTML partials.
*/
gulp.task('angular', ['html'], function () {
var templates = PATH.tmp + '/templates.js';
return gulp.src([PATH.app, templates])
// Remove IIFEs that wrap files, and any use of 'use strict'.
.pipe(plug.replace(/^\(function\s*\(\)\s*\{\s*('use strict';)*/, ''))
// Match tail of IIFE as })(); or }());
.pipe(plug.replace(/\}(?:\)\(|\(\))\);\s*$/, ''))
// Add /lib to stream after IIFEs have been removed
// Should work when https://github.com/gulpjs/vinyl-fs/issues/25 is fixed.
// .pipe(gulp.src(PATH.lib))
// Concatenate all the angular files into a single JavaScript file.
.pipe(plug.concat('app.js'))
// Wrap in a single IIFE.
.pipe(plug.iife({
useStrict : true,
prependSemicolon : false,
trimCode : false
}))
// Save an unminified version.
.pipe(gulp.dest(PATH.distribution))
// Minify and save as app.min.js
.pipe(plug.uglify())
//.pipe(plug.rename({ extname: '.min.js' }))
.pipe(plug.rename({suffix: '.min'}))
.pipe(gulp.dest(PATH.distribution));
});
/*
* Convert HTML partials to JavaScript.
*/
gulp.task('html', ['lint'], function () {
// see: https://github.com/kangax/html-minifier
var htmlminOptions = {
// Remove insignificant white space
collapseWhitespace: true,
// Do not collapse <tag disabled="disabled"> to <tag disabled>
collapseBooleanAttributes: false,
// Keep attributes without values, and thus protect SVG.
empty: true,
removeComments: true,
removeCommentsFromCDATA: false,
removeOptionalTags: false,
removeAttributeQuotes: false
};
var templateCacheConfig = {
file : 'templates.js',
options : {
module : 'app'
}
};
return gulp.src('app/**/*.html')
// With Angular mark-up htmlmin may be improved upon, so do some
// extra processing first.
// Replace 3 or more whitespaces.
.pipe(plug.replace(/(\s){3,}/ig, " "))
// Process each opening tag and singleton tag.
.pipe(plug.replace(/<[^\/>]+\/??>/ig, processTags))
// Convert single quote attributes to double quotes.
.pipe(plug.htmlmin(htmlminOptions))
// Store template files in the temporary directory.
.pipe(gulp.dest(PATH.tmp + '/html'))
// Convert HTML templates to JavaScript.
.pipe(plug.angularTemplatecache(templateCacheConfig.file, templateCacheConfig.options))
// Save templates.js in the temporary directory.
.pipe(gulp.dest(PATH.tmp));
function processTags (tag) {
// Process tag attributes.
tag = tag.replace(/(=")([^"]+?)(")/ig, processAttributes);
return tag;
}
function processAttributes (match, p1, p2, p3) {
// Remove space from around single pipes in attributes.
p2 = p2.replace(/\s\|\s/ig, "|");
// Remove space from around OR double pipes in attributes.
p2 = p2.replace(/\s\|\|\s/ig, "||");
// Remove space from around AND ampersands in attributes.
p2 = p2.replace(/\s&&\s/ig, "&&");
// Remove space from around !==, === and ==
p2 = p2.replace(/\s!==\s/ig, "!==");
p2 = p2.replace(/\s===\s/ig, "===");
p2 = p2.replace(/\s==\s/ig, "==");
p2 = p2.replace(/\s\?\s/ig, "?");
p2 = p2.replace(/\s:\s/ig, ":");
// Remove space from after a single quote and colon within attributes.
p2 = p2.replace(/':\s+/ig, "':");
return p1 + p2 + p3;
}
});
gulp.task('open', function () {
return gulp
.src(__filename)
.pipe(plug.open({
uri: 'http://127.0.0.1:9999/'
}))
.pipe(plug.open({
uri: 'http://127.0.0.1:9999/test/report/coverage/report-html/'
}))
.pipe(plug.open({
uri: 'http://127.0.0.1:9999/doc/'
}));
});
gulp.task('build', ['clean-dist', 'html', 'angular', 'clean-tmp']);
gulp.task('default', function () {
gulp.start('clean-coverage', 'lint', 'test', 'doc', 'build');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment