From c0d5a146fd18e9953ece8e180cfd4c33f8fac63f Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 16:45:14 +1100 Subject: [PATCH 01/13] fix(gulp): inject angular modules before other scripts add sort function to ensure angular modules appear first in inject:js task --- app/templates/gulpfile.babel(gulp).js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 1266f8bef..884fe37b3 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -91,6 +91,25 @@ function whenServerReady(cb) { 100); } +function sortModulesFirst(a, b) { + var module = /\.module\.js$/; + var aMod = module.test(a.path); + var bMod = module.test(b.path); + // inject *.module.js first + if (aMod === bMod) { + // either both modules or both non-modules, so just sort normally + if (a.path < b.path) { + return -1; + } + if (a.path > b.path) { + return 1; + } + return 0; + } else { + return (aMod ? -1 : 1); + } +} + /******************** * Reusable pipelines ********************/ @@ -164,7 +183,7 @@ gulp.task('inject:js', () => { return gulp.src(paths.client.mainView) .pipe(plugins.inject( gulp.src(_.union(paths.client.scripts, ['!client/**/*.spec.<%= scriptExt %>']), {read: false}) - .pipe(plugins.sort()), + .pipe(plugins.sort(sortModulesFirst)), { starttag: '', endtag: '', From 77b7be6ba6d1e8bf7ef5aebde3b0dc915399a231 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 17:10:40 +1100 Subject: [PATCH 02/13] refactor(gulp): update path globs and references use template strings to turn all references to `dist/`, `client/` and `server/` into variables. update some path globs to more accurately match target files (aiming for grunt parity) --- app/templates/gulpfile.babel(gulp).js | 109 +++++++++++++------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 884fe37b3..6b67e9a75 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -17,38 +17,39 @@ import nib from 'nib';<% } %> var plugins = gulpLoadPlugins(); var config; +const clientPath = require('./bower.json').appPath || 'client'; +const serverPath = 'server'; const paths = { - appPath: require('./bower.json').appPath || 'client', client: { - assets: 'client/assets/**/*', - images: 'client/assets/images/*', + assets: `${clientPath}/assets/**/*`, + images: `${clientPath}/assets/images/**/*`, scripts: [ - 'client/**/*.<%= scriptExt %>', - '!client/bower_components/**/*.js' + `${clientPath}/**/*.<%= scriptExt %>`, + `!${clientPath}/bower_components/**/*.js` ], - styles: ['client/{app,components}/**/*.<%= styleExt %>'], - mainStyle: 'client/app/app.<%= styleExt %>', - views: 'client/{app,components}/**/*.<%= templateExt %>', - mainView: 'client/index.html', - test: ['client/**/*.spec.<%= scriptExt %>'], + styles: [`${clientPath}/{app,components}/**/*.<%= styleExt %>`], + mainStyle: `${clientPath}/app/app.<%= styleExt %>`, + views: `${clientPath}/{app,components}/**/*.<%= templateExt %>`, + mainView: `${clientPath}/index.html`, + test: [`${clientPath}/{app,components}/**/*.spec.<%= scriptExt %>`], testRequire: [ - 'client/bower_components/angular/angular.js', - 'client/bower_components/angular-mocks/angular-mocks.js', - 'client/bower_components/angular-resource/angular-resource.js', - 'client/bower_components/angular-cookies/angular-cookies.js', - 'client/bower_components/angular-sanitize/angular-sanitize.js', - 'client/bower_components/angular-route/angular-route.js', - 'client/**/*.spec.<%= scriptExt %>' + `${clientPath}/bower_components/angular/angular.js`, + `${clientPath}/bower_components/angular-mocks/angular-mocks.js`, + `${clientPath}/bower_components/angular-resource/angular-resource.js`, + `${clientPath}/bower_components/angular-cookies/angular-cookies.js`, + `${clientPath}/bower_components/angular-sanitize/angular-sanitize.js`, + `${clientPath}/bower_components/angular-route/angular-route.js`, + `${clientPath}/**/*.spec.<%= scriptExt %>` ], - bower: 'client/bower_components/' + bower: `${clientPath}/bower_components/` }, server: { - scripts: ['server/**/*.<%= scriptExt %>'], - json: ['server/**/*.json'], + scripts: [`${serverPath}/**/*.<%= scriptExt %>`], + json: [`${serverPath}/**/*.json`], test: [ - 'server/**/*.spec.js', - 'server/**/*.mock.js', - 'server/**/*.integration.js' + `${serverPath}/**/*.spec.js`, + `${serverPath}/**/*.mock.js`, + `${serverPath}/**/*.integration.js` ] }, karma: 'karma.conf.js', @@ -117,13 +118,13 @@ function sortModulesFirst(a, b) { let lintClientScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) .pipe(plugins.coffeelint.reporter);<% } else { %> - .pipe(plugins.jshint, 'client/.jshintrc') + .pipe(plugins.jshint, `${clientPath}/.jshintrc`) .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> let lintServerScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.coffeelint) .pipe(plugins.coffeelint.reporter);<% } else { %> - .pipe(plugins.jshint, 'server/.jshintrc') + .pipe(plugins.jshint, `${serverPath}/.jshintrc`) .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> let styles = lazypipe() @@ -152,7 +153,7 @@ let transpile = lazypipe() gulp.task('env:all', () => { let localConfig; try { - localConfig = require('./server/config/local.env'); + localConfig = require(`./${serverPath}/config/local.env`); } catch (e) { localConfig = {}; } @@ -182,31 +183,31 @@ gulp.task('inject', cb => { gulp.task('inject:js', () => { return gulp.src(paths.client.mainView) .pipe(plugins.inject( - gulp.src(_.union(paths.client.scripts, ['!client/**/*.spec.<%= scriptExt %>']), {read: false}) + gulp.src(_.union(paths.client.scripts, [`!${clientPath}/**/*.spec.<%= scriptExt %>`]), {read: false}) .pipe(plugins.sort(sortModulesFirst)), { starttag: '', endtag: '', - transform: (filepath) => '' + transform: (filepath) => '' })) - .pipe(gulp.dest('client')); + .pipe(gulp.dest(clientPath)); }); gulp.task('inject:css', () => { return gulp.src(paths.client.mainView) .pipe(plugins.inject( - gulp.src('/client/**/*.css', {read: false}) + gulp.src('/${clientPath}/{app,components}/**/*.css', {read: false}) .pipe(plugins.sort()), { starttag: '', endtag: '', - transform: (filepath) => '' + transform: (filepath) => '' })) - .pipe(gulp.dest('client')); + .pipe(gulp.dest(clientPath)); }); gulp.task('inject:<%= styleExt %>', () => { - return gulp.src('client/app/app.<%= styleExt %>') + return gulp.src(paths.client.mainStyle) .pipe(plugins.inject( gulp.src(_.union(paths.client.styles, ['!' + paths.client.mainStyle]), {read: false}) .pipe(plugins.sort()), @@ -215,14 +216,14 @@ gulp.task('inject:<%= styleExt %>', () => { endtag: '// endinjector', transform: (filepath) => { let newPath = filepath - .replace('/client/app/', '') - .replace('/client/components/', '../components/') + .replace(`/${clientPath}/app/`, '') + .replace(`/${clientPath}/components/`, '../components/') .replace(/_(.*).<%= styleExt %>/, (match, p1, offset, string) => p1) .replace('.<%= styleExt %>', ''); - return '@import \'' + newPath + '\';'; + return `@import '${newPath}';`; } })) - .pipe(gulp.dest('client/app')); + .pipe(gulp.dest(`${clientPath}/app`)); }); gulp.task('styles', () => { @@ -240,7 +241,7 @@ gulp.task('transpile:client', () => { gulp.task('transpile:server', () => { return gulp.src(_.union(paths.server.scripts, paths.server.json)) .pipe(transpile()) - .pipe(gulp.dest(paths.dist + '/server')); + .pipe(gulp.dest(`${paths.dist}/${serverPath}`)); }); gulp.task('lint:scripts', cb => runSequence(['lint:scripts:client', 'lint:scripts:server'], cb)); @@ -266,8 +267,8 @@ gulp.task('start:client', cb => { gulp.task('start:server', () => { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; - config = require('./server/config/environment'); - nodemon('-w server server') + config = require(`./${serverPath}/config/environment`); + nodemon(`-w ${serverPath} ${serverPath}`) .on('log', onServerLog); }); @@ -360,9 +361,9 @@ gulp.task('wiredep:client', () => { /bootstrap.css/, /font-awesome.css/ ], - ignorePath: paths.appPath + ignorePath: clientPath })) - .pipe(gulp.dest('client/')); + .pipe(gulp.dest(`${clientPath}/`)); }); gulp.task('wiredep:test', () => { @@ -402,7 +403,7 @@ gulp.task('build', cb => { cb); }); -gulp.task('clean:dist', () => del(['dist/**/*'])); +gulp.task('clean:dist', () => del([`${paths.dist}/**/*`])); gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { var appFilter = plugins.filter('**/app.js'); @@ -411,7 +412,7 @@ gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { var htmlFilter = plugins.filter('**/*.html');<% if(filters.jade) { %> var assetsFilter = plugins.filter('**/*.{js,css}');<% } %> - let assets = plugins.useref.assets({searchPath: ['client', '.tmp']}); + let assets = plugins.useref.assets({searchPath: [clientPath, '.tmp']}); return gulp.src(paths.client.mainView)<% if(filters.jade) { %> .pipe(plugins.jade({pretty: true}))<% } %> @@ -435,11 +436,11 @@ gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { .pipe(plugins.revReplace()) .pipe(plugins.useref())<% if(filters.jade) { %> .pipe(assetsFilter)<% } %> - .pipe(gulp.dest(paths.dist + '/client')); + .pipe(gulp.dest(`${paths.dist}/${clientPath}`)); }); gulp.task('html', function() { - return gulp.src('client/{app,components}/**/*.html') + return gulp.src(`${clientPath}/{app,components}/**/*.html`) .pipe(plugins.angularTemplatecache({ module: '<%= scriptAppName %>' })) @@ -452,7 +453,7 @@ gulp.task('jade', function() { });<% } %> gulp.task('constant', function() { - let sharedConfig = require('./server/config/environment/shared'); + let sharedConfig = require(`./${serverPath}/config/environment/shared`); plugins.ngConstant({ name: '<%= scriptAppName %>.constants', deps: [], @@ -463,30 +464,30 @@ gulp.task('constant', function() { .pipe(plugins.rename({ basename: 'app.constant' })) - .pipe(gulp.dest('client/app/')) + .pipe(gulp.dest(`${clientPath}/app/`)) }) gulp.task('build:images', () => { - return gulp.src('client/assets/images/**/*') + return gulp.src(paths.client.images) .pipe(plugins.imagemin({ optimizationLevel: 5, progressive: true, interlaced: true })) - .pipe(gulp.dest(paths.dist + '/client/assets/images')); + .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets/images`)); }); gulp.task('copy:extras', () => { return gulp.src([ - 'client/favicon.ico', - 'client/robots.txt' + `${clientPath}/favicon.ico`, + `${clientPath}/robots.txt` ], { dot: true }) - .pipe(gulp.dest(paths.dist + '/client')); + .pipe(gulp.dest(`${paths.dist}/${clientPath}`)); }); gulp.task('copy:assets', () => { return gulp.src([paths.client.assets, '!' + paths.client.images]) - .pipe(gulp.dest(paths.dist + '/client/assets')); + .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets`)); }); gulp.task('copy:server', () => { From 4d0e2ba32ddaa8c0f4a9a78cbce362843b522894 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 17:36:29 +1100 Subject: [PATCH 03/13] feat(gulp): add missing tasks add the following tasks: * `lint:scripts:test` * `lint:scripts:serverTest` * `coverage:integration` * `coverage:pre` * `coverage:unit` * `jscs` * `lint:scripts:clientTest` * `lint:scripts:serverTest` * `mocha:coverage` * `mocha:integration` * `serve:dist` * `start:server:prod` * `test:e2e` * `webdriver_update` --- app/templates/_package.json | 3 + app/templates/gulpfile.babel(gulp).js | 149 +++++++++++++++++++++----- 2 files changed, 125 insertions(+), 27 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index 09d2e0ea6..e55f4b011 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -44,11 +44,13 @@ "gulp-angular-templatecache": "^1.7.0", "gulp-autoprefixer": "2.3.1",<% if(filters.babel) { %> "gulp-babel": "^5.1.0",<% } %> + "gulp-babel-istanbul": "^0.11.0", "gulp-cache": "^0.2.10", "gulp-concat": "^2.6.0", "gulp-filter": "^2.0.2", "gulp-imagemin": "^2.2.1", "gulp-inject": "^1.3.1", + "gulp-jscs": "^3.0.2", "gulp-jshint": "^1.11.0",<% if(filters.less) { %> "gulp-less": "3.0.3",<% } %> "gulp-livereload": "^3.8.0", @@ -58,6 +60,7 @@ "gulp-ng-annotate": "^1.1.0", "gulp-ng-constant": "^1.1.0", "gulp-plumber": "^1.0.1", + "gulp-protractor": "^2.1.0", "gulp-rename": "^1.2.2", "gulp-rev": "^5.0.0", "gulp-rev-replace": "^0.4.2", diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 6b67e9a75..067770ed0 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -11,7 +11,9 @@ import open from 'open'; import lazypipe from 'lazypipe'; import {stream as wiredep} from 'wiredep'; import nodemon from 'nodemon'; -import runSequence from 'run-sequence';<% if(filters.stylus) { %> +import {Server as KarmaServer} from 'karma'; +import runSequence from 'run-sequence'; +import {protractor, webdriver_update} from 'gulp-protractor';<% if(filters.stylus) { %> import nib from 'nib';<% } %> var plugins = gulpLoadPlugins(); @@ -31,16 +33,8 @@ const paths = { mainStyle: `${clientPath}/app/app.<%= styleExt %>`, views: `${clientPath}/{app,components}/**/*.<%= templateExt %>`, mainView: `${clientPath}/index.html`, - test: [`${clientPath}/{app,components}/**/*.spec.<%= scriptExt %>`], - testRequire: [ - `${clientPath}/bower_components/angular/angular.js`, - `${clientPath}/bower_components/angular-mocks/angular-mocks.js`, - `${clientPath}/bower_components/angular-resource/angular-resource.js`, - `${clientPath}/bower_components/angular-cookies/angular-cookies.js`, - `${clientPath}/bower_components/angular-sanitize/angular-sanitize.js`, - `${clientPath}/bower_components/angular-route/angular-route.js`, - `${clientPath}/**/*.spec.<%= scriptExt %>` - ], + test: [`${clientPath}/{app,components}/**/*.{spec,mock}.<%= scriptExt %>`], + e2e: ['e2e/**/*.spec.js'], bower: `${clientPath}/bower_components/` }, server: { @@ -127,6 +121,12 @@ let lintServerScripts = lazypipe()<% if(filters.coffee) { %> .pipe(plugins.jshint, `${serverPath}/.jshintrc`) .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> +let lintServerTestScripts = lazypipe()<% if(filters.coffee) { %> + .pipe(plugins.coffeelint) + .pipe(plugins.coffeelint.reporter);<% } else { %> + .pipe(plugins.jshint, `${serverPath}/.jshintrc-spec`) + .pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %> + let styles = lazypipe() .pipe(plugins.sourcemaps.init)<% if(filters.stylus) { %> .pipe(plugins.stylus, { @@ -146,6 +146,28 @@ let transpile = lazypipe() .pipe(plugins.coffee, {bare: true})<% } %> .pipe(plugins.sourcemaps.write, '.');<% } %> +let mocha = lazypipe() + .pipe(plugins.mocha, { + reporter: 'spec', + timeout: 5000, + require: [ + './mocha.conf' + ] + }); + +let istanbul = lazypipe() + .pipe(plugins.babelIstanbul.writeReports) + .pipe(plugins.babelIstanbul.enforceThresholds, { + thresholds: { + global: { + lines: 80, + statements: 80, + branches: 80, + functions: 80 + } + } + }); + /******************** * Env ********************/ @@ -256,6 +278,22 @@ gulp.task('lint:scripts:server', () => { .pipe(lintServerScripts()); }); +gulp.task('lint:scripts:clientTest', () => { + return gulp.src(paths.client.test) + .pipe(lintClientScripts()); +}); + +gulp.task('lint:scripts:serverTest', () => { + return gulp.src(paths.server.test) + .pipe(lintServerTestScripts()); +}); + +gulp.task('jscs', () => { + return gulp.src(_.union(paths.client.scripts, paths.server.scripts)) + .pipe(plugins.jscs()) + .pipe(plugins.jscs.reporter()); +}); + gulp.task('clean:tmp', () => del(['.tmp/**/*'])); gulp.task('start:client', cb => { @@ -265,6 +303,13 @@ gulp.task('start:client', cb => { }); }); +gulp.task('start:server:prod', () => { + process.env.NODE_ENV = process.env.NODE_ENV || 'production'; + config = require(`./${paths.dist}/${serverPath}/config/environment`); + nodemon(`-w ${paths.dist}/${serverPath} ${paths.dist}/${serverPath}`) + .on('log', onServerLog); +}); + gulp.task('start:server', () => { process.env.NODE_ENV = process.env.NODE_ENV || 'development'; config = require(`./${serverPath}/config/environment`); @@ -314,6 +359,15 @@ gulp.task('serve', cb => { cb); }); +gulp.task('serve:dist', cb => { + runSequence( + 'build', + 'env:all', + 'env:prod', + ['start:server:prod', 'start:client'], + cb); +}); + gulp.task('test', cb => { return runSequence('test:server', 'test:client', cb); }); @@ -323,30 +377,26 @@ gulp.task('test:server', cb => { 'env:all', 'env:test', 'mocha:unit', + 'mocha:integration', //'mocha:coverage', cb); }); gulp.task('mocha:unit', () => { return gulp.src(paths.server.test) - .pipe(plugins.mocha({ - reporter: 'spec', - require: [ - './mocha.conf' - ] - })) - .once('end', function() { - process.exit(); - }); + .pipe(mocha()); +}); + +gulp.task('mocha:integration', () => { + return gulp.src(paths.server.test.integration) + .pipe(mocha()); }); -gulp.task('test:client', () => { - let testFiles = _.union(paths.client.testRequire, paths.client.test); - return gulp.src(testFiles) - .pipe(plugins.karma({ - configFile: paths.karma, - action: 'watch' - })); +gulp.task('test:client', (done) => { + new KarmaServer({ + configFile: `${__dirname}/${paths.karma}`, + singleRun: true + }, done).start(); }); // inject bower components @@ -498,3 +548,48 @@ gulp.task('copy:server', () => { ], {cwdbase: true}) .pipe(gulp.dest(paths.dist)); }); + +gulp.task('coverage:pre', () => { + return gulp.src(paths.server.scripts) + // Covering files + .pipe(plugins.babelIstanbul()) + // Force `require` to return covered files + .pipe(plugins.babelIstanbul.hookRequire()); +}); + +gulp.task('coverage:unit', () => { + return gulp.src(paths.server.test.unit) + .pipe(mocha()) + .pipe(istanbul()) + // Creating the reports after tests ran +}); + +gulp.task('coverage:integration', () => { + return gulp.src(paths.server.test.integration) + .pipe(mocha()) + .pipe(istanbul()) + // Creating the reports after tests ran +}); + +gulp.task('mocha:coverage', cb => { + runSequence('coverage:pre', + 'env:all', + 'env:test', + 'coverage:unit', + 'coverage:integration', + cb); +}); + +// Downloads the selenium webdriver +gulp.task('webdriver_update', webdriver_update); + +gulp.task('test:e2e', ['env:all', 'env:test', 'start:server', 'webdriver_update'], cb => { + gulp.src(paths.client.e2e) + .pipe(protractor({ + configFile: 'protractor.conf.js', + })).on('error', err => { + console.log(err) + }).on('end', () => { + process.exit(); + }); +}); From 9596ba47a1e817605eb9ccdb600f4aa62d718e3f Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 17:48:55 +1100 Subject: [PATCH 04/13] fix(gulp): clean .tmp folder in build task ensure important files are preserved, the `.tmp` is cleaned and dot files are removed when running build task --- app/templates/gulpfile.babel(gulp).js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 067770ed0..eecb3837e 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -294,7 +294,7 @@ gulp.task('jscs', () => { .pipe(plugins.jscs.reporter()); }); -gulp.task('clean:tmp', () => del(['.tmp/**/*'])); +gulp.task('clean:tmp', () => del(['.tmp/**/*'], {dot: true})); gulp.task('start:client', cb => { whenServerReady(() => { @@ -440,6 +440,7 @@ gulp.task('wiredep:test', () => { gulp.task('build', cb => { runSequence( 'clean:dist', + 'clean:tmp', 'inject', 'wiredep:client', [ @@ -453,7 +454,7 @@ gulp.task('build', cb => { cb); }); -gulp.task('clean:dist', () => del([`${paths.dist}/**/*`])); +gulp.task('clean:dist', () => del([`${paths.dist}/!(.git*|.openshift|Procfile)**`], {dot: true})); gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { var appFilter = plugins.filter('**/app.js'); From f21a388f9e724b34cdd92f5a704782c2035e677d Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 18:27:41 +1100 Subject: [PATCH 05/13] feat(gulp): update useref to latest version --- app/templates/_package.json | 2 +- app/templates/gulpfile.babel(gulp).js | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/templates/_package.json b/app/templates/_package.json index e55f4b011..c4812ec8b 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -68,7 +68,7 @@ "gulp-sourcemaps": "^1.5.2", "gulp-svgmin": "^1.1.2", "gulp-uglify": "^1.2.0", - "gulp-useref": "^1.2.0", + "gulp-useref": "^3.0.3", "gulp-util": "^3.0.5", "gulp-watch": "^4.3.5",<% if(filters.jade) { %> "gulp-jade": "^1.0.1",<% } if(filters.stylus) { %> diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index eecb3837e..48d784203 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -460,14 +460,12 @@ gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { var appFilter = plugins.filter('**/app.js'); var jsFilter = plugins.filter('**/*.js'); var cssFilter = plugins.filter('**/*.css'); - var htmlFilter = plugins.filter('**/*.html');<% if(filters.jade) { %> + var htmlBlock = plugins.filter(['**/*.!(html)']);<% if(filters.jade) { %> var assetsFilter = plugins.filter('**/*.{js,css}');<% } %> - let assets = plugins.useref.assets({searchPath: [clientPath, '.tmp']}); - return gulp.src(paths.client.mainView)<% if(filters.jade) { %> .pipe(plugins.jade({pretty: true}))<% } %> - .pipe(assets) + .pipe(plugins.useref()) .pipe(appFilter) .pipe(plugins.addSrc.append('.tmp/templates.js')) .pipe(plugins.concat('app/app.js')) @@ -482,10 +480,10 @@ gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { processImportFrom: ['!fonts.googleapis.com'] })) .pipe(cssFilter.restore()) - .pipe(plugins.rev()) - .pipe(assets.restore()) - .pipe(plugins.revReplace()) - .pipe(plugins.useref())<% if(filters.jade) { %> + .pipe(htmlBlock) + .pipe(plugins.rev()) + .pipe(htmlBlock.restore()) + .pipe(plugins.revReplace())<% if(filters.jade) { %> .pipe(assetsFilter)<% } %> .pipe(gulp.dest(`${paths.dist}/${clientPath}`)); }); From cf017debb7f2715896bf93003b576a0242a270b5 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 22:30:25 +1100 Subject: [PATCH 06/13] fix(gulp): add missing gulp-env package --- app/templates/_package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/templates/_package.json b/app/templates/_package.json index c4812ec8b..e2804bb0d 100644 --- a/app/templates/_package.json +++ b/app/templates/_package.json @@ -47,6 +47,7 @@ "gulp-babel-istanbul": "^0.11.0", "gulp-cache": "^0.2.10", "gulp-concat": "^2.6.0", + "gulp-env": "^0.2.0", "gulp-filter": "^2.0.2", "gulp-imagemin": "^2.2.1", "gulp-inject": "^1.3.1", From 0cb4a4b9494a564508d6f2ec256374224465808b Mon Sep 17 00:00:00 2001 From: David Mohr Date: Wed, 16 Dec 2015 22:46:58 +1100 Subject: [PATCH 07/13] fix(gulp): get client tests working update `test:client` to invoke Karma directly --- app/templates/gulpfile.babel(gulp).js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 48d784203..eb7f99045 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -26,7 +26,7 @@ const paths = { assets: `${clientPath}/assets/**/*`, images: `${clientPath}/assets/images/**/*`, scripts: [ - `${clientPath}/**/*.<%= scriptExt %>`, + `${clientPath}/**/!(*.spec|*.mock).<%= scriptExt %>`, `!${clientPath}/bower_components/**/*.js` ], styles: [`${clientPath}/{app,components}/**/*.<%= styleExt %>`], From 4a5e02b93a3a39c8a485250e96ff9bf4508e5234 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 07:55:48 +1100 Subject: [PATCH 08/13] refactor(gulp): migrate mocha settings to lazypipe lift mocha settings to a lazypipe for reuse and update test globs to separate unit and integration server tests --- app/templates/gulpfile.babel(gulp).js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index eb7f99045..0a61da397 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -38,13 +38,12 @@ const paths = { bower: `${clientPath}/bower_components/` }, server: { - scripts: [`${serverPath}/**/*.<%= scriptExt %>`], + scripts: [`${serverPath}/**/!(*.spec|*.integration).<%= scriptExt %>`], json: [`${serverPath}/**/*.json`], - test: [ - `${serverPath}/**/*.spec.js`, - `${serverPath}/**/*.mock.js`, - `${serverPath}/**/*.integration.js` - ] + test: { + integration: `${serverPath}/**/*.integration.js`, + unit: `${serverPath}/**/*.spec.js` + } }, karma: 'karma.conf.js', dist: 'dist' @@ -318,7 +317,7 @@ gulp.task('start:server', () => { }); gulp.task('watch', () => { - var testFiles = _.union(paths.client.test, paths.server.test); + var testFiles = _.union(paths.client.test, paths.server.test.unit, paths.server.test.integration); plugins.livereload.listen(); @@ -383,7 +382,7 @@ gulp.task('test:server', cb => { }); gulp.task('mocha:unit', () => { - return gulp.src(paths.server.test) + return gulp.src(paths.server.test.unit) .pipe(mocha()); }); From bb679618d6bca2d84b7bc8adf1886f0171a5d005 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 07:51:07 +1100 Subject: [PATCH 09/13] fix(gulp): use different transpile options for server and client for Grunt parity, the server code should be transpiled with with the `runtime` option --- app/templates/gulpfile.babel(gulp).js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 0a61da397..dadf2e078 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -137,7 +137,15 @@ let styles = lazypipe() .pipe(plugins.autoprefixer, {browsers: ['last 1 version']}) .pipe(plugins.sourcemaps.write, '.');<% if(filters.babel || filters.coffee) { %> -let transpile = lazypipe() +let transpileServer = lazypipe() + .pipe(plugins.sourcemaps.init)<% if(filters.babel) { %> + .pipe(plugins.babel, { + optional: ['runtime'] + })<% } else { %> + .pipe(plugins.coffee, {bare: true})<% } %> + .pipe(plugins.sourcemaps.write, '.'); + +let transpileClient = lazypipe() .pipe(plugins.sourcemaps.init)<% if(filters.babel) { %> .pipe(plugins.babel, { optional: ['es7.classProperties'] @@ -255,13 +263,13 @@ gulp.task('styles', () => { gulp.task('transpile:client', () => { return gulp.src(paths.client.scripts) - .pipe(transpile()) + .pipe(transpileClient()) .pipe(gulp.dest('.tmp')); });<% } %> gulp.task('transpile:server', () => { return gulp.src(_.union(paths.server.scripts, paths.server.json)) - .pipe(transpile()) + .pipe(transpileServer()) .pipe(gulp.dest(`${paths.dist}/${serverPath}`)); }); @@ -335,7 +343,7 @@ gulp.task('watch', () => { plugins.watch(paths.client.scripts) //['inject:js'] .pipe(plugins.plumber())<% if(filters.babel || filters.coffee) { %> - .pipe(transpile()) + .pipe(transpileClient()) .pipe(gulp.dest('.tmp'))<% } %> .pipe(plugins.livereload()); From 017111297968f3fcfb604273fa37d162ad01a714 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 08:00:53 +1100 Subject: [PATCH 10/13] fix(gulp): make sure tests and main app file are not injected filter out tests and `app.js` from the script files injected into `index.html` --- app/templates/gulpfile.babel(gulp).js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index dadf2e078..83b9de837 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -212,7 +212,7 @@ gulp.task('inject', cb => { gulp.task('inject:js', () => { return gulp.src(paths.client.mainView) .pipe(plugins.inject( - gulp.src(_.union(paths.client.scripts, [`!${clientPath}/**/*.spec.<%= scriptExt %>`]), {read: false}) + gulp.src(_.union(paths.client.scripts, [`!${clientPath}/**/*.{spec,mock}.js`, `!${clientPath}/app/app.js`]), {read: false}) .pipe(plugins.sort(sortModulesFirst)), { starttag: '', From 3602406631d4f5e73d51bab6d11c1d975b25bd00 Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 08:12:53 +1100 Subject: [PATCH 11/13] fix(gulp): make sure `.htaccess` is copied on build --- app/templates/gulpfile.babel(gulp).js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 83b9de837..8d305d03f 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -536,7 +536,8 @@ gulp.task('build:images', () => { gulp.task('copy:extras', () => { return gulp.src([ `${clientPath}/favicon.ico`, - `${clientPath}/robots.txt` + `${clientPath}/robots.txt`, + `${clientPath}/.htaccess` ], { dot: true }) .pipe(gulp.dest(`${paths.dist}/${clientPath}`)); }); From 3bf29b27e4a3c61bc932af11dd3ea9a27c8fd48c Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 08:16:19 +1100 Subject: [PATCH 12/13] feat(gulp): add file revisioning for images use `rev.manifest` to record name changes and pass the manifest to `rev.replace` to update the appropriate files --- app/templates/gulpfile.babel(gulp).js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index 8d305d03f..b63224974 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -464,6 +464,8 @@ gulp.task('build', cb => { gulp.task('clean:dist', () => del([`${paths.dist}/!(.git*|.openshift|Procfile)**`], {dot: true})); gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { + var manifest = gulp.src(`${paths.dist}/${clientPath}/assets/rev-manifest.json`); + var appFilter = plugins.filter('**/app.js'); var jsFilter = plugins.filter('**/*.js'); var cssFilter = plugins.filter('**/*.css'); @@ -490,7 +492,7 @@ gulp.task('build:client', ['transpile:client', 'styles', 'html'], () => { .pipe(htmlBlock) .pipe(plugins.rev()) .pipe(htmlBlock.restore()) - .pipe(plugins.revReplace())<% if(filters.jade) { %> + .pipe(plugins.revReplace({manifest}))<% if(filters.jade) { %> .pipe(assetsFilter)<% } %> .pipe(gulp.dest(`${paths.dist}/${clientPath}`)); }); @@ -530,7 +532,13 @@ gulp.task('build:images', () => { progressive: true, interlaced: true })) - .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets/images`)); + .pipe(plugins.rev()) + .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets/images`)) + .pipe(plugins.rev.manifest(`${paths.dist}/${clientPath}/assets/rev-manifest.json`, { + base: `${paths.dist}/${clientPath}/assets`, + merge: true + })) + .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets`)); }); gulp.task('copy:extras', () => { From 103adb2e19feda6bdb3487b3cde69afd12feb48d Mon Sep 17 00:00:00 2001 From: David Mohr Date: Thu, 17 Dec 2015 10:21:38 +1100 Subject: [PATCH 13/13] fix(gulp): call `wiredep:test` before running tests --- app/templates/gulpfile.babel(gulp).js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/templates/gulpfile.babel(gulp).js b/app/templates/gulpfile.babel(gulp).js index b63224974..228a43d66 100644 --- a/app/templates/gulpfile.babel(gulp).js +++ b/app/templates/gulpfile.babel(gulp).js @@ -375,7 +375,7 @@ gulp.task('serve:dist', cb => { cb); }); -gulp.task('test', cb => { +gulp.task('test', ['wiredep:test'], cb => { return runSequence('test:server', 'test:client', cb); });