Skip to content

Instantly share code, notes, and snippets.

@OverZealous
Last active May 26, 2016 19:39
Show Gist options
  • Star 18 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save OverZealous/8343073 to your computer and use it in GitHub Desktop.
Save OverZealous/8343073 to your computer and use it in GitHub Desktop.
Gulpfile for replicating ngboilerplate
//<editor-fold desc="Node Requires, gulp, etc">
var gulp = require('gulp'),
autoprefixer = require('gulp-autoprefixer'),
clean = require('gulp-clean'),
concat = require('gulp-concat'),
csso = require('gulp-csso'),
debug = require('gulp-debug'),
footer = require('gulp-footer'),
gutil = require('gulp-util'),
gzip = require('gulp-gzip'),
header = require('gulp-header'),
help = require('gulp-task-listing'),
_if = require('gulp-if'),
inject = require('gulp-inject'),
jshint = require('gulp-jshint'),
karma = require('gulp-karma'),
less = require('gulp-less'),
livereload = require('gulp-livereload'),
livereloadEmbed = require('gulp-embedlr'),
minifyHtml = require('gulp-minify-html'),
ngHtml2js = require('gulp-ng-html2js'),
ngmin = require('gulp-ngmin'),
plumber = require('gulp-plumber'),
recess = require('gulp-recess'),
rename = require('gulp-rename'),
rev = require('gulp-rev'),
tap = require('gulp-tap'),
uglify = require('gulp-uglify'),
watch = require('gulp-watch'),
_ = require('lodash'),
anysort = require('anysort'),
connect = require('connect'),
es = require('event-stream'),
fs = require('fs'),
http = require('http'),
lazypipe = require('lazypipe'),
open = require('open'),
path = require('path'),
runSequence = require('run-sequence'),
server = require('tiny-lr')();
//</editor-fold>
// Load user config and package data
var cfg = require('./build.config.js');
// common variables
var concatName = cfg.pkg.name;
//=============================================
// MAIN TASKS
//=============================================
gulp.task('default', ['watch']);
gulp.task('server', ['watch'], function(cb) {
startServer(cb);
});
gulp.task('build', function(cb) {
runSequence(['build-assets', 'build-scripts', 'build-styles'], ['build-html', 'test'], cb);
});
gulp.task('watch', ['lr-server', 'build', 'test-watch'], function() {
watch({glob: cfg.watchFiles.js, emitOnGlob: false, name: 'JS'})
.pipe(plumber())
.pipe(jsBuildTasks())
.pipe(livereload(server));
watch({glob: cfg.watchFiles.tpl, emitOnGlob: false, name: 'Templates'})
.pipe(plumber())
.pipe(tplBuildTasks())
.pipe(livereload(server));
watch({glob: cfg.watchFiles.html, emitOnGlob: false, name: 'HTML'}, function() {
return buildHTML();
});
watch({glob: cfg.watchFiles.less, emitOnGlob: false, name: 'Styles'}, function() {
// run this way to ensure that a failed pipe doesn't break the watcher.
return buildStyles();
});
watch({glob: cfg.watchFiles.assets, emitOnGlob: false, name: 'Assets'})
.pipe(gulp.dest(join(cfg.buildDir, cfg.assetsDir)));
});
gulp.task('compile', function() {
runSequence(
'compile-clean',
['compile-assets', 'compile-scripts', 'compile-styles'],
'compile-html'
);
});
gulp.task('clean', ['compile-clean', 'build-clean']);
gulp.task('help', help);
//=============================================
// UTILITIES
//=============================================
function readFile(filename) {
return fs.existsSync(filename) ? fs.readFileSync(filename, {encoding: 'utf8'}) : '';
}
var join = path.join;
var embedLR = false;
function startServer(cb) {
var devApp, devServer, devAddress, devHost, url, log=gutil.log, colors=gutil.colors;
devApp = connect();
if(cfg.server.log) {
devApp.use(connect.logger(cfg.server.log===true ? 'dev' : cfg.server.log));
}
devApp.use(connect.static(cfg.buildDir));
devServer = http.createServer(devApp).listen(cfg.server.port, cfg.server.host||undefined);
devServer.on('error', function(error) {
log(colors.underline(colors.red('ERROR'))+' Unable to start server!');
cb(error);
});
devServer.on('listening', function() {
devAddress = devServer.address();
devHost = devAddress.address === '0.0.0.0' ? 'localhost' : devAddress.address;
url = 'http://' + devHost + ':' + devAddress.port + join('/', cfg.indexFile);
log('');
log('Started dev server at '+colors.magenta(url));
var openByDefault = cfg.server.openByDefault;
if(gutil.env.open || (openByDefault && gutil.env.open !== false)) {
log('Opening dev server URL in browser');
if(openByDefault) {
log(colors.gray('(Run with --no-open to prevent automatically opening URL)'));
}
// Open the URL in the browser at this point.
open(url);
} else if(!openByDefault) {
log(colors.gray('(Run with --open to automatically open URL on startup)'));
}
log('');
cb();
});
}
//=============================================
// SUB TASKS
//=============================================
//---------------------------------------------
// HTML
//---------------------------------------------
var buildHTML = function() {
var htmlFile = readFile(join(cfg.buildDir, cfg.indexFile));
return gulp.src([join(cfg.buildDir, '/**/*.*'), '!' + join(cfg.buildDir, cfg.indexFile)], {read: false})
.pipe(plumber())
.pipe(inject(cfg.appFiles.html, {
addRootSlash: false,
sort: fileSorter, // see below
ignorePath: join('/',cfg.buildDir,'/')
}))
.pipe(_if(embedLR, livereloadEmbed({port: cfg.server.lrPort})))
.pipe(gulp.dest(cfg.buildDir))
.pipe(tap(function(file) {
var newHtmlFile = file.contents.toString();
if(newHtmlFile !== htmlFile) {
htmlFile = newHtmlFile;
gulp.src(file.path).pipe(livereload(server));
}
}));
};
gulp.task('build-html', function() {
// NOTE: this task does NOT depend on buildScripts and buildStyles,
// therefore, it may incorrectly create the HTML file if called
// directly.
return buildHTML();
});
gulp.task('compile-html', function() {
// NOTE: this task does NOT depend on compileScripts and compileStyles,
// therefore, it may incorrectly create the HTML file if called
// directly.
return gulp.src([join(cfg.compileDir, '/**/*.*'), '!' + join(cfg.compileDir, cfg.indexFile)], {read: false})
.pipe(inject(cfg.appFiles.html, {
addRootSlash: false,
ignorePath: join('/', cfg.compileDir, '/')
}))
.pipe(minifyHtml({empty:true,spare:true,quotes:true}))
.pipe(gulp.dest(cfg.compileDir))
.pipe(gzip())
.pipe(gulp.dest(cfg.compileDir))
});
// used by build-html to ensure correct file order during builds
var fileSorter = (function(){
var as = anysort(_.flatten([
// JS files are sorted by original vendor order, common, app, then everything else
cfg.vendorFiles.js.map(function(f){ return join(cfg.jsDir, f); }),
join(cfg.jsDir, 'common/**/*.js'),
join(cfg.jsDir, 'app/**/*.js'),
join(cfg.jsDir, '**/*.js'),
// CSS order should be maintained via Less includes
join(cfg.cssDir, '**/*.css')
]));
return function(a,b){ return as(a.filepath, b.filepath) };
})();
//---------------------------------------------
// JavaScript
//---------------------------------------------
var jsFiles = function() { return gulp.src(cfg.appFiles.js); },
jsBaseTasks = lazypipe()
.pipe(plumber) // jshint won't render parse errors without plumber
.pipe(function() {
return jshint(_.clone(cfg.taskOptions.jshint));
})
.pipe(jshint.reporter, 'jshint-stylish'),
jsBuildTasks = jsBaseTasks
.pipe(gulp.dest, join(cfg.buildDir, cfg.jsDir)),
tplFiles = function() { return gulp.src(cfg.appFiles.tpl); },
tplBuildTasks = lazypipe()
.pipe(ngHtml2js, {moduleName: 'templates'})
.pipe(gulp.dest, join(cfg.buildDir, cfg.jsDir, cfg.templatesDir));
//noinspection FunctionWithInconsistentReturnsJS
gulp.task('build-scripts-vendor', function() {
if(cfg.vendorFiles.js.length) {
return gulp.src(cfg.vendorFiles.js, {base: cfg.vendorDir})
.pipe(gulp.dest(join(cfg.buildDir, cfg.jsDir, cfg.vendorDir)))
}
});
gulp.task('build-scripts-app', function() {
return jsFiles().pipe(jsBuildTasks());
});
gulp.task('build-scripts-templates', function() {
return tplFiles().pipe(tplBuildTasks());
});
gulp.task('build-scripts', ['build-scripts-vendor', 'build-scripts-app', 'build-scripts-templates']);
gulp.task('compile-scripts', function() {
var appFiles = jsFiles()
.pipe(jsBaseTasks())
.pipe(concat('appFiles.js')) // not used
.pipe(ngmin())
.pipe(header(readFile('module.prefix')))
.pipe(footer(readFile('module.suffix')));
var templates = tplFiles()
.pipe(minifyHtml({empty: true, spare: true, quotes: true}))
.pipe(ngHtml2js({moduleName: 'templates'}))
.pipe(concat('templates.min.js')); // not used
var files = [appFiles, templates];
if(cfg.vendorFiles.js.length) {
files.unshift(gulp.src(cfg.vendorFiles.js));
}
return es.concat.apply(es, files)
.pipe(concat(concatName + '.js'))
.pipe(uglify(cfg.taskOptions.uglify))
.pipe(rev())
.pipe(gulp.dest(join(cfg.compileDir, cfg.jsDir)))
.pipe(gzip())
.pipe(gulp.dest(join(cfg.compileDir, cfg.jsDir)))
});
//---------------------------------------------
// Less / CSS Styles
//---------------------------------------------
var styleFiles = function() { return gulp.src(cfg.appFiles.less); },
styleBaseTasks = lazypipe()
.pipe(recess, cfg.taskOptions.recess)
.pipe(less, cfg.taskOptions.less)
.pipe(autoprefixer),
buildStyles = function() {
return styleFiles()
.pipe(plumber())
.pipe(styleBaseTasks())
.pipe(gulp.dest(join(cfg.buildDir, cfg.cssDir)))
.pipe(livereload(server))
};
gulp.task('build-styles', function() {
return buildStyles();
});
gulp.task('compile-styles', function() {
return styleFiles()
.pipe(styleBaseTasks())
.pipe(rename(concatName + '.css'))
.pipe(csso(cfg.taskOptions.csso))
.pipe(rev())
.pipe(gulp.dest(join(cfg.compileDir, cfg.cssDir)))
.pipe(gzip())
.pipe(gulp.dest(join(cfg.compileDir, cfg.cssDir)))
});
//---------------------------------------------
// Unit Testing
//---------------------------------------------
var testFiles = function() {
return gulp.src(_.flatten([cfg.vendorFiles.js, cfg.testFiles.js, cfg.appFiles.jsunit]));
};
gulp.task('test', ['build-scripts'], function() {
return testFiles()
.pipe(karma({
configFile: cfg.testFiles.config
}))
});
gulp.task('test-watch', ['build-scripts', 'test'], function() {
// NOT returned on purpose!
testFiles()
.pipe(karma({
configFile: cfg.testFiles.config,
action: 'watch'
}))
});
//---------------------------------------------
// Assets
//---------------------------------------------
// If you want to automate image compression, or font creation,
// this is the place to do it!
//noinspection FunctionWithInconsistentReturnsJS
gulp.task('build-assets-vendor', function() {
if(cfg.vendorFiles.assets.length) {
return gulp.src(cfg.vendorFiles.assets, {base: cfg.vendorDir})
.pipe(gulp.dest(join(cfg.buildDir, cfg.assetsDir, cfg.vendorDir)))
}
});
gulp.task('build-assets', ['build-assets-vendor'], function() {
return gulp.src(cfg.appFiles.assets)
.pipe(gulp.dest(join(cfg.buildDir, cfg.assetsDir)))
});
//noinspection FunctionWithInconsistentReturnsJS
gulp.task('compile-assets-vendor', function() {
if(cfg.vendorFiles.assets.length) {
return gulp.src(cfg.vendorFiles.assets, {base: cfg.vendorDir})
.pipe(gulp.dest(join(cfg.compileDir, cfg.assetsDir, cfg.vendorDir)))
}
});
gulp.task('compile-assets', ['compile-assets-vendor'], function() {
return gulp.src(cfg.appFiles.assets)
.pipe(gulp.dest(join(cfg.compileDir, cfg.assetsDir)))
});
//---------------------------------------------
// Miscellaneous Tasks
//---------------------------------------------
gulp.task('lr-server', function() {
embedLR = true;
server.listen(cfg.server.lrPort, function(err) {
if(err) {
console.log(err);
}
gutil.log('Started LiveReload server');
});
});
gulp.task('build-clean', function() {
return gulp.src(cfg.buildDir, {read: false}).pipe(clean());
});
gulp.task('compile-clean', function() {
return gulp.src(cfg.compileDir, {read: false}).pipe(clean());
});
/**
* PLEASE NOTE: I HAVEN'T UPDATED THE COMMENTS IN THIS FILE!
*
* This file/module contains all configuration for the build process.
*/
var join = require('path').join,
bowerrc = JSON.parse(require('fs').readFileSync('./.bowerrc', {encoding: 'utf8'})),
bower = require(bowerrc.json.replace(/^\.?\/?/, './')),
pkg = require('./package.json'),
/**
* The `buildDir` folder is where our projects are compiled during
* development and the `compileDir` folder is where our app resides once it's
* completely built.
*/
buildDir = 'build',
compileDir = 'compile',
vendorDir = bowerrc.directory,
templatesDir = 'templates',
indexFile = 'index.html',
jsDir = 'js',
cssDir = 'css',
assetsDir = 'assets';
module.exports = {
buildDir: buildDir,
compileDir: compileDir,
// Relative paths to core files and folders for input and output
indexFile: indexFile,
jsDir: jsDir,
cssDir: cssDir,
assetsDir: assetsDir,
vendorDir: vendorDir,
templatesDir: templatesDir,
// allows settings reuse from package.json and bower.json
bower: bower,
pkg: pkg,
/**
* Settings for the server task
* When run, this task will start a connect server on
* your build directory, great for livereload
*/
server: {
port: 8081, // 0 = random port
host: null, // null/falsy means listen to all, but will auto open localhost
// Enable disable default auto open
// false: run with --open to open
// true: run with --no-open to not open, recommended if port is 0
openByDefault: false,
// set to false to prevent request logging
// set to any non-`true` value to configure the logger
log: false,
// Live Reload server port
lrPort: 35729
},
taskOptions: {
csso: false, // set to true to prevent structural modifications
jshint: {
eqeqeq: true,
camelcase: true,
freeze: true,
immed: true,
latedef: true,
newcap: true,
undef: true,
unused: true,
browser: true,
globals: {
angular: false,
console: false
}
},
less: {},
recess: {
strictPropertyOrder: false,
noOverqualifying: false,
noUniversalSelectors: false
},
uglify: {}
},
/**
* This is a collection of file patterns that refer to our app code (the
* stuff in `src/`). These file paths are used in the configuration of
* build tasks. `js` is all project javascript, less tests. `ctpl` contains
* our reusable components' (`src/common`) template HTML files, while
* `atpl` contains the same, but for our app's code. `html` is just our
* main HTML file, `less` is our main stylesheet, and `unit` contains our
* app's unit tests.
*/
appFiles: {
js: [ 'src/**/*.js', '!src/**/*.spec.js', '!src/assets/**/*.js' ],
jsunit: [ join(buildDir, '/**/*.js'), 'src/**/*.spec.js', '!'+join(buildDir,'/assets/**/*.js'), '!'+join(buildDir, vendorDir, '**/*.js') ],
tpl: [ 'src/app/**/*.tpl.html', 'src/common/**/*.tpl.html' ],
html: join('src', indexFile),
less: 'src/less/main.less',
assets: join('src', assetsDir, '**/*.*')
},
/**
* Similar to above, except this is the pattern of files to watch
* for live build and reloading.
*/
watchFiles: {
js: [ 'src/**/*.js', '!src/**/*.spec.js', '!src/assets/**/*.js' ],
//jsunit: [ 'src/**/*.spec.js' ], // watch is handled by the karma plugin!
tpl: [ 'src/app/**/*.tpl.html', 'src/common/**/*.tpl.html' ],
html: [ join(buildDir, '**/*'), '!'+join(buildDir,indexFile), join('src',indexFile) ],
less: [ 'src/**/*.less' ],
assets: join('src',assetsDir,'**/*.*')
},
/**
* This is a collection of files used during testing only.
*/
testFiles: {
config: 'karma/karma.conf.js',
js: [
'vendor/angular-mocks/angular-mocks.js'
]
},
/**
* This is the same as `app_files`, except it contains patterns that
* reference vendor code (`vendor/`) that we need to place into the build
* process somewhere. While the `app_files` property ensures all
* standardized files are collected for compilation, it is the user's job
* to ensure non-standardized (i.e. vendor-related) files are handled
* appropriately in `vendorFiles.js`.
*
* The `vendorFiles.js` property holds files to be automatically
* concatenated and minified with our project source files.
*
* The `vendorFiles.assets` property holds any assets to be copied along
* with our app's assets. This structure is flattened, so it is not
* recommended that you use wildcards.
*/
vendorFiles: {
js: [
'vendor/angular/angular.js',
'vendor/angular-ui-router/release/angular-ui-router.js'
],
assets: [
]
}
};
{
"author": "Phil DeJarnett",
"name": "example-gulpfile",
"version": "0.1.0",
"homepage": "http://www.overzealous.com",
"licenses": {
"type": "",
"url": ""
},
"bugs": "",
"repository": {
"type": "",
"url": ""
},
"dependencies": {},
"devDependencies": {
"anysort": "~0.1.1",
"event-stream": "*",
"gulp": "3.*",
"gulp-autoprefixer": "*",
"gulp-clean": "*",
"gulp-concat": "*",
"gulp-csso": "*",
"gulp-debug": "*",
"gulp-embedlr": "~0.5.2",
"gulp-footer": "*",
"gulp-gzip": "0.0.4",
"gulp-header": "*",
"gulp-if": "*",
"gulp-inject": "*",
"gulp-jshint": "*",
"gulp-karma": "*",
"gulp-less": "*",
"gulp-livereload": "*",
"gulp-minify-html": "*",
"gulp-ng-html2js": "*",
"gulp-ngmin": "*",
"gulp-plumber": "*",
"gulp-recess": "*",
"gulp-rename": "*",
"gulp-rev": "*",
"gulp-tap": "*",
"gulp-task-listing": "*",
"gulp-uglify": "*",
"gulp-util": "*",
"gulp-watch": "*",
"jshint-stylish": "*",
"lazypipe": "*",
"lodash": "~2.4.1",
"run-sequence": "*",
"tiny-lr": "0.0.5",
"connect": "~2.12.0",
"open": "0.0.4"
}
}
module.exports = function ( grunt ) {
/**
* Load required Grunt tasks. These are installed based on the versions listed
* in `package.json` when you do `npm install` in this directory.
*/
require('load-grunt-tasks')(grunt);
/**
* Load in our build configuration file.
*/
var userConfig = require( './build.config.js' );
/**
* This is the configuration object Grunt uses to give each plugin its
* instructions.
*/
var taskConfig = {
/**
* We read in our `package.json` file so we can access the package name and
* version. It's already there, so we don't repeat ourselves here.
*/
pkg: grunt.file.readJSON("package.json"),
/**
* The banner is the comment that is placed at the top of our compiled
* source files. It is first processed as a Grunt template, where the `<%=`
* pairs are evaluated based on this very configuration object.
*/
meta: {
banner:
'/**\n' +
' * <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
' * <%= pkg.homepage %>\n' +
' *\n' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>\n' +
' * Licensed <%= pkg.licenses.type %> <<%= pkg.licenses.url %>>\n' +
' */\n'
},
/**
* Creates a changelog on a new version.
*/
changelog: {
options: {
dest: 'CHANGELOG.md',
template: 'changelog.tpl'
}
},
/**
* Increments the version number, etc.
*/
bump: {
options: {
files: [
"package.json",
"bower.json"
],
commit: false,
commitMessage: 'chore(release): v%VERSION%',
commitFiles: [
"package.json",
"client/bower.json"
],
createTag: false,
tagName: 'v%VERSION%',
tagMessage: 'Version %VERSION%',
push: false,
pushTo: 'origin'
}
},
/**
* The directories to delete when `grunt clean` is executed.
*/
clean: [
'<%= build_dir %>',
'<%= compile_dir %>'
],
/**
* The `copy` task just copies files from A to B. We use it here to copy
* our project assets (images, fonts, etc.) and javascripts into
* `build_dir`, and then to copy the assets to `compile_dir`.
*/
copy: {
build_app_assets: {
files: [
{
src: [ '**' ],
dest: '<%= build_dir %>/assets/',
cwd: 'src/assets',
expand: true
}
]
},
build_vendor_assets: {
files: [
{
src: [ '<%= vendor_files.assets %>' ],
dest: '<%= build_dir %>/assets/',
cwd: '.',
expand: true,
flatten: true
}
]
},
build_appjs: {
files: [
{
src: [ '<%= app_files.js %>' ],
dest: '<%= build_dir %>/',
cwd: '.',
expand: true
}
]
},
build_vendorjs: {
files: [
{
src: [ '<%= vendor_files.js %>' ],
dest: '<%= build_dir %>/',
cwd: '.',
expand: true
}
]
},
compile_assets: {
files: [
{
src: [ '**' ],
dest: '<%= compile_dir %>/assets',
cwd: '<%= build_dir %>/assets',
expand: true
}
]
}
},
/**
* `grunt concat` concatenates multiple source files into a single file.
*/
concat: {
/**
* The `build_css` target concatenates compiled CSS and vendor CSS
* together.
*/
build_css: {
src: [
'<%= vendor_files.css %>',
'<%= recess.build.dest %>'
],
dest: '<%= recess.build.dest %>'
},
/**
* The `compile_js` target is the concatenation of our application source
* code and all specified vendor source code into a single file.
*/
compile_js: {
options: {
banner: '<%= meta.banner %>'
},
src: [
'<%= vendor_files.js %>',
'module.prefix',
'<%= build_dir %>/src/**/*.js',
'<%= html2js.app.dest %>',
'<%= html2js.common.dest %>',
'module.suffix'
],
dest: '<%= compile_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.js'
}
},
/**
* `ng-min` annotates the sources before minifying. That is, it allows us
* to code without the array syntax.
*/
ngmin: {
compile: {
files: [
{
src: [ '<%= app_files.js %>' ],
cwd: '<%= build_dir %>',
dest: '<%= build_dir %>',
expand: true
}
]
}
},
/**
* Minify the sources!
*/
uglify: {
compile: {
options: {
banner: '<%= meta.banner %>'
},
files: {
'<%= concat.compile_js.dest %>': '<%= concat.compile_js.dest %>'
}
}
},
/**
* `recess` handles our LESS compilation and uglification automatically.
* Only our `main.less` file is included in compilation; all other files
* must be imported from this file.
*/
recess: {
build: {
src: [ '<%= app_files.less %>' ],
dest: '<%= build_dir %>/assets/<%= pkg.name %>-<%= pkg.version %>.css',
options: {
compile: true,
compress: false,
noUnderscores: false,
noIDs: false,
zeroUnits: false
}
},
compile: {
src: [ '<%= recess.build.dest %>' ],
dest: '<%= recess.build.dest %>',
options: {
compile: true,
compress: true,
noUnderscores: false,
noIDs: false,
zeroUnits: false
}
}
},
/**
* `jshint` defines the rules of our linter as well as which files we
* should check. This file, all javascript sources, and all our unit tests
* are linted based on the policies listed in `options`. But we can also
* specify exclusionary patterns by prefixing them with an exclamation
* point (!); this is useful when code comes from a third party but is
* nonetheless inside `src/`.
*/
jshint: {
src: [
'<%= app_files.js %>'
],
test: [
'<%= app_files.jsunit %>'
],
gruntfile: [
'Gruntfile.js'
],
options: {
curly: true,
immed: true,
newcap: true,
noarg: true,
sub: true,
boss: true,
eqnull: true
},
globals: {}
},
/**
* HTML2JS is a Grunt plugin that takes all of your template files and
* places them into JavaScript files as strings that are added to
* AngularJS's template cache. This means that the templates too become
* part of the initial payload as one JavaScript file. Neat!
*/
html2js: {
/**
* These are the templates from `src/app`.
*/
app: {
options: {
base: 'src/app'
},
src: [ '<%= app_files.atpl %>' ],
dest: '<%= build_dir %>/templates-app.js'
},
/**
* These are the templates from `src/common`.
*/
common: {
options: {
base: 'src/common'
},
src: [ '<%= app_files.ctpl %>' ],
dest: '<%= build_dir %>/templates-common.js'
}
},
/**
* The Karma configurations.
*/
karma: {
options: {
configFile: '<%= build_dir %>/karma-unit.js'
},
unit: {
port: 9101,
background: true
},
continuous: {
singleRun: true
}
},
/**
* The `index` task compiles the `index.html` file as a Grunt template. CSS
* and JS files co-exist here but they get split apart later.
*/
index: {
/**
* During development, we don't want to have wait for compilation,
* concatenation, minification, etc. So to avoid these steps, we simply
* add all script files directly to the `<head>` of `index.html`. The
* `src` property contains the list of included files.
*/
build: {
dir: '<%= build_dir %>',
src: [
'<%= vendor_files.js %>',
'<%= build_dir %>/src/**/*.js',
'<%= html2js.common.dest %>',
'<%= html2js.app.dest %>',
'<%= vendor_files.css %>',
'<%= recess.build.dest %>'
]
},
/**
* When it is time to have a completely compiled application, we can
* alter the above to include only a single JavaScript and a single CSS
* file. Now we're back!
*/
compile: {
dir: '<%= compile_dir %>',
src: [
'<%= concat.compile_js.dest %>',
'<%= vendor_files.css %>',
'<%= recess.compile.dest %>'
]
}
},
/**
* This task compiles the karma template so that changes to its file array
* don't have to be managed manually.
*/
karmaconfig: {
unit: {
dir: '<%= build_dir %>',
src: [
'<%= vendor_files.js %>',
'<%= html2js.app.dest %>',
'<%= html2js.common.dest %>',
'<%= test_files.js %>'
]
}
},
/**
* And for rapid development, we have a watch set up that checks to see if
* any of the files listed below change, and then to execute the listed
* tasks when they do. This just saves us from having to type "grunt" into
* the command-line every time we want to see what we're working on; we can
* instead just leave "grunt watch" running in a background terminal. Set it
* and forget it, as Ron Popeil used to tell us.
*
* But we don't need the same thing to happen for all the files.
*/
delta: {
/**
* By default, we want the Live Reload to work for all tasks; this is
* overridden in some tasks (like this file) where browser resources are
* unaffected. It runs by default on port 35729, which your browser
* plugin should auto-detect.
*/
options: {
livereload: true
},
/**
* When the Gruntfile changes, we just want to lint it. In fact, when
* your Gruntfile changes, it will automatically be reloaded!
*/
gruntfile: {
files: 'Gruntfile.js',
tasks: [ 'jshint:gruntfile' ],
options: {
livereload: false
}
},
/**
* When our JavaScript source files change, we want to run lint them and
* run our unit tests.
*/
jssrc: {
files: [
'<%= app_files.js %>'
],
tasks: [ 'jshint:src', 'karma:unit:run', 'copy:build_appjs' ]
},
/**
* When assets are changed, copy them. Note that this will *not* copy new
* files, so this is probably not very useful.
*/
assets: {
files: [
'src/assets/**/*'
],
tasks: [ 'copy:build_assets' ]
},
/**
* When index.html changes, we need to compile it.
*/
html: {
files: [ '<%= app_files.html %>' ],
tasks: [ 'index:build' ]
},
/**
* When our templates change, we only rewrite the template cache.
*/
tpls: {
files: [
'<%= app_files.atpl %>',
'<%= app_files.ctpl %>'
],
tasks: [ 'html2js' ]
},
/**
* When the CSS files change, we need to compile and minify them.
*/
less: {
files: [ 'src/**/*.less' ],
tasks: [ 'recess:build' ]
},
/**
* When a JavaScript unit test file changes, we only want to lint it and
* run the unit tests. We don't want to do any live reloading.
*/
jsunit: {
files: [
'<%= app_files.jsunit %>'
],
tasks: [ 'jshint:test', 'karma:unit:run' ],
options: {
livereload: false
}
}
}
};
grunt.initConfig( grunt.util._.extend( taskConfig, userConfig ) );
/**
* In order to make it safe to just compile or copy *only* what was changed,
* we need to ensure we are starting from a clean, fresh build. So we rename
* the `watch` task to `delta` (that's why the configuration var above is
* `delta`) and then add a new task called `watch` that does a clean build
* before watching for changes.
*/
grunt.renameTask( 'watch', 'delta' );
grunt.registerTask( 'watch', [ 'build', 'karma:unit', 'delta' ] );
/**
* The default task is to build and compile.
*/
grunt.registerTask( 'default', [ 'build', 'compile' ] );
/**
* The `build` task gets your app ready to run for development and testing.
*/
grunt.registerTask( 'build', [
'clean', 'html2js', 'jshint', 'recess:build',
'concat:build_css', 'copy:build_app_assets', 'copy:build_vendor_assets',
'copy:build_appjs', 'copy:build_vendorjs', 'index:build', 'karmaconfig',
'karma:continuous'
]);
/**
* The `compile` task gets your app ready for deployment by concatenating and
* minifying your code.
*/
grunt.registerTask( 'compile', [
'recess:compile', 'copy:compile_assets', 'ngmin', 'concat:compile_js', 'uglify', 'index:compile'
]);
/**
* A utility function to get all app JavaScript sources.
*/
function filterForJS ( files ) {
return files.filter( function ( file ) {
return file.match( /\.js$/ );
});
}
/**
* A utility function to get all app CSS sources.
*/
function filterForCSS ( files ) {
return files.filter( function ( file ) {
return file.match( /\.css$/ );
});
}
/**
* The index.html template includes the stylesheet and javascript sources
* based on dynamic names calculated in this Gruntfile. This task assembles
* the list into variables for the template to use and then runs the
* compilation.
*/
grunt.registerMultiTask( 'index', 'Process index.html template', function () {
var dirRE = new RegExp( '^('+grunt.config('build_dir')+'|'+grunt.config('compile_dir')+')\/', 'g' );
var jsFiles = filterForJS( this.filesSrc ).map( function ( file ) {
return file.replace( dirRE, '' );
});
var cssFiles = filterForCSS( this.filesSrc ).map( function ( file ) {
return file.replace( dirRE, '' );
});
grunt.file.copy('src/index.html', this.data.dir + '/index.html', {
process: function ( contents, path ) {
return grunt.template.process( contents, {
data: {
scripts: jsFiles,
styles: cssFiles,
version: grunt.config( 'pkg.version' )
}
});
}
});
});
/**
* In order to avoid having to specify manually the files needed for karma to
* run, we use grunt to manage the list for us. The `karma/*` files are
* compiled as grunt templates for use by Karma. Yay!
*/
grunt.registerMultiTask( 'karmaconfig', 'Process karma config templates', function () {
var jsFiles = filterForJS( this.filesSrc );
grunt.file.copy( 'karma/karma-unit.tpl.js', grunt.config( 'build_dir' ) + '/karma-unit.js', {
process: function ( contents, path ) {
return grunt.template.process( contents, {
data: {
scripts: jsFiles
}
});
}
});
});
};
@yocontra
Copy link

yocontra commented Jan 9, 2014

@OverZealous

gulp.task('compile-scripts', function () {

  var appFiles = jsBase()
    .pipe(tasks.concat(tmpFileName))
    .pipe(tasks.ngmin());

  var vendorFiles = gulp.src(config.vendorFiles.js)
    .pipe(tasks.concat(concatName + '.js'));

  var tail = tasks.uglify(config.taskOptions.uglify)
    .pipe(tasks.rev())
    .pipe(gulp.dest(config.compileDir + '/js'));

  appFiles.pipe(tail);
  vendorFiles.pipe(tail);
});

I wasn't sure which part you wanted to happen on both forks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment