diff --git a/circle.yml b/circle.yml
index 31795bcd5..ad8bf69e5 100644
--- a/circle.yml
+++ b/circle.yml
@@ -3,7 +3,7 @@ machine:
node:
version: 5.11.1
post:
- - npm install -g gulp-cli grunt-cli bower
+ - npm install -g gulp-cli
## Customize checkout
checkout:
@@ -17,6 +17,9 @@ dependencies:
# builds. If you need to, you can add custom paths to cache:
cache_directories:
- "test/fixtures/node_modules"
+ post:
+ - wget https://saucelabs.com/downloads/sc-latest-linux.tar.gz
+ - tar -xzf sc-latest-linux.tar.gz
## Custom notifications
#notify:
@@ -25,3 +28,12 @@ notify:
# A list of hook hashes, containing the url field
# gitter hook
- url: https://webhooks.gitter.im/e/ac3980c61cb722b9e789
+
+test:
+ pre:
+ - cd sc-*-linux && ./bin/sc --user $SAUCE_USERNAME --api-key $SAUCE_ACCESS_KEY --readyfile ~/sauce_is_ready:
+ background: true
+ # Wait for tunnel to be ready
+ - while [ ! -e ~/sauce_is_ready ]; do sleep 1; done
+ post:
+ - killall --wait sc # wait for Sauce Connect to close the tunnel
diff --git a/gulpfile.js b/gulpfile.js
index 647f84404..c3adf0fda 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -35,7 +35,7 @@ const transpile = lazypipe()
.pipe(babel);
gulp.task('clean', () => {
- return del(['generators/**/*', './test/(**|!fixtures/node_modules|!fixtures/bower_components)/*']);
+ return del(['generators/**/*', './test/(**|!fixtures/node_modules)/*']);
});
gulp.task('babel', () => {
@@ -113,10 +113,7 @@ function updateFixtures(target) {
const dest = __dirname + (deps ? '/angular-fullstack-deps/' : '/test/fixtures/');
const appName = deps ? 'angular-fullstack-deps' : 'tempApp';
- return Promise.all([
- processJson('templates/app/_package.json', dest + 'package.json', {appName, genVer, private: !deps, test: test}),
- processJson('templates/app/_bower.json', dest + 'bower.json', {appName, genVer, private: !deps, test: test})
- ]);
+ return processJson('templates/app/_package.json', dest + 'package.json', {appName, genVer, private: !deps, test: test});
}
gulp.task('updateFixtures', cb => {
@@ -143,16 +140,13 @@ function execAsync(cmd, opt) {
}
gulp.task('installFixtures', function() {
- gutil.log('installing npm & bower dependencies for generated app');
+ gutil.log('installing npm dependencies for generated app');
let progress = setInterval(() => {
process.stdout.write('.');
}, 1 * 1000);
shell.cd('test/fixtures');
- return Promise.all([
- execAsync('npm install --quiet', {cwd: '../fixtures'}),
- execAsync('bower install', {cwd: '../fixtures'})
- ]).then(() => {
+ execAsync('npm install --quiet', {cwd: '../fixtures'}).then(() => {
process.stdout.write('\n');
if(!process.env.SAUCE_USERNAME) {
gutil.log('running npm run-script update-webdriver');
diff --git a/package.json b/package.json
index 671b33dc9..0a4406273 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "generator-angular-fullstack",
- "version": "3.7.5",
+ "version": "4.0.0-beta",
"description": "Yeoman generator for creating MEAN stack applications, using MongoDB, Express, AngularJS, and Node",
"keywords": [
"yeoman-generator",
@@ -45,6 +45,7 @@
"gulp-babel": "^6.1.2",
"gulp-beautify": "^2.0.0",
"gulp-filter": "^4.0.0",
+ "gulp-tap": "^0.1.3",
"insight": "~0.8.1",
"lodash": "^4.13.1",
"semver": "^5.1.0",
diff --git a/src/generators/app/index.js b/src/generators/app/index.js
index 6d4dd5435..8cb2566d7 100644
--- a/src/generators/app/index.js
+++ b/src/generators/app/index.js
@@ -11,6 +11,7 @@ import insight from '../insight-init';
import {exec} from 'child_process';
import babelStream from 'gulp-babel';
import beaufityStream from 'gulp-beautify';
+import tap from 'gulp-tap';
import filter from 'gulp-filter';
import semver from 'semver';
@@ -18,6 +19,9 @@ export class Generator extends Base {
constructor(...args) {
super(...args);
+ this.env.alias('angular-fullstack', 'afs');
+ this.env.alias('afs', 'angular-fullstack');
+
this.argument('name', { type: String, required: false });
this.option('skip-install', {
@@ -126,12 +130,12 @@ export class Generator extends Base {
}[val];
}
}, {
- // TODO: enable once Babel setup supports Flow
- // type: 'confirm',
- // name: 'flow',
- // message: 'Would you like to use Flow types with Babel?',
- // when: answers => answers.transpiler === 'babel'
- // }, {
+ type: 'confirm',
+ name: 'flow',
+ default: false,
+ message: 'Would you like to use Flow types with Babel?',
+ when: answers => answers.transpiler === 'babel'
+ }, {
type: 'list',
name: 'markup',
message: 'What would you like to write markup with?',
@@ -449,24 +453,32 @@ export class Generator extends Base {
]);
*/
+ const flow = this.filters.flow;
+
let babelPlugins = [
'babel-plugin-syntax-flow',
'babel-plugin-syntax-class-properties'
];
- // TODO: enable once Babel setup supports Flow
- // if(this.filters.babel && !this.filters.flow) {
+ if(this.filters.babel && !flow) {
babelPlugins.push('babel-plugin-transform-flow-strip-types');
- // }
+ }
- const jsFilter = filter(['client/**/*.js'], {restore: true});
+ let jsFilter = filter(['client/**/*.js'], {restore: true});
this.registerTransformStream([
jsFilter,
babelStream({
plugins: babelPlugins.map(require.resolve),
/* Babel get's confused about these if you're using an `npm link`ed
generator-angular-fullstack, thus the `require.resolve` */
- // retainLines: true,
+ shouldPrintComment(commentContents) {
+ if(flow) {
+ return true;
+ } else {
+ // strip `// @flow` comments if not using flow
+ return !(/@flow/.test(commentContents));
+ }
+ },
babelrc: false // don't grab the generator's `.babelrc`
}),
beaufityStream({
@@ -493,6 +505,42 @@ export class Generator extends Base {
jsFilter.restore
]);
+ /**
+ * TypeScript doesn't play nicely with things that don't have a default export
+ */
+ if(this.filters.ts) {
+ const modulesToFix = [
+ ['angular', 'angular'],
+ ['ngCookies', 'angular-cookies'],
+ ['ngResource', 'angular-resource'],
+ ['ngSanitize', 'angular-sanitize'],
+ ['uiRouter', 'angular-ui-router'],
+ ['uiBootstrap', 'angular-ui-bootstrap'],
+ ['ngMessages', 'angular-messages'],
+ ['io', 'socket.io-client']
+ ];
+ function replacer(contents) {
+ modulesToFix.forEach(([moduleName, importName]) => {
+ contents = contents.replace(
+ `import ${moduleName} from '${importName}'`,
+ `const ${moduleName} = require('${importName}')`
+ );
+ });
+ return contents;
+ }
+
+ let tsFilter = filter(['client/**/*.ts'], {restore: true});
+ this.registerTransformStream([
+ tsFilter,
+ tap(function(file, t) {
+ var contents = file.contents.toString();
+ contents = replacer(contents);
+ file.contents = new Buffer(contents);
+ }),
+ tsFilter.restore
+ ]);
+ }
+
let self = this;
this.sourceRoot(path.join(__dirname, '../../templates/app'));
this.processDirectory('.', '.');
@@ -515,14 +563,10 @@ export class Generator extends Base {
};
}
- get install() {
- return {
- installDeps: function() {
- this.installDependencies({
- skipInstall: this.options['skip-install']
- });
- }
- };
+ install() {
+ if(!this.options['skip-install']) {
+ this.spawnCommand('npm', ['install']);
+ }
}
get end() {
diff --git a/src/test/endpoint.test.js b/src/test/endpoint.test.js
index 729535b9f..1c901e8f1 100644
--- a/src/test/endpoint.test.js
+++ b/src/test/endpoint.test.js
@@ -53,12 +53,8 @@ function runEndpointGen(name, opt={}) {
dir = _dir;
// symlink our dependency directories
- return Promise.all([
- fs.mkdirAsync(dir + '/client').then(() => {
- return fs.symlinkAsync(__dirname + '/fixtures/bower_components', dir + '/client/bower_components');
- }),
- fs.symlinkAsync(__dirname + '/fixtures/node_modules', dir + '/node_modules')
- ]).then(done);
+ return fs.symlinkAsync(__dirname + '/fixtures/node_modules', dir + '/node_modules')
+ .then(done);
})
.withOptions(options)
.withArguments([name])
@@ -250,4 +246,4 @@ describe('angular-fullstack:endpoint', function() {
return jshintDir(dir, 'foo-bar').should.be.fulfilled();
});
});
-});
\ No newline at end of file
+});
diff --git a/src/test/fixtures/.bowerrc b/src/test/fixtures/.bowerrc
deleted file mode 100644
index 69fad3580..000000000
--- a/src/test/fixtures/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "directory": "bower_components"
-}
diff --git a/src/test/fixtures/.yo-rc.json b/src/test/fixtures/.yo-rc.json
index 3f652f692..b1c868ce5 100644
--- a/src/test/fixtures/.yo-rc.json
+++ b/src/test/fixtures/.yo-rc.json
@@ -26,7 +26,7 @@
"models": true,
"mongooseModels": true,
"mongoose": true,
- "grunt": true,
+ "gulp": true,
"mocha": true,
"jasmine": false,
"expect": true
diff --git a/src/test/get-expected-files.js b/src/test/get-expected-files.js
index 3543eda94..8a3665c16 100644
--- a/src/test/get-expected-files.js
+++ b/src/test/get-expected-files.js
@@ -49,21 +49,22 @@ export function app(options) {
'client/.htaccess',
'client/favicon.ico',
'client/robots.txt',
- 'client/index.html',
+ 'client/_index.html',
+ `client/polyfills.${script}`,
'client/app/app.' + script,
+ 'client/app/app.config.' + script,
'client/app/app.' + stylesheet,
- 'client/app/main/main.' + script,
+ 'client/app/main/main.component.' + script,
+ 'client/app/main/main.component.spec.' + script,
+ 'client/app/main/main.routes.' + script,
'client/app/main/main.' + markup,
'client/app/main/main.' + stylesheet,
- 'client/app/main/main.controller.' + script,
- 'client/app/main/main.controller.spec.' + script,
'client/assets/images/yeoman.png',
'client/components/footer/footer.' + stylesheet,
'client/components/footer/footer.' + markup,
- 'client/components/footer/footer.directive.' + script,
+ 'client/components/footer/footer.component.' + script,
'client/components/navbar/navbar.' + markup,
- 'client/components/navbar/navbar.controller.' + script,
- 'client/components/navbar/navbar.directive.' + script,
+ 'client/components/navbar/navbar.component.' + script,
'client/components/util/util.module.' + script,
'client/components/util/util.service.' + script,
'server/.jshintrc',
@@ -89,7 +90,6 @@ export function app(options) {
'e2e/main/main.spec.js',
'e2e/components/navbar/navbar.po.js',
'.babelrc',
- '.bowerrc',
'.buildignore',
'.editorconfig',
'.gitattributes',
@@ -97,13 +97,18 @@ export function app(options) {
'.travis.yml',
'.jscsrc',
'.yo-rc.json',
- 'Gruntfile.js',
+ 'gulpfile.babel.js',
'package.json',
- 'bower.json',
'karma.conf.js',
'mocha.conf.js',
+ 'mocha.global.js',
'protractor.conf.js',
- 'README.md'
+ 'README.md',
+ 'spec.js',
+ 'webpack.build.js',
+ 'webpack.dev.js',
+ 'webpack.test.js',
+ 'webpack.make.js'
]);
/* TypeScript */
@@ -120,6 +125,11 @@ export function app(options) {
]);
}
+ /* Flow */
+ if(options.flow) {
+ files.push('.flowconfig');
+ }
+
/* Ui-Router */
if (options.router === 'uirouter') {
files = files.concat([
@@ -155,18 +165,22 @@ export function app(options) {
/* Authentication */
if (options.auth) {
files = files.concat([
- 'client/app/account/account.' + script,
+ 'client/app/account/index.' + script,
+ 'client/app/account/account.routes.' + script,
'client/app/account/login/login.' + markup,
+ 'client/app/account/login/index.' + script,
'client/app/account/login/login.controller.' + script,
'client/app/account/settings/settings.' + markup,
+ 'client/app/account/settings/index.' + script,
'client/app/account/settings/settings.controller.' + script,
'client/app/account/signup/signup.' + markup,
+ 'client/app/account/signup/index.' + script,
'client/app/account/signup/signup.controller.' + script,
+ 'client/app/admin/index.' + script,
'client/app/admin/admin.' + markup,
'client/app/admin/admin.' + stylesheet,
- 'client/app/admin/admin.module.' + script,
- 'client/app/admin/admin.router.' + script,
'client/app/admin/admin.controller.' + script,
+ 'client/app/admin/admin.routes.' + script,
'client/components/auth/auth.module.' + script,
'client/components/auth/auth.service.' + script,
'client/components/auth/interceptor.service.' + script,
@@ -200,11 +214,10 @@ export function app(options) {
files = files.concat([
+ 'client/components/oauth-buttons/index.' + script,
'client/components/oauth-buttons/oauth-buttons.' + stylesheet,
'client/components/oauth-buttons/oauth-buttons.' + markup,
- 'client/components/oauth-buttons/oauth-buttons.controller.' + script,
'client/components/oauth-buttons/oauth-buttons.controller.spec.' + script,
- 'client/components/oauth-buttons/oauth-buttons.directive.' + script,
'client/components/oauth-buttons/oauth-buttons.directive.spec.' + script,
'e2e/components/oauth-buttons/oauth-buttons.po.js'
]);
diff --git a/src/test/main.test.js b/src/test/main.test.js
index 5e701de0d..93cf4eecc 100644
--- a/src/test/main.test.js
+++ b/src/test/main.test.js
@@ -15,7 +15,7 @@ import {
} from './test-helpers';
const defaultOptions = {
- buildtool: 'grunt',
+ buildtool: 'gulp',
transpiler: 'babel',
markup: 'html',
stylesheet: 'sass',
@@ -71,19 +71,19 @@ describe('angular-fullstack:app', function() {
});
it('passes JSCS', function() {
- return runCmd('grunt jscs').should.be.fulfilled();
+ return runCmd('gulp jscs').should.be.fulfilled();
});
- it('passes JSHint', function() {
- return runCmd('grunt jshint').should.be.fulfilled();
+ it('passes lint', function() {
+ return runCmd('gulp lint:scripts').should.be.fulfilled();
});
it('passes client tests', function() {
- return runCmd('grunt test:client').should.be.fulfilled();
+ return runCmd('gulp test:client').should.be.fulfilled();
});
it('passes server tests', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
describe('with a generated endpoint', function() {
@@ -94,7 +94,7 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
@@ -106,7 +106,7 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
@@ -118,7 +118,7 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
@@ -130,20 +130,20 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
if(!process.env.SKIP_E2E) {
- it('should run e2e tests successfully', function() {
- this.retries(2);
- return runCmd('grunt test:e2e').should.be.fulfilled();
- });
-
- it('should run e2e tests successfully for production app', function() {
- this.retries(2);
- return runCmd('grunt test:e2e:prod').should.be.fulfilled();
- });
+ // it('should run e2e tests successfully', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e').should.be.fulfilled();
+ // });
+
+ // it('should run e2e tests successfully for production app', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e:prod').should.be.fulfilled();
+ // });
}
});
@@ -163,10 +163,10 @@ describe('angular-fullstack:app', function() {
}
}).then(_dir => {
dir = _dir;
- jscsResult = runCmd('grunt jscs');
- lintResult = runCmd('grunt jshint');
- clientTestResult = runCmd('grunt test:client');
- serverTestResult = runCmd('grunt test:server');
+ jscsResult = runCmd('gulp jscs');
+ lintResult = runCmd('gulp lint:scripts');
+ clientTestResult = runCmd('gulp test:client');
+ serverTestResult = runCmd('gulp test:server');
});
});
@@ -180,7 +180,7 @@ describe('angular-fullstack:app', function() {
return jscsResult.should.be.fulfilled();
});
- it('passes JSHint', function() {
+ it('passes lint', function() {
return lintResult.should.be.fulfilled();
});
@@ -200,7 +200,7 @@ describe('angular-fullstack:app', function() {
var clientTestResult;
var serverTestResult;
var testOptions = {
- buildtool: 'grunt',
+ buildtool: 'gulp',
transpiler: 'ts',
markup: 'jade',
stylesheet: 'less',
@@ -217,10 +217,10 @@ describe('angular-fullstack:app', function() {
before(function() {
return runGen(testOptions).then(_dir => {
dir = _dir;
- jscsResult = runCmd('grunt jscs');
- lintResult = runCmd('grunt tslint');
- clientTestResult = runCmd('grunt test:client');
- serverTestResult = runCmd('grunt test:server');
+ jscsResult = runCmd('gulp jscs');
+ lintResult = runCmd('gulp lint:scripts');
+ clientTestResult = runCmd('gulp test:client');
+ serverTestResult = runCmd('gulp test:server');
});
});
@@ -254,20 +254,20 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
if(!process.env.SKIP_E2E) {
- it('should run e2e tests successfully', function() {
- this.retries(2);
- return runCmd('grunt test:e2e').should.be.fulfilled();
- });
-
- it('should run e2e tests successfully for production app', function() {
- this.retries(2);
- return runCmd('grunt test:e2e:prod').should.be.fulfilled();
- });
+ // it('should run e2e tests successfully', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e').should.be.fulfilled();
+ // });
+
+ // it('should run e2e tests successfully for production app', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e:prod').should.be.fulfilled();
+ // });
}
});
@@ -278,7 +278,7 @@ describe('angular-fullstack:app', function() {
var clientTestResult;
var serverTestResult;
var testOptions = {
- buildtool: 'grunt',
+ buildtool: 'gulp',
transpiler: 'babel',
markup: 'jade',
stylesheet: 'css',
@@ -296,10 +296,10 @@ describe('angular-fullstack:app', function() {
beforeEach(function() {
return runGen(testOptions).then(_dir => {
dir = _dir;
- jscsResult = runCmd('grunt jscs');
- lintResult = runCmd('grunt jshint');
- clientTestResult = runCmd('grunt test:client');
- serverTestResult = runCmd('grunt test:server');
+ jscsResult = runCmd('gulp jscs');
+ lintResult = runCmd('gulp lint:scripts');
+ clientTestResult = runCmd('gulp test:client');
+ serverTestResult = runCmd('gulp test:server');
});
});
@@ -333,20 +333,20 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
if(!process.env.SKIP_E2E) {
- it('should run e2e tests successfully', function() {
- this.retries(2);
- return runCmd('grunt test:e2e').should.be.fulfilled();
- });
-
- it('should run e2e tests successfully for production app', function() {
- this.retries(2);
- return runCmd('grunt test:e2e:prod').should.be.fulfilled();
- });
+ // it('should run e2e tests successfully', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e').should.be.fulfilled();
+ // });
+
+ // it('should run e2e tests successfully for production app', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e:prod').should.be.fulfilled();
+ // });
}
});
@@ -357,7 +357,7 @@ describe('angular-fullstack:app', function() {
var clientTestResult;
var serverTestResult;
var testOptions = {
- buildtool: 'grunt',
+ buildtool: 'gulp',
transpiler: 'ts',
markup: 'jade',
stylesheet: 'stylus',
@@ -375,10 +375,10 @@ describe('angular-fullstack:app', function() {
beforeEach(function() {
return runGen(testOptions).then(_dir => {
dir = _dir;
- jscsResult = runCmd('grunt jscs');
- lintResult = runCmd('grunt tslint');
- clientTestResult = runCmd('grunt test:client');
- serverTestResult = runCmd('grunt test:server');
+ jscsResult = runCmd('gulp jscs');
+ lintResult = runCmd('gulp lint:scripts');
+ clientTestResult = runCmd('gulp test:client');
+ serverTestResult = runCmd('gulp test:server');
});
});
@@ -412,20 +412,20 @@ describe('angular-fullstack:app', function() {
});
it('should run server tests successfully', function() {
- return runCmd('grunt test:server').should.be.fulfilled();
+ return runCmd('gulp test:server').should.be.fulfilled();
});
});
if(!process.env.SKIP_E2E) {
- it('should run e2e tests successfully', function() {
- this.retries(2);
- return runCmd('grunt test:e2e').should.be.fulfilled();
- });
-
- it('should run e2e tests successfully for production app', function() {
- this.retries(2);
- return runCmd('grunt test:e2e:prod').should.be.fulfilled();
- });
+ // it('should run e2e tests successfully', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e').should.be.fulfilled();
+ // });
+
+ // it('should run e2e tests successfully for production app', function() {
+ // this.retries(2);
+ // return runCmd('gulp test:e2e:prod').should.be.fulfilled();
+ // });
}
});
});
diff --git a/src/test/pre.test.js b/src/test/pre.test.js
index 61c88de27..d30652555 100644
--- a/src/test/pre.test.js
+++ b/src/test/pre.test.js
@@ -7,10 +7,6 @@ describe('test fixtures', function() {
assert.file([path.join(__dirname, 'fixtures/package.json')]);
});
- it('should have .bowerrc & bower.json in fixtures', function() {
- assert.file([path.join(__dirname, 'fixtures/bower.json'), path.join(__dirname, 'fixtures/.bowerrc')]);
- });
-
it('should have .yo-rc.json in fixtures', function() {
assert.file([path.join(__dirname, 'fixtures/.yo-rc.json')]);
});
@@ -24,14 +20,4 @@ describe('test fixtures', function() {
});
assert.file(deps);
});
-
- it('should have all bower packages in fixtures/bower_components', function() {
- var bowerJson = require('./fixtures/bower.json');
- var deps = Object.keys(bowerJson.dependencies);
- deps = deps.concat(Object.keys(bowerJson.devDependencies));
- deps = deps.map(function(dep) {
- return path.join(__dirname, 'fixtures', 'bower_components', dep);
- });
- assert.file(deps);
- });
-});
\ No newline at end of file
+});
diff --git a/src/test/test-helpers.js b/src/test/test-helpers.js
index ffd69c0a8..3bf005ab3 100644
--- a/src/test/test-helpers.js
+++ b/src/test/test-helpers.js
@@ -100,9 +100,6 @@ export function runGen(prompts, opts={}) {
if(DEBUG) console.log(`TEMP DIR: ${dir}`);
let promises = [
- fs.mkdirAsync(dir + '/client').then(() => {
- return fs.symlinkAsync(__dirname + '/fixtures/bower_components', dir + '/client/bower_components');
- }),
fs.symlinkAsync(__dirname + '/fixtures/node_modules', dir + '/node_modules')
];
diff --git a/templates/app/.bowerrc b/templates/app/.bowerrc
deleted file mode 100644
index 666f34745..000000000
--- a/templates/app/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "directory": "client/bower_components"
-}
diff --git a/templates/app/.flowconfig(flow) b/templates/app/.flowconfig(flow)
new file mode 100644
index 000000000..e69de29bb
diff --git a/templates/app/.jscsrc b/templates/app/.jscsrc
index e05f83c6c..2560db00f 100644
--- a/templates/app/.jscsrc
+++ b/templates/app/.jscsrc
@@ -31,7 +31,6 @@
"requireLineFeedAtFileEnd": true,
"requireSpaceAfterBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
"requireSpaceBeforeBinaryOperators": ["?", ":", "+", "-", "/", "*", "%", "==", "===", "!=", "!==", ">", ">=", "<", "<=", "&&", "||"],
- "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
"requireSpaceBeforeBlockStatements": true,
"requireSpacesInConditionalExpression": {
"afterTest": true,
diff --git a/templates/app/_.babelrc b/templates/app/_.babelrc
index bde6914ee..87789669f 100644
--- a/templates/app/_.babelrc
+++ b/templates/app/_.babelrc
@@ -1,4 +1,9 @@
{
"presets": ["es2015"],
- "plugins": ["transform-class-properties"]
-}
\ No newline at end of file
+ "plugins": [
+ <%_ if(filters.flow) { -%>
+ "transform-flow-comments",
+ <%_ } -%>
+ "transform-class-properties"
+ ]
+}
diff --git a/templates/app/_.gitignore b/templates/app/_.gitignore
index 9fbd89aa0..c8041ad71 100644
--- a/templates/app/_.gitignore
+++ b/templates/app/_.gitignore
@@ -4,6 +4,7 @@ public
.sass-cache<% } %>
.idea
client/bower_components
+client/index.html
dist
/server/config/local.env.js
npm-debug.log
diff --git a/templates/app/_bower.json b/templates/app/_bower.json
deleted file mode 100644
index b2bcd90bd..000000000
--- a/templates/app/_bower.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- "name": "<%= lodash.slugify(lodash.humanize(appname)) %>",
- "version": "0.0.0",
- "dependencies": {
- "angular": "~1.5.0",
- "json3": "~3.3.1",
- "es5-shim": "~3.0.1",<% if(filters.bootstrap) { if (filters.sass) { %>
- "bootstrap-sass-official": "~3.1.1",<% } %>
- "bootstrap": "~3.1.1",<% if(filters.oauth) { %>
- "bootstrap-social": "~4.9.1",<% }} %>
- "angular-resource": "~1.5.0",
- "angular-cookies": "~1.5.0",
- "angular-sanitize": "~1.5.0",<% if (filters.ngroute) { %>
- "angular-route": "~1.5.0",<% } if (filters.uibootstrap) { %>
- "angular-bootstrap": "~1.1.2",<% } %>
- "font-awesome": ">=4.1.0",
- "lodash": "~2.4.1"<% if(filters.socketio) { %>,
- "angular-socket-io": "~0.7.0"<% } if (filters.uirouter) { %>,
- "angular-ui-router": "~0.2.15"<% } if (filters.auth) { %>,
- "angular-validation-match": "~1.5.2"<% } %>
- },
- "devDependencies": {
- "angular-mocks": "~1.5.0"
- }
-}
diff --git a/templates/app/_package.json b/templates/app/_package.json
index c80e0bf40..219ef0a74 100644
--- a/templates/app/_package.json
+++ b/templates/app/_package.json
@@ -3,6 +3,24 @@
"version": "0.0.0",
"main": "server/app.js",
"dependencies": {
+ <%_ /* CLIENT */ _%>
+ "angular": "~1.5.5",<% if(filters.bootstrap) { if(filters.sass) { %>
+ "bootstrap-sass": "~3.1.1",<% } %>
+ "bootstrap": "~3.1.1",<% if(filters.oauth) { %>
+ "bootstrap-social": "~4.9.1",<% }} %>
+ "angular-animate": "~1.5.5",
+ "angular-aria": "~1.5.5",
+ "angular-resource": "~1.5.5",
+ "angular-cookies": "~1.5.5",
+ "angular-sanitize": "~1.5.5",<% if(filters.ngroute) { %>
+ "angular-route": "~1.5.5",<% } if(filters.uibootstrap) { %>
+ "angular-ui-bootstrap": "~1.1.2",<% } %>
+ "font-awesome": ">=4.1.0",<% if(filters.socketio) { %>
+ "angular-socket-io": "~0.7.0",<% } if(filters.uirouter) { %>
+ "angular-ui-router": "~0.2.15",<% } if(filters.auth) { %>
+ "angular-validation-match": "~1.5.2",<% } %>
+ <%_ /* END CLIENT */ _%>
+ "core-js": "^2.2.1",
"express": "^4.13.3",
"morgan": "~1.7.0",
"body-parser": "^1.13.3",
@@ -15,31 +33,41 @@
"lodash": "^4.6.1",
"lusca": "^1.3.0",
"babel-runtime": "^6.6.1",
- "babel-polyfill": "^6.7.2",<% if (filters.jade) { %>
- "jade": "^1.11.0",<% } %><% if (filters.html) { %>
- "ejs": "^2.3.3",<% } %><% if (filters.mongoose) { %>
+ "babel-polyfill": "^6.7.2",<% if(filters.jade) { %>
+ "jade": "^1.11.0",<% } %><% if(filters.html) { %>
+ "ejs": "^2.3.3",<% } %><% if(filters.mongoose) { %>
"mongoose": "^4.1.2",
"bluebird": "^3.3.3",
- "connect-mongo": "^1.1.0",<% } %><% if (filters.sequelize) { %>
+ "connect-mongo": "^1.1.0",<% } %><% if(filters.sequelize) { %>
"sequelize": "^3.5.1",
"sqlite3": "~3.1.1",
- "express-sequelize-session": "0.4.0",<% } %><% if (filters.auth) { %>
+ "express-sequelize-session": "0.4.0",<% } %><% if(filters.auth) { %>
"jsonwebtoken": "^7.0.0",
"express-jwt": "^3.0.0",
"passport": "~0.3.0",
- "passport-local": "^1.0.0",<% } %><% if (filters.facebookAuth) { %>
- "passport-facebook": "^2.0.0",<% } %><% if (filters.twitterAuth) { %>
- "passport-twitter": "^1.0.3",<% } %><% if (filters.googleAuth) { %>
- "passport-google-oauth20": "^1.0.0",<% } %><% if (filters.socketio) { %>
+ "passport-local": "^1.0.0",<% } %><% if(filters.facebookAuth) { %>
+ "passport-facebook": "^2.0.0",<% } %><% if(filters.twitterAuth) { %>
+ "passport-twitter": "^1.0.3",<% } %><% if(filters.googleAuth) { %>
+ "passport-google-oauth20": "^1.0.0",<% } %><% if(filters.socketio) { %>
"socket.io": "^1.3.5",
"socket.io-client": "^1.3.5",
"socketio-jwt": "^4.2.0",<% } %>
- "serve-favicon": "^2.3.0"
+ "serve-favicon": "^2.3.0",
+ "sprint-js": "~0.1.0"
},
"devDependencies": {
+ <%_ /* CLIENT */ _%>
+ "angular-mocks": "~1.5.5",<% if(filters.stylus) { %>
+ "bootstrap-styl": "^5.0.5",
+ "font-awesome-stylus": "^4.6.2",<% } %>
+ <%_ /* END CLIENT */ _%>
"autoprefixer": "^6.0.0",
"babel-core": "^6.6.5",
"babel-register": "^6.6.5",
+ <%_ if(filters.flow) { -%>
+ "flow-bin": "^0.27.0",
+ "babel-plugin-syntax-flow": "^6.8.0",
+ "babel-plugin-transform-flow-comments": "^6.8.0",<% } %>
"babel-plugin-transform-class-properties": "^6.6.0",
"babel-plugin-transform-runtime": "^6.6.0",
"babel-preset-es2015": "^6.6.0",<% if(filters.gulp) { %>
@@ -51,7 +79,8 @@
"gulp-babel": "^6.1.2",<% if(filters.ts) { %>
"gulp-typescript": "~2.13.0",
"gulp-typings": "^1.3.6",
- "gulp-tslint": "^5.0.0",<% } %>
+ "gulp-tslint": "^5.0.0",
+ "ts-helpers": "1.1.1",<% } %>
"gulp-cache": "^0.4.2",
"gulp-concat": "^2.6.0",
"gulp-env": "^0.4.0",
@@ -96,10 +125,8 @@
"utile": "~0.3.0",
"nodemon": "^1.3.7",
"run-sequence": "^1.1.0",
- "lazypipe": "^1.0.1",
- "wiredep": "^2.2.2",<% } /*end gulp*/ if(filters.grunt) { %>
+ "lazypipe": "^1.0.1",<% } /*end gulp*/ if(filters.grunt) { %>
"grunt": "^0.4.5",
- "grunt-wiredep": "^2.0.0",
"grunt-concurrent": "^2.0.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-concat": "^1.0.0",
@@ -108,8 +135,8 @@
"grunt-contrib-imagemin": "^1.0.0",
"grunt-contrib-jshint": "^1.0.0",
"grunt-contrib-uglify": "^1.0.0",
- "grunt-contrib-watch": "^1.0.0",<% if (filters.jade) { %>
- "grunt-contrib-jade": "^1.0.0",<% } %><% if (filters.less) { %>
+ "grunt-contrib-watch": "^1.0.0",<% if(filters.jade) { %>
+ "grunt-contrib-jade": "^1.0.0",<% } %><% if(filters.less) { %>
"grunt-contrib-less": "^1.2.0",<% } %>
"grunt-babel": "~6.0.0",<% if(filters.ts) { %>
"grunt-ts": "^5.3.2",
@@ -140,6 +167,39 @@
"time-grunt": "^1.2.1",
"grunt-mocha-test": "~0.12.7",
"grunt-mocha-istanbul": "^4.0.2",<% } /*end grunt*/ %>
+ <%_ /* WEBPACK */ _%>
+ "webpack": "^1.12.14",
+ "webpack-dev-middleware": "^1.5.1",
+ "webpack-dev-server": "~1.14.0",
+ "webpack-stream": "^3.2.0",
+ "extract-text-webpack-plugin": "^1.0.1",
+ "html-webpack-plugin": "^2.16.0",
+ "html-webpack-harddisk-plugin": "~0.0.2",
+ <%_ if(filters.jade) { _%>
+ "pug-html-loader": "^1.0.5",<% } %>
+ "awesome-typescript-loader": "0.17.0",
+ "ng-annotate-loader": "~0.1.0",
+ "babel-loader": "^6.2.4",
+ "css-loader": "^0.23.1",
+ "file-loader": "^0.8.4",
+ "imports-loader": "^0.6.5",
+ "isparta-instrumenter-loader": "^1.0.0",
+ "isparta-loader": "^2.0.0",
+ "istanbul-instrumenter-loader": "^0.2.0",
+ "null-loader": "^0.1.1",
+ "postcss-loader": "^0.9.1",
+ "raw-loader": "^0.5.1",
+ "style-loader": "^0.13.0",
+ <%_ if(filters.sass) { _%>
+ "sass-loader": "^3.1.1",<% } %>
+ <%_ if(filters.less) { _%>
+ "less-loader": "^2.2.3",<% } %>
+ <%_ if(filters.stylus) { _%>
+ "stylus-loader": "^2.1.1",<% } %>
+ "tiny-lr": "^0.2.1",
+ "karma-webpack": "^1.7.0",
+ <%_ /* END WEBPACK */ _%>
+ "through2": "^2.0.1",
"open": "~0.0.4",
"jshint-stylish": "^2.2.0",
"connect-livereload": "^0.5.3",
@@ -151,20 +211,18 @@
"karma": "~0.13.3",
"karma-firefox-launcher": "^1.0.0",
"karma-script-launcher": "^1.0.0",
+ "karma-coverage": "^0.5.3",
"karma-chrome-launcher": "^1.0.1",
- "karma-jade-preprocessor": "0.0.11",
- "karma-phantomjs-launcher": "~1.0.0",<% if (filters.jade) { %>
- "karma-ng-jade2js-preprocessor": "^0.2.0",<% } %>
- "karma-ng-html2js-preprocessor": "^1.0.0",
+ "karma-phantomjs-launcher": "~1.0.0",
"karma-spec-reporter": "~0.0.20",
+ "karma-sourcemap-loader": "~0.3.7",
"sinon-chai": "^2.8.0",
- "mocha": "^2.2.5",<% if (filters.mocha) { %>
+ "mocha": "^2.2.5",<% if(filters.mocha) { %>
"karma-mocha": "^1.0.1",
- "karma-chai-plugins": "~0.7.0",<% } if (filters.jasmine) { %>
+ "karma-chai-plugins": "~0.7.0",<% } if(filters.jasmine) { %>
"jasmine-core": "^2.3.4",
"karma-jasmine": "^1.0.2",
- "jasmine-spec-reporter": "^2.4.0",<% } if(filters.babel) { %>
- "karma-babel-preprocessor": "^6.0.1",<% } %>
+ "jasmine-spec-reporter": "^2.4.0",<% } %>
"phantomjs-prebuilt": "^2.1.4",
"proxyquire": "^1.0.1",
"supertest": "^1.1.0"<% if(filters.ts) { %>,
@@ -175,15 +233,23 @@
"node": "^4.4.0",
"npm": "^2.14.20"
},
- "scripts": {<% if(filters.gulp) { %>
- "test": "gulp test",<% } else { %>
- "test": "grunt test",<% } %>
- <%_ if(filters.ts) { _%>
- "postinstall": "./node_modules/.bin/typings install",<% } %>
- <%_ if(semver.satisfies(npmVersion, '>= 3')) { _%>
+ "scripts": {
+ <%_ if(filters.gulp) { -%>
+ "test": "gulp test",
+ <%_ } else { -%>
+ "test": "grunt test",
+ <%_ } -%>
+ <%_ if(filters.ts) { -%>
+ "postinstall": "./node_modules/.bin/typings install",
+ <%_ } -%>
+ <%_ if(filters.flow) { -%>
+ "flow": "flow",
+ <%_ } -%>
+ <%_ if(semver.satisfies(npmVersion, '>= 3')) { -%>
"update-webdriver": "node node_modules/protractor/bin/webdriver-manager update",
- <%_ } else { _%>
- "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update",<% } %>
+ <%_ } else { -%>
+ "update-webdriver": "node node_modules/grunt-protractor-runner/node_modules/protractor/bin/webdriver-manager update",
+ <%_ } -%>
"start": "node server"
},
"private": true
diff --git a/templates/app/client/__index.html b/templates/app/client/__index.html
new file mode 100644
index 000000000..29826783d
--- /dev/null
+++ b/templates/app/client/__index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+ Angular Full-Stack Generator
+
+
+
+
+
+
+
+
+
+
+
+ <% if (filters.ngroute) { %><% } %><% if (filters.uirouter) { %><% } %>
+
+
+
diff --git a/templates/app/client/app/account(auth)/account.js b/templates/app/client/app/account(auth)/account.routes.js
similarity index 53%
rename from templates/app/client/app/account(auth)/account.js
rename to templates/app/client/app/account(auth)/account.routes.js
index 4266116fa..d15b803c5 100644
--- a/templates/app/client/app/account(auth)/account.js
+++ b/templates/app/client/app/account(auth)/account.routes.js
@@ -1,81 +1,72 @@
'use strict';
-angular.module('<%= scriptAppName %>')
- <% if (filters.ngroute) { %>.config(function($routeProvider) {
- $routeProvider
- .when('/login', {
- templateUrl: 'app/account/login/login.html',
+<%_ if (filters.uirouter) { _%>
+export default function routes($stateProvider) {
+ 'ngInject';
+ $stateProvider
+ .state('login', {
+ url: '/login',
+ template: require('./login/login.<%= templateExt %>'),
controller: 'LoginController',
controllerAs: 'vm'
})
- .when('/logout', {
- name: 'logout',
- referrer: '/',
+ .state('logout', {
+ url: '/logout?referrer',
+ referrer: 'main',
template: '',
- controller: function($location, $route, Auth) {
- var referrer = $route.current.params.referrer ||
- $route.current.referrer ||
- '/';
+ controller: function($state, Auth) {
+ 'ngInject';
+ var referrer = $state.params.referrer
+ || $state.current.referrer
+ || 'main';
Auth.logout();
- $location.path(referrer);
+ $state.go(referrer);
}
})
- .when('/signup', {
- templateUrl: 'app/account/signup/signup.html',
+ .state('signup', {
+ url: '/signup',
+ template: require('./signup/signup.<%= templateExt %>'),
controller: 'SignupController',
controllerAs: 'vm'
})
- .when('/settings', {
- templateUrl: 'app/account/settings/settings.html',
+ .state('settings', {
+ url: '/settings',
+ template: require('./settings/settings.<%= templateExt %>'),
controller: 'SettingsController',
controllerAs: 'vm',
authenticate: true
});
- })
- .run(function($rootScope) {
- $rootScope.$on('$routeChangeStart', function(event, next, current) {
- if (next.name === 'logout' && current && current.originalPath && !current.authenticate) {
- next.referrer = current.originalPath;
- }
- });
- });<% } %><% if (filters.uirouter) { %>.config(function($stateProvider) {
- $stateProvider
- .state('login', {
- url: '/login',
- templateUrl: 'app/account/login/login.html',
+}<% } %>
+<%_ if (filters.ngroute) { _%>
+export default function routes($routeProvider) {
+ 'ngInject';
+ $routeProvider
+ .when('/login', {
+ template: require('./login/login.<%= templateExt %>'),
controller: 'LoginController',
controllerAs: 'vm'
})
- .state('logout', {
- url: '/logout?referrer',
- referrer: 'main',
+ .when('/logout', {
+ name: 'logout',
+ referrer: '/',
template: '',
- controller: function($state, Auth) {
- var referrer = $state.params.referrer ||
- $state.current.referrer ||
- 'main';
+ controller: function($location, $route, Auth) {
+ var referrer = $route.current.params.referrer ||
+ $route.current.referrer ||
+ '/';
Auth.logout();
- $state.go(referrer);
+ $location.path(referrer);
}
})
- .state('signup', {
- url: '/signup',
- templateUrl: 'app/account/signup/signup.html',
+ .when('/signup', {
+ template: require('./signup/signup.<%= templateExt %>'),
controller: 'SignupController',
controllerAs: 'vm'
})
- .state('settings', {
- url: '/settings',
- templateUrl: 'app/account/settings/settings.html',
+ .when('/settings', {
+ template: require('./settings/settings.<%= templateExt %>'),
controller: 'SettingsController',
controllerAs: 'vm',
authenticate: true
});
- })
- .run(function($rootScope) {
- $rootScope.$on('$stateChangeStart', function(event, next, nextParams, current) {
- if (next.name === 'logout' && current && current.name && !current.authenticate) {
- next.referrer = current.name;
- }
- });
- });<% } %>
+}<% } %>
diff --git a/templates/app/client/app/account(auth)/index.js b/templates/app/client/app/account(auth)/index.js
new file mode 100644
index 000000000..48ade7142
--- /dev/null
+++ b/templates/app/client/app/account(auth)/index.js
@@ -0,0 +1,44 @@
+'use strict';
+import angular from 'angular';
+<%_ if (filters.ngroute) { _%>
+const ngRoute = require('angular-route'); <% } %>
+<%_ if (filters.uirouter) { _%>
+import uiRouter from 'angular-ui-router';<% } %>
+
+import routing from './account.routes';
+import login from './login';
+import settings from './settings';
+import signup from './signup';
+<%_ if(filters.oauth) { _%>
+import oauthButtons from '../../components/oauth-buttons';<% } %>
+
+export default angular.module('<%= scriptAppName %>.account', [
+ <%_ if (filters.ngroute) { _%>
+ ngRoute,<% } %>
+ <%_ if (filters.uirouter) { _%>
+ uiRouter,<% } %>
+ login,
+ settings,
+ signup<% if(filters.oauth) { %>,
+ oauthButtons<% } %>
+])
+ .config(routing)
+ <%_ if (filters.ngroute) { _%>
+ .run(function($rootScope) {
+ 'ngInject';
+ $rootScope.$on('$routeChangeStart', function(event, next, current) {
+ if (next.name === 'logout' && current && current.originalPath && !current.authenticate) {
+ next.referrer = current.originalPath;
+ }
+ });
+ })<% } %>
+ <%_ if (filters.uirouter) { _%>
+ .run(function($rootScope) {
+ 'ngInject';
+ $rootScope.$on('$stateChangeStart', function(event, next, nextParams, current) {
+ if (next.name === 'logout' && current && current.name && !current.authenticate) {
+ next.referrer = current.name;
+ }
+ });
+ })<% } %>
+ .name;
diff --git a/templates/app/client/app/account(auth)/login/index.js b/templates/app/client/app/account(auth)/login/index.js
new file mode 100644
index 000000000..187b43be5
--- /dev/null
+++ b/templates/app/client/app/account(auth)/login/index.js
@@ -0,0 +1,6 @@
+'use strict';
+import LoginController from './login.controller';
+
+export default angular.module('<%= scriptAppName %>.login', [])
+ .controller('LoginController', LoginController)
+ .name;
diff --git a/templates/app/client/app/account(auth)/login/login.controller.js b/templates/app/client/app/account(auth)/login/login.controller.js
index d53fcbe20..1aa48e1e3 100644
--- a/templates/app/client/app/account(auth)/login/login.controller.js
+++ b/templates/app/client/app/account(auth)/login/login.controller.js
@@ -1,6 +1,7 @@
'use strict';
-class LoginController {
+export default class LoginController {
+ /*@ngInject*/
constructor(Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %>) {
this.user = {};
this.errors = {};
@@ -29,6 +30,3 @@ class LoginController {
}
}
}
-
-angular.module('<%= scriptAppName %>')
- .controller('LoginController', LoginController);
diff --git a/templates/app/client/app/account(auth)/settings/index.js b/templates/app/client/app/account(auth)/settings/index.js
new file mode 100644
index 000000000..823caa530
--- /dev/null
+++ b/templates/app/client/app/account(auth)/settings/index.js
@@ -0,0 +1,6 @@
+'use strict';
+import SettingsController from './settings.controller';
+
+export default angular.module('<%= scriptAppName %>.settings', [])
+ .controller('SettingsController', SettingsController)
+ .name;
diff --git a/templates/app/client/app/account(auth)/settings/settings.controller.js b/templates/app/client/app/account(auth)/settings/settings.controller.js
index 58c89e0ff..976bd5154 100644
--- a/templates/app/client/app/account(auth)/settings/settings.controller.js
+++ b/templates/app/client/app/account(auth)/settings/settings.controller.js
@@ -1,9 +1,10 @@
'use strict';
-class SettingsController {
+export default class SettingsController {
errors = {};
submitted = false;
+ /*@ngInject*/
constructor(Auth) {
this.Auth = Auth;
}
@@ -24,6 +25,3 @@ class SettingsController {
}
}
}
-
-angular.module('<%= scriptAppName %>')
- .controller('SettingsController', SettingsController);
diff --git a/templates/app/client/app/account(auth)/signup/index.js b/templates/app/client/app/account(auth)/signup/index.js
new file mode 100644
index 000000000..43b4842b7
--- /dev/null
+++ b/templates/app/client/app/account(auth)/signup/index.js
@@ -0,0 +1,7 @@
+'use strict';
+
+import SignupController from './signup.controller';
+
+export default angular.module('<%= scriptAppName %>.signup', [])
+ .controller('SignupController', SignupController)
+ .name;
diff --git a/templates/app/client/app/account(auth)/signup/signup.controller.js b/templates/app/client/app/account(auth)/signup/signup.controller.js
index a6f83fb58..6ae9064e4 100644
--- a/templates/app/client/app/account(auth)/signup/signup.controller.js
+++ b/templates/app/client/app/account(auth)/signup/signup.controller.js
@@ -1,12 +1,13 @@
'use strict';
-class SignupController {
+export default class SignupController {
//start-non-standard
user = {};
errors = {};
submitted = false;
//end-non-standard
+ /*@ngInject*/
constructor(Auth<% if (filters.ngroute) { %>, $location<% } %><% if (filters.uirouter) { %>, $state<% } %>) {
this.Auth = Auth;<% if (filters.ngroute) { %>
this.$location = $location;<% } if (filters.uirouter) { %>
@@ -47,6 +48,3 @@ if (filters.sequelizeModels) { %>
}
}
}
-
-angular.module('<%= scriptAppName %>')
- .controller('SignupController', SignupController);
diff --git a/templates/app/client/app/admin(auth)/admin.controller.js b/templates/app/client/app/admin(auth)/admin.controller.js
index b56309871..afb2e557b 100644
--- a/templates/app/client/app/admin(auth)/admin.controller.js
+++ b/templates/app/client/app/admin(auth)/admin.controller.js
@@ -1,12 +1,11 @@
'use strict';
-(function() {
-
-class AdminController {
+export default class AdminController {
<%_ if(filters.ts || filters.flow) { _%>
users: Object[];
<%_ } _%>
+ /*@ngInject*/
constructor(User) {
// Use the User $resource to fetch all users
this.users = User.query();
@@ -17,8 +16,3 @@ class AdminController {
this.users.splice(this.users.indexOf(user), 1);
}
}
-
-angular.module('<%= scriptAppName %>.admin')
- .controller('AdminController', AdminController);
-
-})();
diff --git a/templates/app/client/app/admin(auth)/admin.module.js b/templates/app/client/app/admin(auth)/admin.module.js
deleted file mode 100644
index da769ae91..000000000
--- a/templates/app/client/app/admin(auth)/admin.module.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>.admin', [
- '<%= scriptAppName %>.auth'<% if (filters.ngroute) { %>,
- 'ngRoute'<% } if (filters.uirouter) { %>,
- 'ui.router'<% } %>
-]);
diff --git a/templates/app/client/app/admin(auth)/admin.router.js b/templates/app/client/app/admin(auth)/admin.router.js
deleted file mode 100644
index cc3d9e9f9..000000000
--- a/templates/app/client/app/admin(auth)/admin.router.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>.admin')
- <% if (filters.ngroute) { %>.config(function($routeProvider) {
- $routeProvider
- .when('/admin', {
- templateUrl: 'app/admin/admin.html',
- controller: 'AdminController',
- controllerAs: 'admin',
- authenticate: 'admin'
- });
- });<% } if (filters.uirouter) { %>.config(function($stateProvider) {
- $stateProvider
- .state('admin', {
- url: '/admin',
- templateUrl: 'app/admin/admin.html',
- controller: 'AdminController',
- controllerAs: 'admin',
- authenticate: 'admin'
- });
- });<% } %>
diff --git a/templates/app/client/app/admin(auth)/admin.routes.js b/templates/app/client/app/admin(auth)/admin.routes.js
new file mode 100644
index 000000000..24114892e
--- /dev/null
+++ b/templates/app/client/app/admin(auth)/admin.routes.js
@@ -0,0 +1,25 @@
+'use strict';
+
+<%_ if (filters.ngroute) { _%>
+export default function routes($routeProvider) {
+ 'ngInject';
+ $routeProvider
+ .when('/admin', {
+ template: require('./admin.<%= templateExt %>'),
+ controller: 'AdminController',
+ controllerAs: 'admin',
+ authenticate: 'admin'
+ });
+};<% } %>
+<%_ if (filters.uirouter) { _%>
+export default function routes($stateProvider) {
+ 'ngInject';
+ $stateProvider
+ .state('admin', {
+ url: '/admin',
+ template: require('./admin.<%= templateExt %>'),
+ controller: 'AdminController',
+ controllerAs: 'admin',
+ authenticate: 'admin'
+ });
+};<% } %>
diff --git a/templates/app/client/app/admin(auth)/index.js b/templates/app/client/app/admin(auth)/index.js
new file mode 100644
index 000000000..d78165412
--- /dev/null
+++ b/templates/app/client/app/admin(auth)/index.js
@@ -0,0 +1,12 @@
+'use strict';
+import routes from './admin.routes';
+import AdminController from './admin.controller';
+
+export default angular.module('<%= scriptAppName %>.admin', [
+ '<%= scriptAppName %>.auth'<% if (filters.ngroute) { %>,
+ 'ngRoute'<% } if (filters.uirouter) { %>,
+ 'ui.router'<% } %>
+])
+ .config(routes)
+ .controller('AdminController', AdminController)
+ .name;
diff --git a/templates/app/client/app/app(css).css b/templates/app/client/app/app(css).css
index 2dbd1e8c5..293da309f 100644
--- a/templates/app/client/app/app(css).css
+++ b/templates/app/client/app/app(css).css
@@ -5,11 +5,11 @@
@font-face {
font-family: 'Glyphicons Halflings';
- src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot');
- src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
+ src: url('/assets/fonts/bootstrap/glyphicons-halflings-regular.eot');
+ src: url('/assets/fonts/bootstrap/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
+ url('/assets/fonts/bootstrap/glyphicons-halflings-regular.woff') format('woff'),
+ url('/assets/fonts/bootstrap/glyphicons-halflings-regular.ttf') format('truetype'),
+ url('/assets/fonts/bootstrap/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
}<% } %>
/**
@@ -18,11 +18,11 @@
@font-face {
font-family: 'FontAwesome';
- src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0');
- src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
+ src: url('/assets/fonts/font-awesome/fontawesome-webfont.eot?v=4.1.0');
+ src: url('/assets/fonts/font-awesome/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),
+ url('/assets/fonts/font-awesome/fontawesome-webfont.woff?v=4.1.0') format('woff'),
+ url('/assets/fonts/font-awesome/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),
+ url('/assets/fonts/font-awesome/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
diff --git a/templates/app/client/app/app(less).less b/templates/app/client/app/app(less).less
index 44268cf9f..191118fbb 100644
--- a/templates/app/client/app/app(less).less
+++ b/templates/app/client/app/app(less).less
@@ -1,9 +1,9 @@
-<% if (filters.bootstrap) { %>@import '../bower_components/bootstrap/less/bootstrap.less';
-<% if(filters.oauth) { %>@import '../bower_components/bootstrap-social/bootstrap-social.less';
-<% }} %>@import '../bower_components/font-awesome/less/font-awesome.less';
+<% if(filters.bootstrap) { %>@import '~bootstrap/less/bootstrap.less';
+<% if(filters.oauth) { %>@import '~bootstrap-social/bootstrap-social.less';
+<% }} %>@import '~font-awesome/less/font-awesome.less';
-<% if (filters.bootstrap) { %>@icon-font-path: '../bower_components/bootstrap/fonts/';<% } %>
-@fa-font-path: '../bower_components/font-awesome/fonts';
+<% if(filters.bootstrap) { %>@icon-font-path: '/assets/fonts/bootstrap/';<% } %>
+@fa-font-path: '/assets/fonts/font-awesome/';
/**
* App-wide Styles
diff --git a/templates/app/client/app/app(sass).scss b/templates/app/client/app/app(sass).scss
index 0191121c1..3126d9998 100644
--- a/templates/app/client/app/app(sass).scss
+++ b/templates/app/client/app/app(sass).scss
@@ -1,8 +1,13 @@
-<% if (filters.bootstrap) { %>$icon-font-path: "../bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/";
-@import '../bower_components/bootstrap-sass-official/vendor/assets/stylesheets/bootstrap';
-<% if(filters.oauth) { %>@import '../bower_components/bootstrap-social/bootstrap-social.scss';
-<% }} %>$fa-font-path: "../bower_components/font-awesome/fonts";
-@import '../bower_components/font-awesome/scss/font-awesome';
+<%_ if (filters.bootstrap) { _%>
+$icon-font-path: '/assets/fonts/bootstrap/';
+@import '~bootstrap-sass/vendor/assets/stylesheets/bootstrap';
+<%_ if(filters.oauth) { _%>
+@import '~bootstrap-social/bootstrap-social.scss';
+<% }} _%>
+$fa-font-path: '/assets/fonts/font-awesome/';
+@import '~font-awesome/scss/font-awesome';
+
+// @import url(http://fonts.googleapis.com/css?family=Open+Sans:300,400,600,900|Roboto:300,500,700,900);
/**
* App-wide Styles
diff --git a/templates/app/client/app/app(stylus).styl b/templates/app/client/app/app(stylus).styl
index ca1778ffd..0fc016ef5 100644
--- a/templates/app/client/app/app(stylus).styl
+++ b/templates/app/client/app/app(stylus).styl
@@ -1,32 +1,11 @@
-@import "../bower_components/font-awesome/css/font-awesome.css"
-<% if (filters.bootstrap) { %>@import "../bower_components/bootstrap/dist/css/bootstrap.css"
-<% if (filters.oauth) { %>@import "../bower_components/bootstrap-social/bootstrap-social.css"
-<% } %>
-//
-// Bootstrap Fonts
-//
-
-@font-face
- font-family: 'Glyphicons Halflings'
- src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot')
- src: url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.woff') format('woff'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.ttf') format('truetype'),
- url('../bower_components/bootstrap/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg');
-<% } %>
-//
-// Font Awesome Fonts
-//
+$fa-font-path = '../assets/fonts/font-awesome/'
+@import '~font-awesome-stylus/stylus/index'
-@font-face
- font-family: 'FontAwesome'
- src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?v=4.1.0')
- src: url('../bower_components/font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.woff?v=4.1.0') format('woff'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.ttf?v=4.1.0') format('truetype'),
- url('../bower_components/font-awesome/fonts/fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
- font-weight: normal
- font-style: normal
+<%_ if (filters.bootstrap) { %>
+$icon-font-path = '../assets/fonts/bootstrap/'
+@import '~bootstrap-styl/bootstrap/index';
+<% if (filters.oauth) { %>@import '~bootstrap-social/bootstrap-social.css'
+<% } %><% } %>
//
// App-wide Styles
diff --git a/templates/app/client/app/app.config.js b/templates/app/client/app/app.config.js
new file mode 100644
index 000000000..3b3ea607b
--- /dev/null
+++ b/templates/app/client/app/app.config.js
@@ -0,0 +1,15 @@
+'use strict';
+
+export function routeConfig(<% if (filters.ngroute) { %>$routeProvider<% } if (filters.uirouter) { %>$urlRouterProvider<% } %>, $locationProvider) {
+ 'ngInject';
+ <%_ if(filters.ngroute) { _%>
+ $routeProvider
+ .otherwise({
+ redirectTo: '/'
+ });<% } %>
+ <%_ if(filters.uirouter) { _%>
+ $urlRouterProvider
+ .otherwise('/');<% } %>
+
+ $locationProvider.html5Mode(true);
+}
diff --git a/templates/app/client/app/app.js b/templates/app/client/app/app.js
index a9d9f2b09..d0b622947 100644
--- a/templates/app/client/app/app.js
+++ b/templates/app/client/app/app.js
@@ -1,13 +1,84 @@
'use strict';
+import angular from 'angular';
+// import ngAnimate from 'angular-animate';
+import ngCookies from 'angular-cookies';
+import ngResource from 'angular-resource';
+import ngSanitize from 'angular-sanitize';
+<%_ if(filters.socketio) { _%>
+import 'angular-socket-io';<% } %>
+<%_ if(filters.ngroute) { _%>
+const ngRoute = require('angular-route');<% } %>
+<%_ if(filters.uirouter) { _%>
+import uiRouter from 'angular-ui-router';<% } %>
+<%_ if(filters.uibootstrap) { _%>
+import uiBootstrap from 'angular-ui-bootstrap';<% } %>
+// import ngMessages from 'angular-messages';
+<%_ if(filters.auth) { _%>
+//import ngValidationMatch from 'angular-validation-match';<% } %>
-angular.module('<%= scriptAppName %>', [<%- angularModules %>])
- .config(function(<% if (filters.ngroute) { %>$routeProvider<% } if (filters.uirouter) { %>$urlRouterProvider<% } %>, $locationProvider) {<% if (filters.ngroute) { %>
- $routeProvider
- .otherwise({
- redirectTo: '/'
- });<% } if (filters.uirouter) { %>
- $urlRouterProvider
- .otherwise('/');<% } %>
- $locationProvider.html5Mode(true);
+import {routeConfig} from './app.config';
+
+<%_ if(filters.auth) { _%>
+import _Auth from '../components/auth/auth.module';
+import account from './account';
+import admin from './admin';<% } %>
+import navbar from '../components/navbar/navbar.component';
+import footer from '../components/footer/footer.component';
+import main from './main/main.component';
+import './app.constant';
+import util from '../components/util/util.module';
+<%_ if(filters.socketio) { _%>
+import socket from '../components/socket/socket.service';<% } %>
+
+
+import './app.<%= styleExt %>';
+
+angular.module('<%= scriptAppName %>', [
+ // ngAnimate,
+ ngCookies,
+ ngResource,
+ ngSanitize,
+ <%_ if(filters.socketio) { %>
+ 'btford.socket-io',<% } %>
+ <%_ if(filters.ngroute) { %>
+ ngRoute,<% } _%>
+ <%_ if(filters.uirouter) { %>
+ uiRouter,<% } _%>
+ <%_ if(filters.uibootstrap) { %>
+ uiBootstrap,<% } %>
+ // ngMessages,
+ <%_ if(filters.auth) { %>
+ // ngValidationMatch,
+ _Auth,
+ account,
+ admin,<% } _%>
+ navbar,
+ footer,
+ main,
+ '<%= scriptAppName %>.constants',
+ <%_ if(filters.socketio) { _%>
+ socket,<% } %>
+ util
+])
+ .config(routeConfig)
+ <%_ if(filters.auth) { _%>
+ .run(function($rootScope, $location, Auth) {
+ 'ngInject';
+ // Redirect to login if route requires auth and you're not logged in
+ $rootScope.$on('$stateChangeStart', function(event, next) {
+ Auth.isLoggedIn(function(loggedIn) {
+ if(next.authenticate && !loggedIn) {
+ $location.path('/login');
+ }
+ });
+ });
+ })<% } %>;
+
+angular
+ .element(document)
+ .ready(() => {
+ angular.bootstrap(document, ['<%= scriptAppName %>'], {
+ strictDi: true
+ });
});
diff --git a/templates/app/client/app/main/main.component.js b/templates/app/client/app/main/main.component.js
new file mode 100644
index 000000000..fab99e6a3
--- /dev/null
+++ b/templates/app/client/app/main/main.component.js
@@ -0,0 +1,52 @@
+import angular from 'angular';
+<%_ if(filters.ngroute) { _%>
+const ngRoute = require('angular-route');<% } _%>
+<%_ if(filters.uirouter) { _%>
+import uiRouter from 'angular-ui-router';<% } _%>
+
+import routing from './main.routes';
+
+export class MainController {
+ /*@ngInject*/
+ constructor($http<% if(filters.socketio) { %>, $scope, socket<% } %>) {
+ this.$http = $http;<% if (filters.socketio) { %>
+ this.socket = socket;<% } %>
+ this.awesomeThings = [];
+ <%_ if (filters.socketio) { _%>
+
+ $scope.$on('$destroy', function() {
+ socket.unsyncUpdates('thing');
+ });<% } %>
+ }
+
+ $onInit() {
+ this.$http.get('/api/things').then(response => {
+ this.awesomeThings = response.data;<% if (filters.socketio) { %>
+ this.socket.syncUpdates('thing', this.awesomeThings);<% } %>
+ });
+ }<% if (filters.models) { %>
+
+ addThing() {
+ if (this.newThing) {
+ this.$http.post('/api/things', { name: this.newThing });
+ this.newThing = '';
+ }
+ }
+
+ deleteThing(thing) {
+ this.$http.delete('/api/things/' + thing._id);
+ }<% } %>
+}
+
+export default angular.module('<%= scriptAppName %>.main', [
+ <%_ if(filters.ngroute) { _%>
+ ngRoute<% } _%>
+ <%_ if(filters.uirouter) { _%>
+ uiRouter<% } _%>
+])
+ .config(routing)
+ .component('main', {
+ template: require('./main.<%= templateExt %>'),
+ controller: MainController
+ })
+ .name;
diff --git a/templates/app/client/app/main/main.controller.spec.js b/templates/app/client/app/main/main.component.spec.js
similarity index 75%
rename from templates/app/client/app/main/main.controller.spec.js
rename to templates/app/client/app/main/main.component.spec.js
index 67982faa0..ac10b1c54 100644
--- a/templates/app/client/app/main/main.controller.spec.js
+++ b/templates/app/client/app/main/main.component.spec.js
@@ -1,11 +1,15 @@
'use strict';
-describe('Component: mainComponent', function() {
+import main from './main.component';
+import {MainController} from './main.component';
- // load the controller's module
- beforeEach(module('<%= scriptAppName %>'));<% if (filters.uirouter) {%>
- beforeEach(module('stateMock'));<% } %><% if (filters.socketio) {%>
- beforeEach(module('socketMock'));<% } %>
+describe('Component: MainComponent', function() {
+
+ beforeEach(angular.mock.module(main));
+ <%_ if (filters.uirouter) { _%>
+ beforeEach(angular.mock.module('stateMock'));<% } _%>
+ <%_ if (filters.socketio) { _%>
+ beforeEach(angular.mock.module('socketMock'));<% } %>
var scope;
var mainComponent;<% if (filters.uirouter) {%>
diff --git a/templates/app/client/app/main/main.controller.js b/templates/app/client/app/main/main.controller.js
deleted file mode 100644
index 02f408164..000000000
--- a/templates/app/client/app/main/main.controller.js
+++ /dev/null
@@ -1,42 +0,0 @@
-'use strict';
-
-(function() {
-
-class MainController {
-
- constructor($http<% if (filters.socketio) { %>, $scope, socket<% } %>) {
- this.$http = $http;<% if (filters.socketio) { %>
- this.socket = socket;<% } %>
- this.awesomeThings = [];<% if (filters.socketio) { %>
-
- $scope.$on('$destroy', function() {
- socket.unsyncUpdates('thing');
- });<% } %>
- }
-
- $onInit() {
- this.$http.get('/api/things').then(response => {
- this.awesomeThings = response.data;<% if (filters.socketio) { %>
- this.socket.syncUpdates('thing', this.awesomeThings);<% } %>
- });
- }<% if (filters.models) { %>
-
- addThing() {
- if (this.newThing) {
- this.$http.post('/api/things', { name: this.newThing });
- this.newThing = '';
- }
- }
-
- deleteThing(thing) {
- this.$http.delete('/api/things/' + thing._id);
- }<% } %>
-}
-
-angular.module('<%= scriptAppName %>')
- .component('main', {
- templateUrl: 'app/main/main.html',
- controller: MainController
- });
-
-})();
diff --git a/templates/app/client/app/main/main.js b/templates/app/client/app/main/main.js
deleted file mode 100644
index 9d5f59887..000000000
--- a/templates/app/client/app/main/main.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>')
- <% if (filters.ngroute) { %>.config(function($routeProvider) {
- $routeProvider
- .when('/', {
- template: ''
- });
- });<% } %><% if (filters.uirouter) { %>.config(function($stateProvider) {
- $stateProvider
- .state('main', {
- url: '/',
- template: ''
- });
- });<% } %>
diff --git a/templates/app/client/app/main/main.routes.js b/templates/app/client/app/main/main.routes.js
new file mode 100644
index 000000000..95c7968a9
--- /dev/null
+++ b/templates/app/client/app/main/main.routes.js
@@ -0,0 +1,19 @@
+'use strict';
+
+<%_ if(filters.ngroute) { _%>
+export default function routes($routeProvider) {
+ 'ngInject';
+ $routeProvider
+ .when('/', {
+ template: ''
+ });
+};<% } %>
+<%_ if(filters.uirouter) { _%>
+export default function routes($stateProvider) {
+ 'ngInject';
+ $stateProvider
+ .state('main', {
+ url: '/',
+ template: ''
+ });
+};<% } %>
diff --git a/templates/app/client/components/auth(auth)/auth.module.js b/templates/app/client/components/auth(auth)/auth.module.js
index 60ce6e321..a4f22d887 100644
--- a/templates/app/client/components/auth(auth)/auth.module.js
+++ b/templates/app/client/components/auth(auth)/auth.module.js
@@ -1,12 +1,32 @@
'use strict';
+import angular from 'angular';
+// import constants from '../../app/app.constant';
+import util from '../util/util.module';
+import ngCookies from 'angular-cookies';
+import {authInterceptor} from './interceptor.service';
+import {routerDecorator} from './router.decorator';
+import {AuthService} from './auth.service';
+import {UserResource} from './user.service';
+<%_ if (filters.ngroute) { _%>
+const ngRoute = require('angular-route');<% } %>
+<%_ if (filters.uirouter) { _%>
+import uiRouter from 'angular-ui-router';<% } %>
-angular.module('<%= scriptAppName %>.auth', [
+function addInterceptor($httpProvider) {
+ 'ngInject';
+ $httpProvider.interceptors.push('authInterceptor');
+}
+
+export default angular.module('<%= scriptAppName %>.auth', [
'<%= scriptAppName %>.constants',
- '<%= scriptAppName %>.util',
- 'ngCookies'<% if (filters.ngroute) { %>,
- 'ngRoute'<% } if (filters.uirouter) { %>,
- 'ui.router'<% } %>
+ util,
+ ngCookies<% if(filters.ngroute) { %>,
+ ngRoute<% } if(filters.uirouter) { %>,
+ uiRouter<% } %>
])
- .config(function($httpProvider) {
- $httpProvider.interceptors.push('authInterceptor');
- });
+ .factory('authInterceptor', authInterceptor)
+ .run(routerDecorator)
+ .factory('Auth', AuthService)
+ .factory('User', UserResource)
+ .config(['$httpProvider', addInterceptor])
+ .name;
diff --git a/templates/app/client/components/auth(auth)/auth.service.js b/templates/app/client/components/auth(auth)/auth.service.js
index 3a75c5a9a..08a91603a 100644
--- a/templates/app/client/components/auth(auth)/auth.service.js
+++ b/templates/app/client/components/auth(auth)/auth.service.js
@@ -1,8 +1,8 @@
'use strict';
+// @flow
-(function() {
-
-function AuthService($location, $http, $cookies, $q, appConfig, Util, User) {
+export function AuthService($location, $http, $cookies, $q, appConfig, Util, User) {
+ 'ngInject';
var safeCb = Util.safeCb;
var currentUser = {};
var userRoles = appConfig.userRoles || [];
@@ -182,8 +182,3 @@ function AuthService($location, $http, $cookies, $q, appConfig, Util, User) {
return Auth;
}
-
-angular.module('<%= scriptAppName %>.auth')
- .factory('Auth', AuthService);
-
-})();
diff --git a/templates/app/client/components/auth(auth)/interceptor.service.js b/templates/app/client/components/auth(auth)/interceptor.service.js
index 72c3441b0..e868b8924 100644
--- a/templates/app/client/components/auth(auth)/interceptor.service.js
+++ b/templates/app/client/components/auth(auth)/interceptor.service.js
@@ -1,10 +1,10 @@
'use strict';
-(function() {
-
-function authInterceptor($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>, Util) {
- <% if (filters.uirouter) { %>var state;
- <% } %>return {
+export function authInterceptor($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $injector<% } %>, Util) {
+ 'ngInject';
+ <%_ if (filters.uirouter) { _%>
+ var state;<% } %>
+ return {
// Add authorization token to headers
request(config) {
config.headers = config.headers || {};
@@ -17,7 +17,10 @@ function authInterceptor($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $
// Intercept 401s and redirect you to login
responseError(response) {
if (response.status === 401) {
- <% if (filters.ngroute) { %>$location.path('/login');<% } if (filters.uirouter) { %>(state || (state = $injector.get('$state'))).go('login');<% } %>
+ <%_ if (filters.ngroute) { _%>
+ $location.path('/login');<% } %>
+ <%_ if (filters.uirouter) { _%>
+ (state || (state = $injector.get('$state'))).go('login');<% } %>
// remove any stale tokens
$cookies.remove('token');
}
@@ -25,8 +28,3 @@ function authInterceptor($rootScope, $q, $cookies<% if (filters.ngroute) { %>, $
}
};
}
-
-angular.module('<%= scriptAppName %>.auth')
- .factory('authInterceptor', authInterceptor);
-
-})();
diff --git a/templates/app/client/components/auth(auth)/router.decorator.js b/templates/app/client/components/auth(auth)/router.decorator.js
index 752ad0720..5c135293b 100644
--- a/templates/app/client/components/auth(auth)/router.decorator.js
+++ b/templates/app/client/components/auth(auth)/router.decorator.js
@@ -1,39 +1,40 @@
'use strict';
+import * as _ from 'lodash';
-(function() {
+export function routerDecorator($rootScope<% if(filters.ngroute) { %>, $location<% } if(filters.uirouter) { %>, $state<% } %>, Auth) {
+ 'ngInject';
+ // Redirect to login if route requires auth and the user is not logged in, or doesn't have required role
+ $rootScope.$on(<% if(filters.ngroute) { %>'$routeChangeStart'<% } %><% if(filters.uirouter) { %>'$stateChangeStart'<% } %>, function(event, next) {
+ if(!next.authenticate) {
+ return;
+ }
-angular.module('<%= scriptAppName %>.auth')
- .run(function($rootScope<% if (filters.ngroute) { %>, $location<% } if (filters.uirouter) { %>, $state<% } %>, Auth) {
- // Redirect to login if route requires auth and the user is not logged in, or doesn't have required role
- $rootScope.$on(<% if (filters.ngroute) { %>'$routeChangeStart'<% } %><% if (filters.uirouter) { %>'$stateChangeStart'<% } %>, function(event, next) {
- if (!next.authenticate) {
- return;
- }
+ if(typeof next.authenticate === 'string') {
+ Auth.hasRole(next.authenticate, _.noop).then(has => {
+ if(has) {
+ return;
+ }
- if (typeof next.authenticate === 'string') {
- Auth.hasRole(next.authenticate, _.noop).then(has => {
- if (has) {
- return;
- }
-
- event.preventDefault();
- return Auth.isLoggedIn(_.noop).then(is => {<% if (filters.ngroute) { %>
- $location.path(is ? '/' : '/login');<% } if (filters.uirouter) { %>
- $state.go(is ? 'main' : 'login');<% } %>
- });
+ event.preventDefault();
+ return Auth.isLoggedIn(_.noop).then(is => {
+ <%_ if(filters.ngroute) { _%>
+ $location.path(is ? '/' : '/login');<% } %>
+ <%_ if(filters.uirouter) { _%>
+ $state.go(is ? 'main' : 'login');<% } %>
});
- } else {
- Auth.isLoggedIn(_.noop).then(is => {
- if (is) {
- return;
- }
+ });
+ } else {
+ Auth.isLoggedIn(_.noop).then(is => {
+ if(is) {
+ return;
+ }
- event.preventDefault();<% if (filters.ngroute) { %>
- $location.path('/login');<% } if (filters.uirouter) { %>
- $state.go('login');<% } %>
- });
- }
- });
+ event.preventDefault();
+ <%_ if(filters.ngroute) { _%>
+ $location.path('/login');<% } %>
+ <%_ if(filters.uirouter) { _%>
+ $state.go('login');<% } %>
+ });
+ }
});
-
-})();
+};
diff --git a/templates/app/client/components/auth(auth)/user.service.js b/templates/app/client/components/auth(auth)/user.service.js
index 63f4040d0..a458a89a2 100644
--- a/templates/app/client/components/auth(auth)/user.service.js
+++ b/templates/app/client/components/auth(auth)/user.service.js
@@ -1,8 +1,7 @@
'use strict';
-(function() {
-
-function UserResource($resource) {
+export function UserResource($resource) {
+ 'ngInject';
return $resource('/api/users/:id/:controller', {
id: '@_id'
}, {
@@ -20,8 +19,3 @@ function UserResource($resource) {
}
});
}
-
-angular.module('<%= scriptAppName %>.auth')
- .factory('User', UserResource);
-
-})();
diff --git a/templates/app/client/components/footer/footer.component.js b/templates/app/client/components/footer/footer.component.js
new file mode 100644
index 000000000..88b9312a7
--- /dev/null
+++ b/templates/app/client/components/footer/footer.component.js
@@ -0,0 +1,10 @@
+import angular from 'angular';
+
+export class FooterComponent {}
+
+export default angular.module('directives.footer', [])
+ .component('footer', {
+ template: require('./footer.<%= templateExt %>'),
+ controller: FooterComponent
+ })
+ .name;
diff --git a/templates/app/client/components/footer/footer.directive.js b/templates/app/client/components/footer/footer.directive.js
deleted file mode 100644
index 9ed31900c..000000000
--- a/templates/app/client/components/footer/footer.directive.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>')
- .directive('footer', function() {
- return {
- templateUrl: 'components/footer/footer.html',
- restrict: 'E',
- link: function(scope, element) {
- element.addClass('footer');
- }
- };
- });
diff --git a/templates/app/client/components/modal(uibootstrap)/modal.service.js b/templates/app/client/components/modal(uibootstrap)/modal.service.js
index d7807e6b5..91d94894c 100644
--- a/templates/app/client/components/modal(uibootstrap)/modal.service.js
+++ b/templates/app/client/components/modal(uibootstrap)/modal.service.js
@@ -1,73 +1,76 @@
'use strict';
-angular.module('<%= scriptAppName %>')
- .factory('Modal', function($rootScope, $uibModal) {
- /**
- * Opens a modal
- * @param {Object} scope - an object to be merged with modal's scope
- * @param {String} modalClass - (optional) class(es) to be applied to the modal
- * @return {Object} - the instance $uibModal.open() returns
- */
- function openModal(scope = {}, modalClass = 'modal-default') {
- var modalScope = $rootScope.$new();
+export function Modal($rootScope, $uibModal) {
+ /**
+ * Opens a modal
+ * @param {Object} scope - an object to be merged with modal's scope
+ * @param {String} modalClass - (optional) class(es) to be applied to the modal
+ * @return {Object} - the instance $uibModal.open() returns
+ */
+ function openModal(scope = {}, modalClass = 'modal-default') {
+ var modalScope = $rootScope.$new();
- angular.extend(modalScope, scope);
+ angular.extend(modalScope, scope);
- return $uibModal.open({
- templateUrl: 'components/modal/modal.html',
- windowClass: modalClass,
- scope: modalScope
- });
- }
+ return $uibModal.open({
+ template: require('./modal.<%= templateExt %>'),
+ windowClass: modalClass,
+ scope: modalScope
+ });
+ }
- // Public API here
- return {
+ // Public API here
+ return {
- /* Confirmation modals */
- confirm: {
+ /* Confirmation modals */
+ confirm: {
+ /**
+ * Create a function to open a delete confirmation modal (ex. ng-click='myModalFn(name, arg1, arg2...)')
+ * @param {Function} del - callback, ran when delete is confirmed
+ * @return {Function} - the function to open the modal (ex. myModalFn)
+ */
+ delete(del = angular.noop) {
/**
- * Create a function to open a delete confirmation modal (ex. ng-click='myModalFn(name, arg1, arg2...)')
- * @param {Function} del - callback, ran when delete is confirmed
- * @return {Function} - the function to open the modal (ex. myModalFn)
+ * Open a delete confirmation modal
+ * @param {String} name - name or info to show on modal
+ * @param {All} - any additional args are passed straight to del callback
*/
- delete(del = angular.noop) {
- /**
- * Open a delete confirmation modal
- * @param {String} name - name or info to show on modal
- * @param {All} - any additional args are passed straight to del callback
- */
- return function() {
- var args = Array.prototype.slice.call(arguments),
- name = args.shift(),
- deleteModal;
+ return function() {
+ var args = Array.prototype.slice.call(arguments),
+ name = args.shift(),
+ deleteModal;
- deleteModal = openModal({
- modal: {
- dismissable: true,
- title: 'Confirm Delete',
- html: 'Are you sure you want to delete ' + name + ' ?
',
- buttons: [{
- classes: 'btn-danger',
- text: 'Delete',
- click: function(e) {
- deleteModal.close(e);
- }
- }, {
- classes: 'btn-default',
- text: 'Cancel',
- click: function(e) {
- deleteModal.dismiss(e);
- }
- }]
- }
- }, 'modal-danger');
+ deleteModal = openModal({
+ modal: {
+ dismissable: true,
+ title: 'Confirm Delete',
+ html: 'Are you sure you want to delete ' + name + ' ?
',
+ buttons: [{
+ classes: 'btn-danger',
+ text: 'Delete',
+ click: function(e) {
+ deleteModal.close(e);
+ }
+ }, {
+ classes: 'btn-default',
+ text: 'Cancel',
+ click: function(e) {
+ deleteModal.dismiss(e);
+ }
+ }]
+ }
+ }, 'modal-danger');
- deleteModal.result.then(function(event) {
- del.apply(event, args);
- });
- };
- }
+ deleteModal.result.then(function(event) {
+ del.apply(event, args);
+ });
+ };
}
- };
- });
+ }
+ };
+}
+
+export default angular.module('<%= scriptAppName %>')
+ .factory('Modal', Modal)
+ .name;
diff --git a/templates/app/client/components/navbar/navbar(html).html b/templates/app/client/components/navbar/navbar(html).html
index 4b6692d36..79d7b5a78 100644
--- a/templates/app/client/components/navbar/navbar(html).html
+++ b/templates/app/client/components/navbar/navbar(html).html
@@ -1,7 +1,7 @@
-
+
-
+
<% if (filters.auth) { %>
<% } %>
diff --git a/templates/app/client/components/navbar/navbar(jade).jade b/templates/app/client/components/navbar/navbar(jade).jade
index d8a86b647..cd32fb74f 100644
--- a/templates/app/client/components/navbar/navbar(jade).jade
+++ b/templates/app/client/components/navbar/navbar(jade).jade
@@ -1,34 +1,34 @@
-div.navbar.navbar-default.navbar-static-top(ng-controller='NavbarController')
+div.navbar.navbar-default.navbar-static-top
div.container
div.navbar-header
- button.navbar-toggle(type='button', ng-click='nav.isCollapsed = !nav.isCollapsed')
+ button.navbar-toggle(type='button', ng-click='$ctrl.isCollapsed = !$ctrl.isCollapsed')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href='/') <%= lodash.slugify(lodash.humanize(appname)) %>
- div#navbar-main.navbar-collapse.collapse(uib-collapse='nav.isCollapsed')
+ div#navbar-main.navbar-collapse.collapse(uib-collapse='$ctrl.isCollapsed')
ul.nav.navbar-nav
- li(ng-repeat='item in nav.menu', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: nav.isActive(item.link)}'<% } %>)
+ li(ng-repeat='item in $ctrl.menu', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: $ctrl.isActive(item.link)}'<% } %>)
a(<% if (filters.uirouter) { %>ui-sref='{{item.state}}'<% } else { %>ng-href='{{item.link}}'<% } %>) {{item.title}}<% if (filters.auth) { %>
- li(ng-show='nav.isAdmin()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: nav.isActive("/admin")}'<% } %>)
+ li(ng-show='$ctrl.isAdmin()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: $ctrl.isActive("/admin")}'<% } %>)
a(<% if (filters.uirouter) { %>ui-sref='admin'<% } else { %>href='/admin'<% } %>) Admin
ul.nav.navbar-nav.navbar-right
- li(ng-hide='nav.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: nav.isActive("/signup")}'<% } %>)
+ li(ng-hide='$ctrl.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: $ctrl.isActive("/signup")}'<% } %>)
a(<% if (filters.uirouter) { %>ui-sref='signup'<% } else { %>href='/signup'<% } %>) Sign up
- li(ng-hide='nav.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: nav.isActive("/login")}'<% } %>)
+ li(ng-hide='$ctrl.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: $ctrl.isActive("/login")}'<% } %>)
a(<% if (filters.uirouter) { %>ui-sref='login'<% } else { %>href='/login'<% } %>) Login
- li(ng-show='nav.isLoggedIn()')
- p.navbar-text Hello {{ nav.getCurrentUser().name }}
+ li(ng-show='$ctrl.isLoggedIn()')
+ p.navbar-text Hello {{ $ctrl.getCurrentUser().name }}
- li(ng-show='nav.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: nav.isActive("/settings")}'<% } %>)
+ li(ng-show='$ctrl.isLoggedIn()', <% if (filters.uirouter) { %>ui-sref-active='active'<% } else { %>ng-class='{active: $ctrl.isActive("/settings")}'<% } %>)
a(<% if (filters.uirouter) { %>ui-sref='settings'<% } else { %>href='/settings'<% } %>)
span.glyphicon.glyphicon-cog
- li(ng-show='nav.isLoggedIn()')
+ li(ng-show='$ctrl.isLoggedIn()')
a(<% if (filters.uirouter) { %>ui-sref='logout'<% } else { %>href='/logout'<% } %>) Logout<% } %>
diff --git a/templates/app/client/components/navbar/navbar.controller.js b/templates/app/client/components/navbar/navbar.component.js
similarity index 76%
rename from templates/app/client/components/navbar/navbar.controller.js
rename to templates/app/client/components/navbar/navbar.component.js
index 12ae0b351..d46af76b3 100644
--- a/templates/app/client/components/navbar/navbar.controller.js
+++ b/templates/app/client/components/navbar/navbar.component.js
@@ -1,17 +1,18 @@
'use strict';
-class NavbarController {
+export class NavbarComponent {
//start-non-standard
menu = [{
'title': 'Home',
<% if (filters.uirouter) { %>'state': 'main'<% } else { %>'link': '/'<% } %>
}];
-
+
isCollapsed = true;
//end-non-standard
<%_ if(filters.ngroute || filters.auth) { _%>
constructor(<% if(!filters.uirouter) { %>$location<% } if(!filters.uirouter && filters.auth) { %>, <% } if (filters.auth) { %>Auth<% } %>) {
+ 'ngInject';
<%_ if(!filters.uirouter) { _%>
this.$location = $location;
<%_ } _%>
@@ -28,5 +29,9 @@ class NavbarController {
}<% } %>
}
-angular.module('<%= scriptAppName %>')
- .controller('NavbarController', NavbarController);
+export default angular.module('directives.navbar', [])
+ .component('navbar', {
+ template: require('./navbar.<%= templateExt %>'),
+ controller: NavbarComponent
+ })
+ .name;
diff --git a/templates/app/client/components/navbar/navbar.directive.js b/templates/app/client/components/navbar/navbar.directive.js
deleted file mode 100644
index 3ae1a4a57..000000000
--- a/templates/app/client/components/navbar/navbar.directive.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>')
- .directive('navbar', () => ({
- templateUrl: 'components/navbar/navbar.html',
- restrict: 'E',
- controller: 'NavbarController',
- controllerAs: 'nav'
- }));
diff --git a/templates/app/client/components/oauth-buttons(oauth)/index.js b/templates/app/client/components/oauth-buttons(oauth)/index.js
new file mode 100644
index 000000000..8ce33c85e
--- /dev/null
+++ b/templates/app/client/components/oauth-buttons(oauth)/index.js
@@ -0,0 +1,21 @@
+'use strict';
+
+export function OauthButtonsController($window) {
+ this.loginOauth = function(provider) {
+ $window.location.href = '/auth/' + provider;
+ };
+}
+
+export default angular.module('<%= scriptAppName %>.oauthButtons', [])
+ .directive('oauthButtons', function() {
+ return {
+ template: require('./oauth-buttons.<%= templateExt %>'),
+ restrict: 'EA',
+ controller: OauthButtonsController,
+ controllerAs: 'OauthButtons',
+ scope: {
+ classes: '@'
+ }
+ };
+ })
+ .name;
diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.js b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.js
deleted file mode 100644
index 36d5d6467..000000000
--- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>')
- .controller('OauthButtonsCtrl', function($window) {
- this.loginOauth = function(provider) {
- $window.location.href = '/auth/' + provider;
- };
- });
diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.spec.js b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.spec.js
index 144745e5e..721792277 100644
--- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.spec.js
+++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.controller.spec.js
@@ -1,11 +1,17 @@
'use strict';
-describe('Controller: OauthButtonsCtrl', function() {
+import {OauthButtonsController} from './index';
- // load the controller's module
- beforeEach(module('<%= scriptAppName %>'));
+describe('Controller: OauthButtonsController', function() {
+
+ var controller, $window;
- var OauthButtonsCtrl, $window;
+ beforeEach(() => {
+ angular.module('test', [])
+ .controller('OauthButtonsController', OauthButtonsController);
+ });
+ // load the controller's module
+ beforeEach(angular.mock.module('test'));
// Initialize the controller and a mock $window
beforeEach(inject(function($controller) {
@@ -13,13 +19,13 @@ describe('Controller: OauthButtonsCtrl', function() {
location: {}
};
- OauthButtonsCtrl = $controller('OauthButtonsCtrl', {
+ controller = $controller('OauthButtonsController', {
$window: $window
});
}));
it('should attach loginOauth', function() {<% if (filters.jasmine) { %>
- expect(OauthButtonsCtrl.loginOauth).toEqual(jasmine.any(Function));<% } if (filters.mocha) { %>
- <%= expect() %>OauthButtonsCtrl.loginOauth<%= to() %>.be.a('function');<% } %>
+ expect(controller.loginOauth).toEqual(jasmine.any(Function));<% } if (filters.mocha) { %>
+ <%= expect() %>controller.loginOauth<%= to() %>.be.a('function');<% } %>
});
});
diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.js b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.js
deleted file mode 100644
index 401f669e3..000000000
--- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-
-angular.module('<%= scriptAppName %>')
- .directive('oauthButtons', function() {
- return {
- templateUrl: 'components/oauth-buttons/oauth-buttons.html',
- restrict: 'EA',
- controller: 'OauthButtonsCtrl',
- controllerAs: 'OauthButtons',
- scope: {
- classes: '@'
- }
- };
- });
diff --git a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.spec.js b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.spec.js
index 14682cc6e..4728acc89 100644
--- a/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.spec.js
+++ b/templates/app/client/components/oauth-buttons(oauth)/oauth-buttons.directive.spec.js
@@ -1,10 +1,12 @@
'use strict';
+const $ = require('sprint-js');
+import OauthButtons from './index';
describe('Directive: oauthButtons', function() {
// load the directive's module and view
- beforeEach(module('<%= scriptAppName %>'));
- beforeEach(module('components/oauth-buttons/oauth-buttons.html'));
+ beforeEach(angular.mock.module(OauthButtons));
+ // beforeEach(angular.mock.module('components/oauth-buttons/oauth-buttons.html'));
var element, parentScope, elementScope;
@@ -23,8 +25,8 @@ describe('Directive: oauthButtons', function() {
it('should contain anchor buttons', function() {
compileDirective('
');<% if (filters.jasmine) { %>
- expect(element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>').length).toBeGreaterThan(0);<% } if (filters.mocha) { %>
- <%= expect() %>element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>').length<%= to() %>.be.at.least(1);<% } %>
+ expect($(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>').length).toBeGreaterThan(0);<% } if (filters.mocha) { %>
+ <%= expect() %>$(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>').length<%= to() %>.be.at.least(1);<% } %>
});
it('should evaluate and bind the classes attribute to scope.classes', function() {
@@ -39,13 +41,13 @@ describe('Directive: oauthButtons', function() {
// Add classes
elementScope.classes = 'testClass1 testClass2';
elementScope.$digest();<% if (filters.jasmine) { %>
- expect(element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length).toBeGreaterThan(0);<% } if (filters.mocha) { %>
- <%= expect() %>element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length<%= to() %>.be.at.least(1);<% } %>
+ expect($(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length).toBeGreaterThan(0);<% } if (filters.mocha) { %>
+ <%= expect() %>$(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length<%= to() %>.be.at.least(1);<% } %>
// Remove classes
elementScope.classes = '';
elementScope.$digest();<% if (filters.jasmine) { %>
- expect(element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length).toEqual(0);<% } if (filters.mocha) { %>
- <%= expect() %>element.find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length<%= to() %>.equal(0);<% } %>
+ expect($(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length).toEqual(0);<% } if (filters.mocha) { %>
+ <%= expect() %>$(element[0]).find('a.btn<% if (filters.bootstrap) { %>.btn-social<% } %>.testClass1.testClass2').length<%= to() %>.equal(0);<% } %>
});
});
diff --git a/templates/app/client/components/socket(socketio)/socket.mock.js b/templates/app/client/components/socket(socketio)/socket.mock.js
index ba09c1d35..fdf9e5a57 100644
--- a/templates/app/client/components/socket(socketio)/socket.mock.js
+++ b/templates/app/client/components/socket(socketio)/socket.mock.js
@@ -1,4 +1,5 @@
'use strict';
+const angular = require('angular');
angular.module('socketMock', [])
.factory('socket', function() {
diff --git a/templates/app/client/components/socket(socketio)/socket.service.js b/templates/app/client/components/socket(socketio)/socket.service.js
index 97e5dfee6..bcaa55b18 100644
--- a/templates/app/client/components/socket(socketio)/socket.service.js
+++ b/templates/app/client/components/socket(socketio)/socket.service.js
@@ -1,8 +1,8 @@
-/* global io */
'use strict';
-angular.module('<%= scriptAppName %>')
- .factory('socket', function(socketFactory) {
+import io from 'socket.io-client';
+
+function Socket(socketFactory) {
// socket.io now auto-configures its connection when we ommit a connection url
var ioSocket = io('', {
// Send auth token on connection, you will need to DI the Auth service above
@@ -68,4 +68,8 @@ angular.module('<%= scriptAppName %>')
socket.removeAllListeners(modelName + ':remove');
}
};
- });
+ }
+
+export default angular.module('<%= scriptAppName %>.socket', [])
+ .factory('socket', Socket)
+ .name;
diff --git a/templates/app/client/components/ui-router(uirouter)/ui-router.mock.js b/templates/app/client/components/ui-router(uirouter)/ui-router.mock.js
index a5a1bf413..35b8d030b 100644
--- a/templates/app/client/components/ui-router(uirouter)/ui-router.mock.js
+++ b/templates/app/client/components/ui-router(uirouter)/ui-router.mock.js
@@ -1,4 +1,5 @@
'use strict';
+const angular = require('angular');
angular.module('stateMock', []);
angular.module('stateMock').service('$state', function($q) {
diff --git a/templates/app/client/components/util/util.module.js b/templates/app/client/components/util/util.module.js
index 690b12456..3e93a69b9 100644
--- a/templates/app/client/components/util/util.module.js
+++ b/templates/app/client/components/util/util.module.js
@@ -1,3 +1,6 @@
'use strict';
+import {UtilService} from './util.service';
-angular.module('<%= scriptAppName %>.util', []);
+export default angular.module('<%= scriptAppName %>.util', [])
+ .factory('Util', UtilService)
+ .name;
diff --git a/templates/app/client/components/util/util.service.js b/templates/app/client/components/util/util.service.js
index 4ce50a841..39b108988 100644
--- a/templates/app/client/components/util/util.service.js
+++ b/templates/app/client/components/util/util.service.js
@@ -1,11 +1,10 @@
'use strict';
-(function() {
-
/**
* The Util service is for thin, globally reusable, utility functions
*/
-function UtilService($window) {
+export function UtilService($window) {
+ 'ngInject';
var Util = {
/**
* Return a callback or noop function
@@ -50,7 +49,7 @@ function UtilService($window) {
origins = origins.filter(function(o) {
let hostnameCheck = url.hostname === o.hostname;
let protocolCheck = url.protocol === o.protocol;
- // 2nd part of the special treatment for IE fix (see above):
+ // 2nd part of the special treatment for IE fix (see above):
// This part is when using well-known ports 80 or 443 with IE,
// when $window.location.port==='' instead of the real port number.
// Probably the same cause as this IE bug: https://goo.gl/J9hRta
@@ -63,8 +62,3 @@ function UtilService($window) {
return Util;
}
-
-angular.module('<%= scriptAppName %>.util')
- .factory('Util', UtilService);
-
-})();
diff --git a/templates/app/client/index.html b/templates/app/client/index.html
deleted file mode 100644
index 807f85068..000000000
--- a/templates/app/client/index.html
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- <% if (filters.ngroute) { %>
<% } %><% if (filters.uirouter) { %>
<% } %>
-
-
-
-
-
-
-
-
- <% if (filters.socketio) { %>
- <% } %>
-
-
-
-
-
-
-
-
diff --git a/templates/app/client/polyfills.js b/templates/app/client/polyfills.js
new file mode 100644
index 000000000..92650a052
--- /dev/null
+++ b/templates/app/client/polyfills.js
@@ -0,0 +1,36 @@
+// Polyfills
+// (these modules are what are in 'angular2/bundles/angular2-polyfills' so don't use that here)
+
+// import 'ie-shim'; // Internet Explorer
+// import 'es6-shim';
+// import 'es6-promise';
+// import 'es7-reflect-metadata';
+
+// Prefer CoreJS over the polyfills above
+import 'core-js/es6';
+import 'core-js/es7/reflect';
+// require('zone.js/dist/zone');
+
+<%_ if(filters.ts) { _%>
+// Typescript emit helpers polyfill
+import 'ts-helpers';
+
+interface IPolyFillErrorConstructor extends ErrorConstructor {
+ stackTraceLimit: any;
+}<% } %>
+
+if(!ENV) {
+ var ENV = 'development';
+}
+
+if(ENV === 'production') {
+ // Production
+} else {
+ // Development
+
+ <%_ if(filters.ts) { _%>
+ (
Error).stackTraceLimit = Infinity;<% } else { %>
+ Error.stackTraceLimit = Infinity;
+ <% } %>
+ // require('zone.js/dist/long-stack-trace-zone');
+}
\ No newline at end of file
diff --git a/templates/app/e2e/account(auth)/login/login.spec(jasmine).js b/templates/app/e2e/account(auth)/login/login.spec(jasmine).js
index 03ea404df..780ed57d0 100644
--- a/templates/app/e2e/account(auth)/login/login.spec(jasmine).js
+++ b/templates/app/e2e/account(auth)/login/login.spec(jasmine).js
@@ -56,12 +56,18 @@ describe('Login View', function() {
describe('with local auth', function() {
it('should login a user and redirecting to "/"', function() {
- page.login(testUser);
-
- var navbar = require('../../components/navbar/navbar.po');
-
- expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');
- expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name);
+ return page.login(testUser).then(() => {
+ var navbar = require('../../components/navbar/navbar.po');
+
+ return browser.wait(
+ () => element(by.css('.hero-unit')),
+ 5000,
+ `Didn't find .hero-unit after 5s`
+ ).then(() => {
+ expect(browser.getCurrentUrl()).toBe(config.baseUrl + '/');
+ expect(navbar.navbarAccountGreeting.getText()).toBe('Hello ' + testUser.name);
+ });
+ });
});
it('should indicate login failures', function() {
diff --git a/templates/app/e2e/account(auth)/login/login.spec(mocha).js b/templates/app/e2e/account(auth)/login/login.spec(mocha).js
index 08758dc07..fd11f4131 100644
--- a/templates/app/e2e/account(auth)/login/login.spec(mocha).js
+++ b/templates/app/e2e/account(auth)/login/login.spec(mocha).js
@@ -56,12 +56,18 @@ describe('Login View', function() {
describe('with local auth', function() {
it('should login a user and redirecting to "/"', function() {
- page.login(testUser);
-
- var navbar = require('../../components/navbar/navbar.po');
-
- <%= expect() %>browser.getCurrentUrl()<%= to() %>.eventually.equal(config.baseUrl + '/');
- <%= expect() %>navbar.navbarAccountGreeting.getText()<%= to() %>.eventually.equal('Hello ' + testUser.name);
+ return page.login(testUser).then(() => {
+ var navbar = require('../../components/navbar/navbar.po');
+
+ return browser.wait(
+ () => element(by.css('.hero-unit')),
+ 5000,
+ `Didn't find .hero-unit after 5s`
+ ).then(() => {
+ <%= expect() %>browser.getCurrentUrl()<%= to() %>.eventually.equal(config.baseUrl + '/');
+ <%= expect() %>navbar.navbarAccountGreeting.getText()<%= to() %>.eventually.equal('Hello ' + testUser.name);
+ });
+ });
});
describe('and invalid credentials', function() {
diff --git a/templates/app/gulpfile.babel(gulp).js b/templates/app/gulpfile.babel(gulp).js
index 16582400f..0cc25c44c 100644
--- a/templates/app/gulpfile.babel(gulp).js
+++ b/templates/app/gulpfile.babel(gulp).js
@@ -6,22 +6,28 @@ import del from 'del';
import gulp from 'gulp';
import grunt from 'grunt';
import path from 'path';
+import through2 from 'through2';
import gulpLoadPlugins from 'gulp-load-plugins';
import http from 'http';
import open from 'open';
import lazypipe from 'lazypipe';
-import {stream as wiredep} from 'wiredep';
import nodemon from 'nodemon';
import {Server as KarmaServer} from 'karma';
import runSequence from 'run-sequence';
import {protractor, webdriver_update} from 'gulp-protractor';
import {Instrumenter} from 'isparta';<% if(filters.stylus) { %>
import nib from 'nib';<% } %>
+import webpack from 'webpack-stream';
+import makeWebpackConfig from './webpack.make';
var plugins = gulpLoadPlugins();
var config;
+const webpackDevConfig = makeWebpackConfig({ DEV: true });
+const webpackE2eConfig = makeWebpackConfig({ E2E: true });
+const webpackDistConfig = makeWebpackConfig({ BUILD: true });
+const webpackTestConfig = makeWebpackConfig({ TEST: true });
-const clientPath = require('./bower.json').appPath || 'client';
+const clientPath = 'client';
const serverPath = 'server';
const paths = {
client: {
@@ -91,25 +97,6 @@ function whenServerReady(cb) {
100);
}
-function sortModulesFirst(a, b) {
- var module = /\.module\.<%= scriptExt %>$/;
- 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
********************/
@@ -118,7 +105,7 @@ let lintClientScripts = lazypipe()<% if(filters.babel) { %>
.pipe(plugins.jshint, `${clientPath}/.jshintrc`)
.pipe(plugins.jshint.reporter, 'jshint-stylish');<% } %><% if(filters.ts) { %>
.pipe(plugins.tslint, require(`./${clientPath}/tslint.json`))
- .pipe(plugins.tslint.report, 'verbose');<% } %>
+ .pipe(plugins.tslint.report, 'verbose', {emitError: false});<% } %>
let lintServerScripts = lazypipe()
.pipe(plugins.jshint, `${serverPath}/.jshintrc`)
@@ -128,24 +115,6 @@ let lintServerTestScripts = lazypipe()
.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, {
- use: [nib()],
- errors: true
- })<% } if(filters.sass) { %>
- .pipe(plugins.sass)<% } if(filters.less) { %>
- .pipe(plugins.less)<% } %>
- <%_ if(filters.css) { _%>
- .pipe(plugins.cleanCss, {processImportFrom: ['!fonts.googleapis.com']})<% } %>
- .pipe(plugins.autoprefixer, {browsers: ['last 1 version']})
- .pipe(plugins.sourcemaps.write, '.');<% if(filters.babel) { %>
-
-let transpileClient = lazypipe()
- .pipe(plugins.sourcemaps.init)
- .pipe(plugins.babel)
- .pipe(plugins.sourcemaps.write, '.');<% } %>
-
let transpileServer = lazypipe()
.pipe(plugins.sourcemaps.init)
.pipe(plugins.babel, {
@@ -211,20 +180,7 @@ gulp.task('env:prod', () => {
********************/
gulp.task('inject', cb => {
- runSequence(['inject:js', 'inject:css'<% if(!filters.css) { %>, 'inject:<%= styleExt %>'<% } %><% if(filters.ts) { %>, 'inject:tsconfig'<% } %>], cb);
-});
-
-gulp.task('inject:js', () => {
- return gulp.src(paths.client.mainView)
- .pipe(plugins.inject(
- gulp.src(_.union(paths.client.scripts, [<% if(filters.ts) { %>'client/app/app.constant.js', <% } %>`!${clientPath}/**/*.{spec,mock}.<%= scriptExt %>`, `!${clientPath}/app/app.<%= scriptExt %>`]), {read: false})
- .pipe(plugins.sort(sortModulesFirst)),
- {
- starttag: '',
- endtag: '',
- transform: (filepath) => ''
- }))
- .pipe(gulp.dest(clientPath));
+ runSequence(['inject:css'<% if(!filters.css) { %>, 'inject:<%= styleExt %>'<% } %><% if(filters.ts) { %>, 'inject:tsconfig'<% } %>], cb);
});<% if(filters.ts) { %>
function injectTsConfig(filesGlob, tsconfigPath){
@@ -247,7 +203,7 @@ gulp.task('inject:tsconfig', () => {
`${clientPath}/**/!(*.spec|*.mock).ts`,
`!${clientPath}/bower_components/**/*`,
`typings/main.d.ts`
- ],
+ ],
'./tsconfig.client.json');
});
@@ -256,7 +212,7 @@ gulp.task('inject:tsconfigTest', () => {
`${clientPath}/**/+(*.spec|*.mock).ts`,
`!${clientPath}/bower_components/**/*`,
`typings/main.d.ts`
- ],
+ ],
'./tsconfig.client.test.json');
});<% } %>
@@ -293,7 +249,33 @@ gulp.task('inject:<%= styleExt %>', () => {
}
}))
.pipe(gulp.dest(`${clientPath}/app`));
-});<% } %><% if(filters.ts) { %>
+});<% } %>
+
+gulp.task('webpack:dev', function() {
+ return gulp.src(webpackDevConfig.entry.app)
+ .pipe(plugins.plumber())
+ .pipe(webpack(webpackDevConfig))
+ .pipe(gulp.dest('.tmp'))
+ .pipe(plugins.livereload());
+});
+
+gulp.task('webpack:dist', function() {
+ return gulp.src(webpackDistConfig.entry.app)
+ .pipe(webpack(webpackDistConfig))
+ .pipe(gulp.dest(`${paths.dist}/client`));
+});
+
+gulp.task('webpack:test', function() {
+ return gulp.src(webpackTestConfig.entry.app)
+ .pipe(webpack(webpackTestConfig))
+ .pipe(gulp.dest('.tmp'));
+});
+
+gulp.task('webpack:e2e', function() {
+ return gulp.src(webpackE2eConfig.entry.app)
+ .pipe(webpack(webpackE2eConfig))
+ .pipe(gulp.dest('.tmp'));
+});<% if(filters.ts) { %>
// Install DefinitelyTyped TypeScript definition files
gulp.task('typings', () => {
@@ -314,28 +296,6 @@ gulp.task('styles', () => {
gulp.task('copy:constant', ['constant'], () => {
return gulp.src(`${clientPath}/app/app.constant.js`, { dot: true })
.pipe(gulp.dest('.tmp/app'));
-})
-
-gulp.task('transpile:client', ['typings', 'copy:constant'], () => {
- return gulp.src(['client/{app,components}/**/!(*.spec|*.mock).ts', 'typings/main.d.ts'])
- .pipe(plugins.sourcemaps.init())
- .pipe(plugins.typescript()).js
- .pipe(plugins.sourcemaps.write('.'))
- .pipe(gulp.dest('.tmp'));
-});
-
-gulp.task('transpile:client:test', ['typings'], () => {
- return gulp.src(['client/{app,components}/**/+(*.spec|*.mock).ts', 'typings/main.d.ts'])
- .pipe(plugins.sourcemaps.init())
- .pipe(plugins.typescript()).js
- .pipe(plugins.sourcemaps.write('.'))
- .pipe(gulp.dest('.tmp/test'));
-});<% } %><% if(filters.babel) { %>
-
-gulp.task('transpile:client', () => {
- return gulp.src(paths.client.scripts)
- .pipe(transpileClient())
- .pipe(gulp.dest('.tmp'));
});<% } %>
gulp.task('transpile:server', () => {
@@ -416,44 +376,51 @@ gulp.task('watch', () => {
plugins.livereload.listen();
- plugins.watch(paths.client.styles, () => { //['inject:<%= styleExt %>']
- gulp.src(paths.client.mainStyle)
- .pipe(plugins.plumber())
- .pipe(styles())
- .pipe(gulp.dest('.tmp/app'))
- .pipe(plugins.livereload());
- });
-
- plugins.watch(paths.client.views)<% if(filters.jade) { %>
- .pipe(plugins.jade())
- .pipe(gulp.dest('.tmp'))<% } %>
- .pipe(plugins.plumber())
- .pipe(plugins.livereload());<% if(filters.babel) { %>
-
- plugins.watch(paths.client.scripts) //['inject:js']
- .pipe(plugins.plumber())
- .pipe(transpileClient())
- .pipe(gulp.dest('.tmp'))
- .pipe(plugins.livereload());<% } %><% if(filters.ts) { %>
-
- gulp.watch(paths.client.scripts, ['lint:scripts:client', 'transpile:client']);<% } %>
-
plugins.watch(_.union(paths.server.scripts, testFiles))
.pipe(plugins.plumber())
.pipe(lintServerScripts())
.pipe(plugins.livereload());
- gulp.watch('bower.json', ['wiredep:client']);
+ plugins.watch(_.union(paths.server.test.unit, paths.server.test.integration))
+ .pipe(plugins.plumber())
+ .pipe(lintServerTestScripts());
});
gulp.task('serve', cb => {
- runSequence(['clean:tmp', 'constant', 'env:all'<% if(filters.ts) { %>, 'typings'<% } %>],
- ['lint:scripts', 'inject'<% if(filters.jade) { %>, 'jade'<% } %>],
- ['wiredep:client'],
- ['transpile:client', 'styles'],
+ runSequence(
+ [
+ 'clean:tmp',
+ 'lint:scripts',
+ 'constant',
+ 'inject',
+ 'copy:fonts:dev',
+ 'env:all'<% if(filters.ts) { %>,
+ 'typings'<% } %>
+ ],
+ // 'webpack:dev',
['start:server', 'start:client'],
'watch',
- cb);
+ cb
+ );
+});
+
+gulp.task('serve:debug', cb => {
+ runSequence(
+ [
+ 'clean:tmp',
+ 'lint:scripts',
+ 'constant',
+ 'inject',
+ 'copy:fonts:dev',
+ 'env:all'<% if(filters.ts) { %>,
+ 'typings'<% } %>
+ ],
+ 'webpack:dev',
+ 'start:inspector',
+ ['start:server:debug', 'start:client'],
+ 'watch',
+ cb
+ );
});
gulp.task('serve:dist', cb => {
@@ -465,17 +432,6 @@ gulp.task('serve:dist', cb => {
cb);
});
-gulp.task('serve:debug', cb => {
- runSequence(['clean:tmp', 'constant'<% if(filters.ts) { %>, 'typings'<% } %>],
- ['lint:scripts', 'inject'<% if(filters.jade) { %>, 'jade'<% } %>],
- ['wiredep:client'],
- ['transpile:client', 'styles'],
- 'start:inspector',
- ['start:server:debug', 'start:client'],
- 'watch',
- cb);
-});
-
gulp.task('test', cb => {
return runSequence('test:server', 'test:client', cb);
});
@@ -486,7 +442,6 @@ gulp.task('test:server', cb => {
'env:test',
'mocha:unit',
'mocha:integration',
- 'mocha:coverage',
cb);
});
@@ -500,124 +455,95 @@ gulp.task('mocha:integration', () => {
.pipe(mocha());
});
-gulp.task('test:client', ['wiredep:test', 'constant'<% if(filters.ts) { %>, 'transpile:client', 'transpile:client:test'<% } %>], (done) => {
- new KarmaServer({
- configFile: `${__dirname}/${paths.karma}`,
- singleRun: true
- }, done).start();
+gulp.task('test:server:coverage', cb => {
+ runSequence('coverage:pre',
+ 'env:all',
+ 'env:test',
+ 'coverage:unit',
+ 'coverage:integration',
+ cb);
});
-// inject bower components
-gulp.task('wiredep:client', () => {
- return gulp.src(paths.client.mainView)
- .pipe(wiredep({
- exclude: [<% if(filters.uibootstrap) { %>
- /bootstrap.js/,<% } %>
- '/json3/',
- '/es5-shim/'<% if(!filters.css) { %>,
- /font-awesome\.css/<% if(filters.bootstrap) { %>,
- /bootstrap\.css/<% if(filters.sass) { %>,
- /bootstrap-sass-official/<% } if(filters.oauth) { %>,
- /bootstrap-social\.css/<% }}} %>
- ],
- ignorePath: clientPath
- }))
- .pipe(gulp.dest(`${clientPath}/`));
-});
-
-gulp.task('wiredep:test', () => {
- return gulp.src(paths.karma)
- .pipe(wiredep({
- exclude: [<% if(filters.uibootstrap) { %>
- /bootstrap.js/,<% } %>
- '/json3/',
- '/es5-shim/'<% if(!filters.css) { %>,
- /font-awesome\.css/<% if(filters.bootstrap) { %>,
- /bootstrap\.css/<% if(filters.sass) { %>,
- /bootstrap-sass-official/<% } if(filters.oauth) { %>,
- /bootstrap-social\.css/<% }}} %>
- ],
- devDependencies: true
+gulp.task('coverage:pre', () => {
+ return gulp.src(paths.server.scripts)
+ // Covering files
+ .pipe(plugins.istanbul({
+ instrumenter: Instrumenter, // Use the isparta instrumenter (code coverage for ES6)
+ includeUntested: true
+ }))
+ // Force `require` to return covered files
+ .pipe(plugins.istanbul.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
+});
+
+// Downloads the selenium webdriver
+gulp.task('webdriver_update', webdriver_update);
+
+gulp.task('test:e2e', ['webpack:e2e', 'constant', 'env:all', 'env:test', 'start:server', 'webdriver_update'], cb => {
+ gulp.src(paths.client.e2e)
+ .pipe(protractor({
+ configFile: 'protractor.conf.js',
}))
- .pipe(gulp.dest('./'));
+ .on('error', e => { throw e })
+ .on('end', () => { process.exit() });
+});
+
+gulp.task('test:client', ['constant'], done => {
+ new KarmaServer({
+ configFile: `${__dirname}/${paths.karma}`,
+ singleRun: true
+ }, err => {
+ done(err);
+ process.exit(err);
+ }).start();
});
/********************
* Build
********************/
-//FIXME: looks like font-awesome isn't getting loaded
gulp.task('build', cb => {
runSequence(
[
'clean:dist',
'clean:tmp'
- ],<% if(filters.jade) { %>
- 'jade',<% } %>
+ ],
'inject',
- 'wiredep:client',<% if(filters.ts) { %>
- 'typings',<% } %>
[
'transpile:client',
'transpile:server'
],
[
'build:images',
+ 'generate-favicon',
+ 'typings'
+ ],
+ [
'copy:extras',
- 'copy:fonts',
'copy:assets',
+ 'copy:fonts:dist',
'copy:server',
- 'build:client'
+ 'webpack:dist'
],
+ 'revReplaceWebpack',
cb);
});
gulp.task('clean:dist', () => del([`${paths.dist}/!(.git*|.openshift|Procfile)**`], {dot: true}));
-gulp.task('build:client', ['styles', 'html', 'constant', 'build:images'], () => {
- var manifest = gulp.src(`${paths.dist}/${clientPath}/assets/rev-manifest.json`);
-
- var appFilter = plugins.filter('**/app.js', {restore: true});
- var jsFilter = plugins.filter('**/*.js', {restore: true});
- var cssFilter = plugins.filter('**/*.css', {restore: true});
- var htmlBlock = plugins.filter(['**/*.!(html)'], {restore: true});
-
- return gulp.src(paths.client.mainView)
- .pipe(plugins.useref())
- .pipe(appFilter)
- .pipe(plugins.addSrc.append('.tmp/templates.js'))
- .pipe(plugins.concat('app/app.js'))
- .pipe(appFilter.restore)
- .pipe(jsFilter)
- .pipe(plugins.ngAnnotate())
- .pipe(plugins.uglify())
- .pipe(jsFilter.restore)
- .pipe(cssFilter)
- .pipe(plugins.cleanCss({
- processImportFrom: ['!fonts.googleapis.com']
- }))
- .pipe(cssFilter.restore)
- .pipe(htmlBlock)
- .pipe(plugins.rev())
- .pipe(htmlBlock.restore)
- .pipe(plugins.revReplace({manifest}))
- .pipe(gulp.dest(`${paths.dist}/${clientPath}`));
-});
-
-gulp.task('html', function() {<% if(filters.jade) { %>
- return gulp.src(`.tmp/{app,components}/**/*.html`)<% } else { %>
- return gulp.src(`${clientPath}/{app,components}/**/*.html`)<% } %>
- .pipe(plugins.angularTemplatecache({
- module: '<%= scriptAppName %>'
- }))
- .pipe(gulp.dest('.tmp'));
-});<% if (filters.jade) { %>
-gulp.task('jade', function() {
- gulp.src(paths.client.views)
- .pipe(plugins.jade())
- .pipe(gulp.dest('.tmp'));
-});<% } %>
-
gulp.task('constant', function() {
let sharedConfig = require(`./${serverPath}/config/environment/shared`);
return plugins.ngConstant({
@@ -649,6 +575,12 @@ gulp.task('build:images', () => {
.pipe(gulp.dest(`${paths.dist}/${clientPath}/assets`));
});
+gulp.task('revReplaceWebpack', function() {
+ return gulp.src('dist/client/app.*.js')
+ .pipe(plugins.revReplace({manifest: gulp.src(paths.client.assets.revManifest)}))
+ .pipe(gulp.dest('dist/client'));
+});
+
gulp.task('copy:extras', () => {
return gulp.src([
`${clientPath}/favicon.ico`,
@@ -658,10 +590,33 @@ gulp.task('copy:extras', () => {
.pipe(gulp.dest(`${paths.dist}/${clientPath}`));
});
-gulp.task('copy:fonts', () => {<% if(filters.bootstrap) { %>
- return gulp.src(`${clientPath}/bower_components/{bootstrap,font-awesome}/fonts/**/*`, { dot: true })<% } else { %>
- return gulp.src(`${clientPath}/bower_components/font-awesome/fonts/**/*`, { dot: true })<% } %>
- .pipe(gulp.dest(`${paths.dist}/${clientPath}/bower_components`));
+/**
+ * turns 'boostrap/fonts/font.woff' into 'boostrap/font.woff'
+ */
+function flatten() {
+ return through2.obj(function(file, enc, next) {
+ if(!file.isDirectory()) {
+ try {
+ let dir = path.dirname(file.relative).split(path.sep)[0];
+ let fileName = path.normalize(path.basename(file.path));
+ file.path = path.join(file.base, path.join(dir, fileName));
+ this.push(file);
+ } catch(e) {
+ this.emit('error', new Error(e));
+ }
+ }
+ next();
+ });
+}
+gulp.task('copy:fonts:dev', () => {
+ return gulp.src('node_modules/{bootstrap,font-awesome}/fonts/*')
+ .pipe(flatten())
+ .pipe(gulp.dest(`${clientPath}/assets/fonts`));
+});
+gulp.task('copy:fonts:dist', () => {
+ return gulp.src('node_modules/{bootstrap,font-awesome}/fonts/*')
+ .pipe(flatten())
+ .pipe(gulp.dest(`${paths.dist}/${clientPath}/assets/fonts`));
});
gulp.task('copy:assets', () => {
@@ -678,54 +633,6 @@ gulp.task('copy:server', () => {
.pipe(gulp.dest(paths.dist));
});
-gulp.task('coverage:pre', () => {
- return gulp.src(paths.server.scripts)
- // Covering files
- .pipe(plugins.istanbul({
- instrumenter: Instrumenter, // Use the isparta instrumenter (code coverage for ES6)
- includeUntested: true
- }))
- // Force `require` to return covered files
- .pipe(plugins.istanbul.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();
- });
-});
-
/********************
* Grunt ported tasks
********************/
diff --git a/templates/app/karma.conf.js b/templates/app/karma.conf.js
index 35190d50e..21b11c718 100644
--- a/templates/app/karma.conf.js
+++ b/templates/app/karma.conf.js
@@ -1,5 +1,8 @@
// Karma configuration
-// http://karma-runner.github.io/0.10/config/configuration-file.html
+// http://karma-runner.github.io/0.13/config/configuration-file.html
+/*eslint-env node*/
+
+import makeWebpackConfig from './webpack.make';
module.exports = function(config) {
config.set({
@@ -17,45 +20,48 @@ module.exports = function(config) {
},<% } %>
// list of files / patterns to load in the browser
- files: [
- // bower:js
- // endbower<% if (filters.socketio) { %>
- 'node_modules/socket.io-client/socket.io.js',<% } %><% if(filters.ts) { %>
- '.tmp/app/app.js',
- '.tmp/{app,components}/**/*.module.js',
- '.tmp/{app,components}/**/*.js',
- '.tmp/test/**/*.js',<% } %><% if(filters.babel) { %>
- 'client/app/app.js',
- 'client/{app,components}/**/*.module.js',
- 'client/{app,components}/**/*.js',<% } %>
- 'client/{app,components}/**/*.<%= filters.jade ? '{jade,html}' : 'html' %>'
- ],
+ files: ['spec.js'],
preprocessors: {
- '**/*.html': 'ng-html2js',<% if (filters.jade) { %>
- '**/*.jade': 'ng-jade2js',<% } if (filters.babel) { %>
- 'client/{app,components}/**/*.js': 'babel'<% } %>
+ 'spec.js': ['webpack']
},
- ngHtml2JsPreprocessor: {
- stripPrefix: 'client/'
- },<% if (filters.jade) { %>
-
- ngJade2JsPreprocessor: {
- stripPrefix: 'client/'
- },<% } if (filters.babel) { %>
-
- babelPreprocessor: {
- options: {
- sourceMap: 'inline'
- },
- filename: function (file) {
- return file.originalPath.replace(/\.js$/, '.es5.js');
- },
- sourceFileName: function (file) {
- return file.originalPath;
- }
- },<% } %>
+ webpack: makeWebpackConfig({ TEST: true }),
+
+ webpackMiddleware: {
+ // webpack-dev-middleware configuration
+ // i. e.
+ noInfo: true
+ },
+
+ coverageReporter: {
+ reporters: [{
+ type: 'html', //produces a html document after code is run
+ subdir: 'client'
+ }, {
+ type: 'json',
+ subdir: '.',
+ file: 'client-coverage.json'
+ }],
+ dir: 'coverage/' //path to created html doc
+ },
+
+ plugins: [
+ require('karma-chai-plugins'),
+ require('karma-chrome-launcher'),
+ require('karma-coverage'),
+ require('karma-firefox-launcher'),
+ <%_ if(filters.mocha) { _%>
+ require('karma-mocha'),
+ require('karma-chai-plugins'),<% } %>
+ <%_ if(filters.jasmine) { _%>
+ require('karma-jasmine'),<% } %>
+ require('karma-spec-reporter'),
+ require('karma-phantomjs-launcher'),
+ require('karma-script-launcher'),
+ require('karma-webpack'),
+ require('karma-sourcemap-loader')
+ ],
// list of files / patterns to exclude
exclude: [],
@@ -74,7 +80,7 @@ module.exports = function(config) {
// - junit
// - growl
// - coverage
- reporters: ['spec'],
+ reporters: ['spec', 'coverage'],
// enable / disable watching file and executing tests whenever any file changes
autoWatch: false,
diff --git a/templates/app/server/config/express.js b/templates/app/server/config/express.js
index 2e4b8b1cb..eae03e71b 100644
--- a/templates/app/server/config/express.js
+++ b/templates/app/server/config/express.js
@@ -15,8 +15,8 @@ import errorHandler from 'errorhandler';
import path from 'path';
import lusca from 'lusca';
import config from './environment';<% if (filters.auth) { %>
-import passport from 'passport';<% } %>
-import session from 'express-session';<% if (filters.mongoose) { %>
+import passport from 'passport';<% } %><% if(!filters.noModels) { %>
+import session from 'express-session';<% } %><% if (filters.mongoose) { %>
<%_ if(semver.satisfies(nodeVersion, '>= 4')) { _%>
import connectMongo from 'connect-mongo';<% } else { _%>
import connectMongo from 'connect-mongo/es5';<% } %>
@@ -52,6 +52,7 @@ export default function(app) {
app.use(cookieParser());<% if (filters.auth) { %>
app.use(passport.initialize());<% } %>
+ <% if(!filters.noModels) { %>
// Persist sessions with MongoStore / sequelizeStore
// We need to enable sessions for passport-twitter because it's an
// oauth 1.0 strategy, and Lusca depends on sessions
@@ -83,16 +84,61 @@ export default function(app) {
},
xssProtection: true
}));
- }
+ }<% } %>
if ('development' === env) {
- app.use(require('connect-livereload')({
+ const webpackDevMiddleware = require('webpack-dev-middleware');
+ const webpack = require('webpack');
+ const makeWebpackConfig = require('../../webpack.make');
+ const webpackConfig = makeWebpackConfig({ DEV: true });
+ const compiler = webpack(webpackConfig);
+
+ const pkgConfig = require('../../package.json');
+ const livereloadServer = require('tiny-lr')();
+ var livereloadServerConfig = {
ignore: [
/^\/api\/(.*)/,
/\.js(\?.*)?$/, /\.css(\?.*)?$/, /\.svg(\?.*)?$/, /\.ico(\?.*)?$/, /\.woff(\?.*)?$/,
/\.png(\?.*)?$/, /\.jpg(\?.*)?$/, /\.jpeg(\?.*)?$/, /\.gif(\?.*)?$/, /\.pdf(\?.*)?$/
- ]
+ ],
+ port: (pkgConfig.livereload || {}).port
+ };
+ var triggerLiveReloadChanges = function() {
+ livereloadServer.changed({
+ body: {
+ files: [webpackConfig.output.path + webpackConfig.output.filename]
+ }
+ });
+ };
+ if(livereloadServerConfig.port) {
+ livereloadServer.listen(livereloadServerConfig.port, triggerLiveReloadChanges);
+ } else {
+ /**
+ * Get free port for livereload
+ * server
+ */
+ livereloadServerConfig.port = require('http').createServer().listen(function() {
+ /*eslint no-invalid-this:0*/
+ this.close();
+ livereloadServer.listen(livereloadServerConfig.port, triggerLiveReloadChanges);
+ }).address().port;
+ }
+
+ /**
+ * On change compilation of bundle
+ * trigger livereload change event
+ */
+ compiler.plugin('done', triggerLiveReloadChanges);
+
+ app.use(webpackDevMiddleware(compiler, {
+ stats: {
+ colors: true,
+ timings: true,
+ chunks: false
+ }
}));
+
+ app.use(require('connect-livereload')(livereloadServerConfig));
}
if ('development' === env || 'test' === env) {
diff --git a/templates/app/spec.js b/templates/app/spec.js
new file mode 100644
index 000000000..614d79d8b
--- /dev/null
+++ b/templates/app/spec.js
@@ -0,0 +1,14 @@
+'use strict';
+/*eslint-env node*/
+var testsContext;
+
+require('babel-polyfill');
+require('angular');
+require('angular-mocks');
+<%_ if(filters.uirouter) { _%>
+require('./client/components/ui-router/ui-router.mock');<% } %>
+<%_ if(filters.socketio) { _%>
+require('./client/components/socket/socket.mock');<% } %>
+
+testsContext = require.context('./client', true, /\.spec\.<%= scriptExt %>$/);
+testsContext.keys().forEach(testsContext);
diff --git a/templates/app/tsconfig.client(ts).json b/templates/app/tsconfig.client(ts).json
index e84a3e2fe..df5ddcd14 100644
--- a/templates/app/tsconfig.client(ts).json
+++ b/templates/app/tsconfig.client(ts).json
@@ -2,13 +2,24 @@
"compilerOptions": {
"sourceMap": true,
"rootDir": "./client",
+ "module": "commonjs",
"outDir": ".tmp",
+ "removeComments": false,
"target": "ES5"
},
+ "exclude": [
+ "node_modules",
+ "typings/main.d.ts",
+ "typings/main"
+ ],
"filesGlob": [
"client/{app,components}/**/!(*.spec).ts",
- "typings/main.d.ts"
+ "typings/browser.d.ts"
],
+ "awesomeTypescriptLoaderOptions": {
+ "resolveGlobs": true,
+ "forkChecker": true
+ },
"files": [
"client/app/account/account.ts",
"client/app/account/login/login.controller.ts",
diff --git a/templates/app/tsconfig.client.test(ts).json b/templates/app/tsconfig.client.test(ts).json
index 8263986dd..b704be74b 100644
--- a/templates/app/tsconfig.client.test(ts).json
+++ b/templates/app/tsconfig.client.test(ts).json
@@ -2,6 +2,7 @@
"compilerOptions": {
"sourceMap": true,
"rootDir": "./client",
+ "module": "commonjs",
"outDir": ".tmp/test"
},
"filesGlob": [
diff --git a/templates/app/typings(ts).json b/templates/app/typings(ts).json
index cfbd0f707..6ec1e1e7a 100644
--- a/templates/app/typings(ts).json
+++ b/templates/app/typings(ts).json
@@ -1,9 +1,13 @@
{
"ambientDependencies": {
"angular": "registry:dt/angular#1.5.0+20160412133217",
+ "angular-resource": "registry:dt/angular-resource#1.5.0+20160613142217",
"jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#40c60850ad6c8175a62d5ab48c4e016ea5b3dffe",
"lodash": "github:DefinitelyTyped/DefinitelyTyped/lodash/lodash.d.ts#40c60850ad6c8175a62d5ab48c4e016ea5b3dffe",
- "socket.io-client": "github:DefinitelyTyped/DefinitelyTyped/socket.io-client/socket.io-client.d.ts#40c60850ad6c8175a62d5ab48c4e016ea5b3dffe"
+ "socket.io-client": "github:DefinitelyTyped/DefinitelyTyped/socket.io-client/socket.io-client.d.ts#40c60850ad6c8175a62d5ab48c4e016ea5b3dffe",
+ "core-js": "registry:dt/core-js#0.0.0+20160317120654",
+ "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#8cf8164641be73e8f1e652c2a5b967c7210b6729",
+ "webpack": "github:DefinitelyTyped/DefinitelyTyped/webpack/webpack.d.ts#95c02169ba8fa58ac1092422efbd2e3174a206f4"
},
"ambientDevDependencies": {
"angular-protractor": "github:DefinitelyTyped/DefinitelyTyped/angular-protractor/angular-protractor.d.ts#40c60850ad6c8175a62d5ab48c4e016ea5b3dffe",
diff --git a/templates/app/webpack.build.js b/templates/app/webpack.build.js
new file mode 100644
index 000000000..2bf43c071
--- /dev/null
+++ b/templates/app/webpack.build.js
@@ -0,0 +1,8 @@
+/**
+ * Webpack config for builds
+ */
+module.exports = require('./webpack.make')({
+ BUILD: true,
+ TEST: false,
+ DEV: false
+});
diff --git a/templates/app/webpack.dev.js b/templates/app/webpack.dev.js
new file mode 100644
index 000000000..491f6e946
--- /dev/null
+++ b/templates/app/webpack.dev.js
@@ -0,0 +1,8 @@
+/**
+ * Webpack config for development
+ */
+module.exports = require('./webpack.make')({
+ BUILD: false,
+ TEST: false,
+ DEV: true
+});
diff --git a/templates/app/webpack.make.js b/templates/app/webpack.make.js
new file mode 100644
index 000000000..0f1cdeb2e
--- /dev/null
+++ b/templates/app/webpack.make.js
@@ -0,0 +1,411 @@
+'use strict';
+/*eslint-env node*/
+var webpack = require('webpack');
+var autoprefixer = require('autoprefixer');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
+var ExtractTextPlugin = require('extract-text-webpack-plugin');
+var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
+var fs = require('fs');
+var path = require('path');
+var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin;
+
+module.exports = function makeWebpackConfig(options) {
+ /**
+ * Environment type
+ * BUILD is for generating minified builds
+ * TEST is for generating test builds
+ */
+ var BUILD = !!options.BUILD;
+ var TEST = !!options.TEST;
+ var E2E = !!options.E2E;
+ var DEV = !!options.DEV;
+
+ /**
+ * Config
+ * Reference: http://webpack.github.io/docs/configuration.html
+ * This is the object where all configuration gets set
+ */
+ var config = {};
+
+ /**
+ * Entry
+ * Reference: http://webpack.github.io/docs/configuration.html#entry
+ * Should be an empty object if it's generating a test build
+ * Karma will set this when it's a test build
+ */
+ if(TEST) {
+ config.entry = {};
+ } else {
+ config.entry = {
+ app: './client/app/app.<%= scriptExt %>',
+ polyfills: './client/polyfills.<%= scriptExt %>',
+ vendor: [
+ 'angular',
+ 'angular-animate',
+ 'angular-aria',
+ 'angular-cookies',
+ 'angular-resource',
+ <%_ if(filters.ngroute) { _%>
+ 'angular-route',<% } %>
+ 'angular-sanitize',
+ 'angular-socket-io',
+ 'angular-ui-bootstrap',
+ <%_ if(filters.uirouter) { _%>
+ 'angular-ui-router',<% } %>
+ 'lodash'
+ ]
+ };
+ }
+
+ /**
+ * Output
+ * Reference: http://webpack.github.io/docs/configuration.html#output
+ * Should be an empty object if it's generating a test build
+ * Karma will handle setting it up for you when it's a test build
+ */
+ if(TEST) {
+ config.output = {};
+ } else {
+ config.output = {
+ // Absolute output directory
+ path: BUILD ? path.join(__dirname, '/dist/client/') : path.join(__dirname, '/.tmp/'),
+
+ // Output path from the view of the page
+ // Uses webpack-dev-server in development
+ publicPath: BUILD || DEV || E2E ? '/' : `http://localhost:${8080}/`,
+ //publicPath: BUILD ? '/' : 'http://localhost:' + env.port + '/',
+
+ // Filename for entry points
+ // Only adds hash in build mode
+ filename: BUILD ? '[name].[hash].js' : '[name].bundle.js',
+
+ // Filename for non-entry points
+ // Only adds hash in build mode
+ chunkFilename: BUILD ? '[name].[hash].js' : '[name].bundle.js'
+ };
+ }
+
+ <%_ if(filters.ts) { _%>
+ config.resolve = {
+ modulesDirectories: ['node_modules'],
+ extensions: ['', '.js', '.ts']
+ };<% } %>
+
+ if(TEST) {
+ config.resolve = {
+ modulesDirectories: [
+ 'node_modules'
+ ],
+ extensions: ['', '.js', '.ts']
+ };
+ }
+
+ /**
+ * Devtool
+ * Reference: http://webpack.github.io/docs/configuration.html#devtool
+ * Type of sourcemap to use per build type
+ */
+ if(TEST) {
+ config.devtool = 'inline-source-map';
+ } else if(BUILD || DEV) {
+ config.devtool = 'source-map';
+ } else {
+ config.devtool = 'eval';
+ }
+
+ /**
+ * Loaders
+ * Reference: http://webpack.github.io/docs/configuration.html#module-loaders
+ * List: http://webpack.github.io/docs/list-of-loaders.html
+ * This handles most of the magic responsible for converting modules
+ */
+ <%_ if(filters.sass) { _%>
+
+ config.sassLoader = {
+ outputStyle: 'compressed',
+ precision: 10,
+ sourceComments: false
+ };<% } %>
+
+ <%_ if(filters.babel) { -%>
+ config.babel = {
+ shouldPrintComment(commentContents) {
+ <%_ if(filters.flow) { -%>
+ let regex = DEV
+ // keep `// @flow`, `/*@ngInject*/`, & flow type comments in dev
+ ? /(@flow|@ngInject|^:)/
+ // keep `/*@ngInject*/`
+ : /@ngInject/;
+ return regex.test(commentContents);
+ <%_ } -%>
+ <%_ if(!filters.flow) { -%>
+ // keep `/*@ngInject*/`
+ return /@ngInject/.test(commentContents);
+ <%_ } -%>
+ }
+ }<% } %>
+
+ // Initialize module
+ config.module = {
+ preLoaders: [],
+ loaders: [{
+ // JS LOADER
+ // Reference: https://github.com/babel/babel-loader
+ // Transpile .js files using babel-loader
+ // Compiles ES6 and ES7 into ES5 code
+ test: /\.js$/,
+ loader: 'babel',
+ include: [
+ path.resolve(__dirname, 'client/'),
+ path.resolve(__dirname, 'node_modules/lodash-es/')
+ ]
+ }, {
+ // TS LOADER
+ // Reference: https://github.com/s-panferov/awesome-typescript-loader
+ // Transpile .ts files using awesome-typescript-loader
+ test: /\.ts$/,
+ loader: 'awesome-typescript-loader',
+ query: {
+ tsconfig: path.resolve(__dirname, 'tsconfig.client.json')
+ },
+ include: [
+ path.resolve(__dirname, 'client/')
+ ]
+ }, {
+ // ASSET LOADER
+ // Reference: https://github.com/webpack/file-loader
+ // Copy png, jpg, jpeg, gif, svg, woff, woff2, ttf, eot files to output
+ // Rename the file using the asset hash
+ // Pass along the updated reference to your code
+ // You can add here any file extension you want to get copied to your output
+ test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)([\?]?.*)$/,
+ loader: 'file'
+ }, {
+ <%_ if(filters.jade) { _%>
+ // Jade LOADER
+ // Reference: https://github.com/webpack/jade-loader
+ // Allow loading jade throw js
+ test: /\.jade$/,
+ loaders: ['pug-html']
+ }, {<% } %>
+ <%_ if(filters.html) { _%>
+ // HTML LOADER
+ // Reference: https://github.com/webpack/raw-loader
+ // Allow loading html through js
+ test: /\.html$/,
+ loader: 'raw'
+ }, {<% } %>
+ // CSS LOADER
+ // Reference: https://github.com/webpack/css-loader
+ // Allow loading css through js
+ //
+ // Reference: https://github.com/postcss/postcss-loader
+ // Postprocess your css with PostCSS plugins
+ test: /\.css$/,
+ loader: !TEST
+ // Reference: https://github.com/webpack/extract-text-webpack-plugin
+ // Extract css files in production builds
+ //
+ // Reference: https://github.com/webpack/style-loader
+ // Use style-loader in development for hot-loading
+ ? ExtractTextPlugin.extract('style', 'css?sourceMap!postcss')
+ // Reference: https://github.com/webpack/null-loader
+ // Skip loading css in test mode
+ : 'null'
+ }<% if(!filters.css) { %>, {
+ <%_ if(filters.sass) { _%>
+ // SASS LOADER
+ // Reference: https://github.com/jtangelder/sass-loader
+ test: /\.(scss|sass)$/,
+ loaders: ['style', 'css', 'sass'],
+ include: [
+ path.resolve(__dirname, 'node_modules/bootstrap-sass/assets/stylesheets/*.scss'),
+ path.resolve(__dirname, 'client/app/app.scss')
+ ]<% } %>
+ <%_ if(filters.less) { _%>
+ // LESS LOADER
+ // Reference: https://github.com/
+ test: /\.less$/,
+ loaders: ['style', 'css', 'less'],
+ include: [
+ path.resolve(__dirname, 'node_modules/bootstrap/less/*.less'),
+ path.resolve(__dirname, 'client/app/app.less')
+ ]<% } %>
+ <%_ if(filters.stylus) { _%>
+ // Stylus LOADER
+ // Reference: https://github.com/
+ test: /\.styl$/,
+ loaders: ['style', 'css', 'stylus'],
+ include: [
+ path.resolve(__dirname, 'node_modules/bootstrap-styl/bootstrap/*.styl'),
+ path.resolve(__dirname, 'client/app/app.styl')
+ ]<% } %>
+ }<% } %>]
+ };
+
+ config.module.postLoaders = [{
+ test: /\.<%= scriptExt %>$/,
+ loader: 'ng-annotate?single_quotes'
+ }];
+
+ <%_ if(filters.babel) { _%>
+ // ISPARTA INSTRUMENTER LOADER
+ // Reference: https://github.com/ColCh/isparta-instrumenter-loader
+ // Instrument JS files with Isparta for subsequent code coverage reporting
+ // Skips node_modules and spec files
+ if(TEST) {
+ config.module.preLoaders.push({
+ //delays coverage til after tests are run, fixing transpiled source coverage error
+ test: /\.js$/,
+ exclude: /(node_modules|spec\.js|mock\.js)/,
+ loader: 'isparta-instrumenter',
+ query: {
+ babel: {
+ // optional: ['runtime', 'es7.classProperties', 'es7.decorators']
+ }
+ }
+ });
+ }<% } %>
+ <%_ if(filters.ts) { _%>
+ //TODO: TS Instrumenter<% } %>
+
+ /**
+ * PostCSS
+ * Reference: https://github.com/postcss/autoprefixer-core
+ * Add vendor prefixes to your css
+ */
+ config.postcss = [
+ autoprefixer({
+ browsers: ['last 2 version']
+ })
+ ];
+
+ /**
+ * Plugins
+ * Reference: http://webpack.github.io/docs/configuration.html#plugins
+ * List: http://webpack.github.io/docs/list-of-plugins.html
+ */
+ config.plugins = [
+ /*
+ * Plugin: ForkCheckerPlugin
+ * Description: Do type checking in a separate process, so webpack don't need to wait.
+ *
+ * See: https://github.com/s-panferov/awesome-typescript-loader#forkchecker-boolean-defaultfalse
+ */
+ new ForkCheckerPlugin(),
+
+ // Reference: https://github.com/webpack/extract-text-webpack-plugin
+ // Extract css files
+ // Disabled when in test mode or not in build mode
+ new ExtractTextPlugin('[name].[hash].css', {
+ disable: !BUILD || TEST
+ })
+ ];
+
+ if(!TEST) {
+ config.plugins.push(new CommonsChunkPlugin({
+ name: 'vendor',
+
+ // filename: "vendor.js"
+ // (Give the chunk a different name)
+
+ minChunks: Infinity
+ // (with more entries, this ensures that no other module
+ // goes into the vendor chunk)
+ }));
+ }
+
+ // Skip rendering index.html in test mode
+ // Reference: https://github.com/ampedandwired/html-webpack-plugin
+ // Render index.html
+ let htmlConfig = {
+ template: 'client/_index.html'
+ }
+ if(E2E) {
+ htmlConfig.filename = '../client/index.html';
+ htmlConfig.alwaysWriteToDisk = true;
+ }
+ config.plugins.push(new HtmlWebpackPlugin(htmlConfig));
+ if(E2E) config.plugins.push(new HtmlWebpackHarddiskPlugin());
+
+ // Add build specific plugins
+ if(BUILD) {
+ config.plugins.push(
+ // Reference: http://webpack.github.io/docs/list-of-plugins.html#noerrorsplugin
+ // Only emit files when there are no errors
+ new webpack.NoErrorsPlugin(),
+
+ // Reference: http://webpack.github.io/docs/list-of-plugins.html#dedupeplugin
+ // Dedupe modules in the output
+ new webpack.optimize.DedupePlugin(),
+
+ // Reference: http://webpack.github.io/docs/list-of-plugins.html#uglifyjsplugin
+ // Minify all javascript, switch loaders to minimizing mode
+ new webpack.optimize.UglifyJsPlugin({
+ mangle: false,
+ output: {
+ comments: false
+ },
+ compress: {
+ warnings: false
+ }
+ }),
+
+ // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
+ // Define free global variables
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: '"production"'
+ }
+ })
+ );
+ }
+
+ if(DEV) {
+ config.plugins.push(
+ // Reference: https://webpack.github.io/docs/list-of-plugins.html#defineplugin
+ // Define free global variables
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: '"development"'
+ }
+ })
+ );
+ }
+
+ config.cache = DEV;
+
+ if(TEST) {
+ config.stats = {
+ colors: true,
+ reasons: true
+ };
+ config.debug = false;
+ }
+
+ /**
+ * Dev server configuration
+ * Reference: http://webpack.github.io/docs/configuration.html#devserver
+ * Reference: http://webpack.github.io/docs/webpack-dev-server.html
+ */
+ config.devServer = {
+ contentBase: './client/',
+ stats: {
+ modules: false,
+ cached: false,
+ colors: true,
+ chunk: false
+ }
+ };
+
+ config.node = {
+ global: 'window',
+ process: true,
+ crypto: 'empty',
+ clearImmediate: false,
+ setImmediate: false
+ };
+
+ return config;
+};
diff --git a/templates/app/webpack.test.js b/templates/app/webpack.test.js
new file mode 100644
index 000000000..9175a1b69
--- /dev/null
+++ b/templates/app/webpack.test.js
@@ -0,0 +1,8 @@
+/**
+ * Webpack config for tests
+ */
+module.exports = require('./webpack.make')({
+ BUILD: false,
+ TEST: true,
+ DEV: false
+});
diff --git a/test/fixtures/.bowerrc b/test/fixtures/.bowerrc
deleted file mode 100644
index 69fad3580..000000000
--- a/test/fixtures/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "directory": "bower_components"
-}
diff --git a/test/fixtures/.yo-rc.json b/test/fixtures/.yo-rc.json
index 3f652f692..b1c868ce5 100644
--- a/test/fixtures/.yo-rc.json
+++ b/test/fixtures/.yo-rc.json
@@ -26,7 +26,7 @@
"models": true,
"mongooseModels": true,
"mongoose": true,
- "grunt": true,
+ "gulp": true,
"mocha": true,
"jasmine": false,
"expect": true