SlideShare a Scribd company logo
Scaffolding in JavaScript
March 2015
Tomi Vanek
Copyright © 2015 Accenture All rights reserved. 2
Tomi Vanek
Senior technology architect by Accenture
25+ years of experience
Current focus on modern web applications
Copyright © 2015 Accenture All rights reserved. 3Credit: Flickr, photo by Cedward Bricehttps://www.youtube.com/watch?v=2nMD6sjAe8I#t=134
Copyright © 2015 Accenture All rights reserved. 4
Copyright © 2015 Accenture All rights reserved. 5
- name must be prefixed by generator-.
- folder tree reflects available generators
generator-angular
|
|__ package.json
|
|__ generators
| |__ app
| | |__ index.js
| |
| |__ controller
| | |__ index.js
| |
| |__ directive
| |__ index.js
|
|__ templates
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 6
- name must be prefixed by generator-.
- folder tree reflects available generators
generator-angular
|
|__ package.json
|
|__ generators
| |__ app
| | |__ index.js
| |
| |__ controller
| | |__ index.js
| |
| |__ directive
| |__ index.js
|
|__ templates
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 7
• Start with extending from
• generators.Base for default generator
• generators.NamedBase for sub-generator
• Methods/functions are executed in the order
they are defined
• Private methods – use underscore or instance
method
• Execution phases:
• Initializing
• Prompting
• Configuring
• Default
• Writing
• Conflicts
• Install
• End
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 8
• Start with extending from
• generators.Base for default generator
• generators.NamedBase for sub-generator
• Methods/functions are executed in the order
they are defined
• Private methods – use underscore or instance
method
• Execution phases:
• Initializing
• Prompting
• Configuring
• Default
• Writing
• Conflicts
• Install
• End
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 9
• Start with extending from
• generators.Base for default generator
• generators.NamedBase for sub-generator
• Methods/functions are executed in the order
they are defined
• Private methods – use underscore or instance
method
• Execution phases:
• Initializing
• Prompting
• Configuring
• Default
• Writing
• Conflicts
• Install
• End
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 10
• Start with extending from
• generators.Base for default generator
• generators.NamedBase for sub-generator
• Methods/functions are executed in the order
they are defined
• Private methods – use underscore or instance
method
• Execution phases:
• Initializing
• Prompting
• Configuring
• Default
• Writing
• Conflicts
• Install
• End
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 11
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
greetDeveloper: function() {
this.log('Hello!');
},
createFiles: function() {
},
end: function() {
},
_helper: function() {
}
});
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 12
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
greetDeveloper: function() {
this.log('Hello!');
},
createFiles: function() {
},
end: function() {
},
_helper: function() {
}
});
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 13
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
greetDeveloper: function() {
this.log('Hello!');
},
createFiles: function() {
},
end: function() {
},
_helper: function() {
}
});
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 14
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
greetDeveloper: function() {
this.log('Hello!');
},
createFiles: function() {
},
end: function() {
},
_helper: function() {
}
});
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 15
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
greetDeveloper: function() {
this.log('Hello!');
},
createFiles: function() {
},
end: function() {
},
_helper: function() {
}
});
Initialization
Interaction
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 16
• Arguments
• yo angular:controller admin
var yg = require('yeoman-generator');
module.exports = yg.generators.NamedBase.extend({
constructor: function(args, options) {
yg.generators.NamedBase.apply(this, arguments);
},
displayName: function() {
this.log(‘Creating ' + this.name + 'Ctrl.');
}
});
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 17
• Arguments
• yo angular:controller admin
var yg = require('yeoman-generator');
module.exports = yg.generators.NamedBase.extend({
constructor: function(args, options) {
yg.generators.NamedBase.apply(this, arguments);
},
displayName: function() {
this.log(‘Creating ' + this.name + 'Ctrl.');
}
});
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 18
• Options
• yo angular --coffee --skip-install
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
createFiles: function() {
if (this.options['coffee']){
// use CoffeeScript templates
} else {
// use JavaScript templates
}
},
install: function() {
if (this.options['skip-install']) {
// don’t run installation
}
}
});
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 19
• Options
• yo angular --coffee --skip-install
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
createFiles: function() {
if (this.options['coffee']){
// use CoffeeScript templates
} else {
// use JavaScript templates
}
},
install: function() {
if (this.options['skip-install']) {
// don’t run installation
}
}
});
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 20
• Options
• yo angular --coffee --skip-install
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
},
createFiles: function() {
if (this.options['coffee']){
// use CoffeeScript templates
} else {
// use JavaScript templates
}
},
install: function() {
if (this.options['skip-install']) {
// don’t run installation
}
}
});
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 21
// list
? What would you like to write scripts with?:
> JavaScript
CoffeeScript
// checkbox
? Which modules would you like to include?:
> (•) angular-animate.js
( ) angular-cookies.js
(•) angular-route.js
( ) angular-touch.js
// confirm
? Would you like to include Bootstrap?: (Y/n)
// expand
? Overwrite bower.json?: (Ynaxdh) a
>> overwrite this and all others
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 22
• Prompts – via Inquirer.js
• Asking questions
• Parsing
• Validation
• Hierarchical prompts
• Error handling
• Available prompt types
• List
• Raw list
• Checkbox
• Confirm (y/n)
• Expand
• Input
• Password
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 23
askAboutAngularModules: function() {
var ngModules = [{
value: 'ngAnimate',
checked: true
},{
value: 'ngResource',
checked: false
},{
value: 'ngCookies',
checked: false }];
var cb = this.async();
this.prompt([
{
type: 'checkbox’,
name: ‘angularModules’,
message: ‘Which modules would you like to
include?’,
choices: ngModules
}
], function(answers) {
this.angularModules = nswers.angularModules;
cb()
}.bind(this));
}
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 24
askAboutAngularModules: function() {
var ngModules = [{
value: 'ngAnimate',
checked: true
},{
value: 'ngResource',
checked: false
},{
value: 'ngCookies',
checked: false }];
var cb = this.async();
this.prompt([
{
type: 'checkbox’,
name: ‘angularModules’,
message: ‘Which modules would you like to
include?’,
choices: ngModules
}
], function(result) {
this.angularModules = result.angularModules;
cb();
}.bind(this));
}
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 25
askAboutAngularModules: function() {
var ngModules = [{
value: 'ngAnimate',
checked: true
},{
value: 'ngResource',
checked: false
},{
value: 'ngCookies',
checked: false }];
var cb = this.async();
this.prompt([
{
type: 'checkbox’,
name: ‘angularModules’,
message: ‘Which modules would you like to
include?’,
choices: ngModules
}
], function(answers) {
this.angularModules = nswers.angularModules;
cb()
}.bind(this));
}
Interaction
Initialization
Configuration
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 26
• Storing user configuration and sharing it
between sub-generators:
• Source directory
• Bootstrap
• Routing option
• SASS/LESS
• HTML/Jade
• Path to custom templates
• etc.
• Configuration Persistence - API
• generator.config.save()
• generator.config.set()
• generator.config.get()
• generator.config.getAll()
• generator.config.delete()
• generator.config.defaults()
Interaction
Configuration
Initialization
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 27
.yo-rc.json – yeoman configuration file
{
"generator-angular": {
"srcDir": "src/client",
"routing": "uiRouter",
"bootstrap": true,
"ngModules": [
"ngAnimate",
"ngSanitize",
"ngTouch"
],
"extensions": ["js", "html"]
},
"generator-node": {
"srcDir": "src/server",
"socketio": false,
"oauth": true
}
}
Interaction
Configuration
Initialization
Generation
Installation
End
Copyright © 2015 Accenture All rights reserved. 28
• Two location contexts:
• sourceRoot
• destinationRoot
• File path is relative to location contexts
• File utilities:
• template(source, dest [, data])
• copy(source, dest)
• dir(source, dest [, data])
• Template data – optional JS object
• If not provided – properties of `this` are used
• File conflict handling out of box
? Overwrite bower.json?: (Ynaxdh) a
>> overwrite this and all others
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 29
(function() {
'use strict';
angular
.module('<%= moduleName %>')
.directive('<%= name %>', [<%= name %>]);
/* @ngInject */
function <%= name %> () {
var directive = {
restrict: 'EA',
link: link,<% if (separateTemplate) { %>
templateUrl: '<%= templateUrl %>‘
<% } else { %>
template: '<div><%= name %></div>‘<% } %>
};
return directive;
function link(scope, element, attrs) {
element.text('<%= name %>');
}
}
})();
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 30
(function() {
'use strict';
angular
.module('<%= moduleName %>')
.directive('<%= name %>', [<%= name %>]);
/* @ngInject */
function <%= name %> () {
var directive = {
restrict: 'EA',
link: link,<% if (separateTemplate) { %>
templateUrl: '<%= templateUrl %>‘
<% } else { %>
template: '<div><%= name %></div>‘<% } %>
};
return directive;
function link(scope, element, attrs) {
element.text('<%= name %>');
}
}
})();
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 31
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
this.sourceRoot('../templates');
this.destinationRoot('.');
this.appName = 'myApp';
},
configFiles: function() {
this.copy('_editorconfig', '.editorconfig');
this.dir('code-analysis', '.');
this.dir('pkg-conf', '.', {name: 'demo'});
},
appModule: function() {
this.template('module/module.js_',
'src/client/app/app.module.js');
this.template('controller/ctrl.js_',
'src/client/app.controller.js',
{name: 'MyAppCtrl', appName: 'myApp')};
}
});
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 32
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
this.sourceRoot('../templates');
this.destinationRoot('.');
this.appName = 'myApp';
},
configFiles: function() {
this.copy('_editorconfig', '.editorconfig');
this.dir('code-analysis', '.');
this.dir('pkg-conf', '.', {name: 'demo'});
},
appModule: function() {
this.template('module/module.js_',
'src/client/app/app.module.js');
this.template('controller/ctrl.js_',
'src/client/app.controller.js',
{name: 'MyAppCtrl', appName: 'myApp')};
}
});
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 33
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
this.sourceRoot('../templates');
this.destinationRoot('.');
this.appName = 'myApp';
},
configFiles: function() {
this.copy('_editorconfig', '.editorconfig');
this.dir('code-analysis', '.');
this.dir('pkg-conf', '.', {name: 'demo'});
},
appModule: function() {
this.template('module/module.js_',
'src/client/app/app.module.js');
this.template('controller/ctrl.js_',
'src/client/app.controller.js',
{name: 'MyAppCtrl', appName: 'myApp')};
}
});
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 34
var yg = require('yeoman-generator');
module.exports = yg.generators.Base.extend({
constructor: function(args, options) {
yg.generators.Base.apply(this, arguments);
this.sourceRoot('../templates');
this.destinationRoot('.');
this.appName = 'myApp';
},
configFiles: function() {
this.copy('_editorconfig', '.editorconfig');
this.dir('code-analysis', '.');
this.dir('pkg-conf', '.', {name: 'demo'});
},
appModule: function() {
this.template('module/module.js_',
'src/client/app/app.module.js');
this.template('controller/ctrl.js_',
'src/client/app.controller.js',
{name: 'MyAppCtrl', appName: 'myApp')};
}
});
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 35
• Yeoman runs npm & bower install for you
• Spawn CLI commands
• Execute in 'install' or 'end' running context
_skippedInstl: function() {
if (this.options['skip-install']) {
this.log('Run npm install & bower install');
} else {
this.spawnCommand('grunt', ['wiredep']);
}
},
end: function() {
this.installDependencies({
skipInstall: this.options['skip-install'],
skipMessage: this.options['skip-message'],
callback: this._skippedInstl.bind(this)
});
}
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 36
• Yeoman runs npm & bower install for you
• Spawn CLI commands
• Execute in 'install' or 'end' running context
_skippedInstl: function() {
if (this.options['skip-install']) {
this.log('Run npm install & bower install');
} else {
this.spawnCommand('grunt', ['wiredep']);
}
},
end: function() {
this.installDependencies({
skipInstall: this.options['skip-install'],
skipMessage: this.options['skip-message'],
callback: this._skippedInstl.bind(this)
});
}
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 37
• Yeoman runs npm & bower install for you
• Spawn CLI commands
• Execute in 'install' or 'end' running context
_skippedInstl: function() {
if (this.options['skip-install']) {
this.log('Run npm install & bower install');
} else {
this.spawnCommand('grunt', ['wiredep']);
}
},
end: function() {
this.installDependencies({
skipInstall: this.options['skip-install'],
skipMessage: this.options['skip-message'],
callback: this._skippedInstl.bind(this)
});
}
Interaction
Configuration
Generation
Initialization
End
Installation
Copyright © 2015 Accenture All rights reserved. 38
Short summary of the result
Next manual steps
(i.e. on –skip-installation)
After running `npm install` & `bower install`, inject
your front end dependencies into your source code
by running: grunt wiredep
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 39
Short summary of the result
Next manual steps
(i.e. on –skip-installation)
After running `npm install` & `bower install`, inject
your front end dependencies into your source code
by running: grunt wiredep
Interaction
Configuration
Generation
Initialization
Installation
End
Copyright © 2015 Accenture All rights reserved. 40
Unit Tests
• Put each tested type of generator into separate describe block
• Mock user interaction and run generator in before block
• Test assertions in the it block
describe('angular generator', function() {
before(function(done) {
// run tested generator
done();
});
describe('should generate following files', function() {
it('bower.json', function() {
// assert the file exits
// assert correct file content
});
it('package.json', function() {
});
});
});
Copyright © 2015 Accenture All rights reserved. 41
Unit Tests
• Put each tested type of generator into separate describe block
• Mock user interaction and run generator in before block
• Test assertions in the it block
describe('angular generator', function() {
before(function(done) {
// run tested generator
done();
});
describe('should generate following files', function() {
it('bower.json', function() {
// assert the file exits
// assert correct file content
});
it('package.json', function() {
});
});
});
Copyright © 2015 Accenture All rights reserved. 42
Unit Tests
• Put each tested type of generator into separate describe block
• Mock user interaction and run generator in before block
• Test assertions in the it block
describe('angular generator', function() {
before(function(done) {
// run tested generator
done();
});
describe('should generate following files', function() {
it('bower.json', function() {
// assert the file exits
// assert correct file content
});
it('package.json', function() {
});
});
});
Copyright © 2015 Accenture All rights reserved. 43
Unit Tests
describe('angular generator', function() {
before(function(done) {
helpers.run(path.join(__dirname, '../generators/app')
.inDir(path.join(__dirname, './temp'), function(dir) {
})
.withArguments([]),
.withOptions({'coffee': false}),
.withPrompts({'bootstrap': true, 'routing': 'uiRouter'})
.on('ready', function(generator) {
generator.on('start', yoOutput.mute);
})
.on('end', function() {
yoOutput.unmute();
done();
});
});
describe('should generate following files', function() {
// test the assertions
});
});
Copyright © 2015 Accenture All rights reserved. 44
Unit Tests
describe('angular generator', function() {
before(function(done) {
helpers.run(path.join(__dirname, '../generators/app')
.inDir(path.join(__dirname, './temp'), function(dir) {
})
.withArguments([]),
.withOptions({'coffee': false}),
.withPrompts({'bootstrap': true, 'routing': 'uiRouter'})
.on('ready', function(generator) {
generator.on('start', yoOutput.mute);
})
.on('end', function() {
yoOutput.unmute();
done();
});
});
describe('should generate following files', function() {
// test the assertions
});
});
Copyright © 2015 Accenture All rights reserved. 45
Unit Tests
describe('angular generator', function() {
before(function(done) {
helpers.run(path.join(__dirname, '../generators/app')
.inDir(path.join(__dirname, './temp'), function(dir) {
})
.withArguments([]),
.withOptions({'coffee': false}),
.withPrompts({'bootstrap': true, 'routing': 'uiRouter'})
.on('ready', function(generator) {
generator.on('start', yoOutput.mute);
})
.on('end', function() {
yoOutput.unmute();
done();
});
});
describe('should generate following files', function() {
// test the assertions
});
});
Copyright © 2015 Accenture All rights reserved. 46
Unit Tests
describe('angular generator', function() {
before(function(done) {
// run tested generator
done();
});
describe('should generate following files', function() {
it('bower.json', function() {
// assert the file exits
assert.file('bower.json');
// assert correct file content
assert.fileContent('bower.json', /bootstrap/);
assert.noFileContent('bower.json', /angular-route/);
});
it('package.json', function() {
});
});
});
Copyright © 2015 Accenture All rights reserved. 47
Unit Tests
describe('angular generator', function() {
before(function(done) {
// run tested generator
done();
});
describe('should generate following files', function() {
it('bower.json', function() {
// assert the file exits
assert.file('bower.json');
// assert correct file content
assert.fileContent('bower.json', /bootstrap/);
assert.noFileContent('bower.json', /angular-route/);
});
it('package.json', function() {
});
});
});
Copyright © 2015 Accenture All rights reserved. 48
Modularization
• Subgenerators
this.composeWith('angular:controller', {
arguments: ['admin'],
options: {'matchingView': false}
}
};
• External generators
this.composeWith('karma', {}, {
local: require.resolve('generator-karma')
}
};
• Shared templates and utilities
Copyright © 2015 Accenture All rights reserved. 49
Modularization
• Subgenerators
this.composeWith('angular:controller', {
arguments: ['admin'],
options: {'matchingView': false}
}
};
• External generators
this.composeWith('karma', {}, {
local: require.resolve('generator-karma')
}
};
• Shared templates and utilities
Copyright © 2015 Accenture All rights reserved. 50
Modularization
• Subgenerators
this.composeWith('angular:controller', {
arguments: ['admin'],
options: {'matchingView': false}
}
};
• External generators
this.composeWith('karma', {}, {
local: require.resolve('generator-karma')
}
};
• Shared templates and utilities
Copyright © 2015 Accenture All rights reserved. 51
• Enterprise IT, BPM, B2B
• DevOps
• API, WS
• Language, DSL
• Model-Driven Development
• Runtime Code Generation
• Scaffold
• Project Seed
• Framework, Platform, SDK
• Runtime Module, Component, Library
• Copy-Paste
• Hand-Written Code
Scaffolding in Model-Driven Architecture
Copyright © 2015 Accenture All rights reserved. 52
• Asynchronous callbacks in conditional execution
• Post-write to files
• OS-specific path
• Naming
• Simplicity vs rich configurability
Pitfalls
Copyright © 2015 Accenture All rights reserved. 53
Questions
Scaffolding in JavaScript
Yeoman code generator
tomi vanek
software architect

More Related Content

What's hot

Building maintainable app
Building maintainable appBuilding maintainable app
Building maintainable app
Kristijan Jurković
 
AngularJS - dependency injection
AngularJS - dependency injectionAngularJS - dependency injection
AngularJS - dependency injection
Alexe Bogdan
 
AngularJS Project Setup step-by- step guide - RapidValue Solutions
AngularJS Project Setup step-by- step guide - RapidValue SolutionsAngularJS Project Setup step-by- step guide - RapidValue Solutions
AngularJS Project Setup step-by- step guide - RapidValue Solutions
RapidValue
 
AngularJS in practice
AngularJS in practiceAngularJS in practice
AngularJS in practice
Eugene Fidelin
 
Technozaure - Angular2
Technozaure - Angular2Technozaure - Angular2
Technozaure - Angular2
Demey Emmanuel
 
ChtiJUG - Introduction à Angular2
ChtiJUG - Introduction à Angular2ChtiJUG - Introduction à Angular2
ChtiJUG - Introduction à Angular2
Demey Emmanuel
 
Angularjs
AngularjsAngularjs
Angularjs
Ynon Perek
 
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Codemotion
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)
Fabio Biondi
 
AngularJS Best Practices
AngularJS Best PracticesAngularJS Best Practices
AngularJS Best Practices
Betclic Everest Group Tech Team
 
Working with AngularJS
Working with AngularJSWorking with AngularJS
Working with AngularJS
André Vala
 
AngularJs-training
AngularJs-trainingAngularJs-training
AngularJs-training
Pratchaya Suputsopon
 
Developing New Widgets for your Views in Owl
Developing New Widgets for your Views in OwlDeveloping New Widgets for your Views in Owl
Developing New Widgets for your Views in Owl
Odoo
 
Recap of Android Dev Summit 2018
Recap of Android Dev Summit 2018Recap of Android Dev Summit 2018
Recap of Android Dev Summit 2018
Hassan Abid
 
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
Christian Janz
 
You don't need DI
You don't need DIYou don't need DI
You don't need DI
Sebastian Świerczek
 
Rohit android lab projects in suresh gyan vihar
Rohit android lab projects in suresh gyan viharRohit android lab projects in suresh gyan vihar
Rohit android lab projects in suresh gyan vihar
Rohit malav
 
Refactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsRefactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.js
Stacy London
 
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Kelly Shuster
 
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember DataIn The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
Stacy London
 

What's hot (20)

Building maintainable app
Building maintainable appBuilding maintainable app
Building maintainable app
 
AngularJS - dependency injection
AngularJS - dependency injectionAngularJS - dependency injection
AngularJS - dependency injection
 
AngularJS Project Setup step-by- step guide - RapidValue Solutions
AngularJS Project Setup step-by- step guide - RapidValue SolutionsAngularJS Project Setup step-by- step guide - RapidValue Solutions
AngularJS Project Setup step-by- step guide - RapidValue Solutions
 
AngularJS in practice
AngularJS in practiceAngularJS in practice
AngularJS in practice
 
Technozaure - Angular2
Technozaure - Angular2Technozaure - Angular2
Technozaure - Angular2
 
ChtiJUG - Introduction à Angular2
ChtiJUG - Introduction à Angular2ChtiJUG - Introduction à Angular2
ChtiJUG - Introduction à Angular2
 
Angularjs
AngularjsAngularjs
Angularjs
 
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
Universal JavaScript Web Applications with React - Luciano Mammino - Codemoti...
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)
 
AngularJS Best Practices
AngularJS Best PracticesAngularJS Best Practices
AngularJS Best Practices
 
Working with AngularJS
Working with AngularJSWorking with AngularJS
Working with AngularJS
 
AngularJs-training
AngularJs-trainingAngularJs-training
AngularJs-training
 
Developing New Widgets for your Views in Owl
Developing New Widgets for your Views in OwlDeveloping New Widgets for your Views in Owl
Developing New Widgets for your Views in Owl
 
Recap of Android Dev Summit 2018
Recap of Android Dev Summit 2018Recap of Android Dev Summit 2018
Recap of Android Dev Summit 2018
 
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
Zukunftssichere Anwendungen mit AngularJS 1.x entwickeln (GDG DevFest Karlsru...
 
You don't need DI
You don't need DIYou don't need DI
You don't need DI
 
Rohit android lab projects in suresh gyan vihar
Rohit android lab projects in suresh gyan viharRohit android lab projects in suresh gyan vihar
Rohit android lab projects in suresh gyan vihar
 
Refactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.jsRefactoring Large Web Applications with Backbone.js
Refactoring Large Web Applications with Backbone.js
 
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
Internal Android Library Management (DroidCon SF 2016, Droidcon Italy 2016)
 
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember DataIn The Trenches With Tomster, Upgrading Ember.js & Ember Data
In The Trenches With Tomster, Upgrading Ember.js & Ember Data
 

Similar to JavaScript code generator with Yeoman

An Introduction to Web Components
An Introduction to Web ComponentsAn Introduction to Web Components
An Introduction to Web Components
Red Pill Now
 
Voorhoede - Front-end architecture
Voorhoede - Front-end architectureVoorhoede - Front-end architecture
Voorhoede - Front-end architecture
Jasper Moelker
 
Protractor framework architecture with example
Protractor framework architecture with exampleProtractor framework architecture with example
Protractor framework architecture with example
shadabgilani
 
Play Framework on Google App Engine
Play Framework on Google App EnginePlay Framework on Google App Engine
Play Framework on Google App Engine
Fred Lin
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
Carsten Sandtner
 
mean stack
mean stackmean stack
mean stack
michaelaaron25322
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
OdessaJS Conf
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
Appium workshop technopark trivandrum
Appium workshop technopark trivandrumAppium workshop technopark trivandrum
Appium workshop technopark trivandrum
Syam Sasi
 
Pyramid patterns
Pyramid patternsPyramid patterns
Pyramid patterns
Carlos de la Guardia
 
How to Implement Micro Frontend Architecture using Angular Framework
How to Implement Micro Frontend Architecture using Angular FrameworkHow to Implement Micro Frontend Architecture using Angular Framework
How to Implement Micro Frontend Architecture using Angular Framework
RapidValue
 
Front End Development for Back End Developers - vJUG24 2017
Front End Development for Back End Developers - vJUG24 2017Front End Development for Back End Developers - vJUG24 2017
Front End Development for Back End Developers - vJUG24 2017
Matt Raible
 
Bootiful Development with Spring Boot and Angular - RWX 2018
Bootiful Development with Spring Boot and Angular - RWX 2018Bootiful Development with Spring Boot and Angular - RWX 2018
Bootiful Development with Spring Boot and Angular - RWX 2018
Matt Raible
 
Google Cloud Platform
Google Cloud Platform Google Cloud Platform
Google Cloud Platform
Francesco Marchitelli
 
Play with azure functions
Play with azure functionsPlay with azure functions
Play with azure functions
Baskar rao Dsn
 
Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017
Matt Raible
 
Enterprise Build And Test In The Cloud
Enterprise Build And Test In The CloudEnterprise Build And Test In The Cloud
Enterprise Build And Test In The Cloud
Carlos Sanchez
 
Sst hackathon express
Sst hackathon expressSst hackathon express
Sst hackathon express
Aeshan Wijetunge
 
AngularJs Crash Course
AngularJs Crash CourseAngularJs Crash Course
AngularJs Crash Course
Keith Bloomfield
 
Anatomy of an Addon Ecosystem - EmberConf 2019
Anatomy of an Addon Ecosystem - EmberConf 2019Anatomy of an Addon Ecosystem - EmberConf 2019
Anatomy of an Addon Ecosystem - EmberConf 2019
Lisa Backer
 

Similar to JavaScript code generator with Yeoman (20)

An Introduction to Web Components
An Introduction to Web ComponentsAn Introduction to Web Components
An Introduction to Web Components
 
Voorhoede - Front-end architecture
Voorhoede - Front-end architectureVoorhoede - Front-end architecture
Voorhoede - Front-end architecture
 
Protractor framework architecture with example
Protractor framework architecture with exampleProtractor framework architecture with example
Protractor framework architecture with example
 
Play Framework on Google App Engine
Play Framework on Google App EnginePlay Framework on Google App Engine
Play Framework on Google App Engine
 
Night Watch with QA
Night Watch with QANight Watch with QA
Night Watch with QA
 
mean stack
mean stackmean stack
mean stack
 
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
Maciej Treder ''Angular Universal - a medicine for the Angular + SEO/CDN issu...
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
Appium workshop technopark trivandrum
Appium workshop technopark trivandrumAppium workshop technopark trivandrum
Appium workshop technopark trivandrum
 
Pyramid patterns
Pyramid patternsPyramid patterns
Pyramid patterns
 
How to Implement Micro Frontend Architecture using Angular Framework
How to Implement Micro Frontend Architecture using Angular FrameworkHow to Implement Micro Frontend Architecture using Angular Framework
How to Implement Micro Frontend Architecture using Angular Framework
 
Front End Development for Back End Developers - vJUG24 2017
Front End Development for Back End Developers - vJUG24 2017Front End Development for Back End Developers - vJUG24 2017
Front End Development for Back End Developers - vJUG24 2017
 
Bootiful Development with Spring Boot and Angular - RWX 2018
Bootiful Development with Spring Boot and Angular - RWX 2018Bootiful Development with Spring Boot and Angular - RWX 2018
Bootiful Development with Spring Boot and Angular - RWX 2018
 
Google Cloud Platform
Google Cloud Platform Google Cloud Platform
Google Cloud Platform
 
Play with azure functions
Play with azure functionsPlay with azure functions
Play with azure functions
 
Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017Front End Development for Back End Developers - UberConf 2017
Front End Development for Back End Developers - UberConf 2017
 
Enterprise Build And Test In The Cloud
Enterprise Build And Test In The CloudEnterprise Build And Test In The Cloud
Enterprise Build And Test In The Cloud
 
Sst hackathon express
Sst hackathon expressSst hackathon express
Sst hackathon express
 
AngularJs Crash Course
AngularJs Crash CourseAngularJs Crash Course
AngularJs Crash Course
 
Anatomy of an Addon Ecosystem - EmberConf 2019
Anatomy of an Addon Ecosystem - EmberConf 2019Anatomy of an Addon Ecosystem - EmberConf 2019
Anatomy of an Addon Ecosystem - EmberConf 2019
 

Recently uploaded

How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?
ToXSL Technologies
 
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
gapen1
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
Remote DBA Services
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
Remote DBA Services
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
dakas1
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
ICS
 
Preparing Non - Technical Founders for Engaging a Tech Agency
Preparing Non - Technical Founders for Engaging  a  Tech AgencyPreparing Non - Technical Founders for Engaging  a  Tech Agency
Preparing Non - Technical Founders for Engaging a Tech Agency
ISH Technologies
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
Patrick Weigel
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
Peter Muessig
 
Lecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptxLecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptx
TaghreedAltamimi
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
Green Software Development
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
Alina Yurenko
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
kalichargn70th171
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
sjcobrien
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
Alberto Brandolini
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
Karya Keeper
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Julian Hyde
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
Rakesh Kumar R
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
Rakesh Kumar R
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
mz5nrf0n
 

Recently uploaded (20)

How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?How Can Hiring A Mobile App Development Company Help Your Business Grow?
How Can Hiring A Mobile App Development Company Help Your Business Grow?
 
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
如何办理(hull学位证书)英国赫尔大学毕业证硕士文凭原版一模一样
 
Oracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptxOracle 23c New Features For DBAs and Developers.pptx
Oracle 23c New Features For DBAs and Developers.pptx
 
Oracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptxOracle Database 19c New Features for DBAs and Developers.pptx
Oracle Database 19c New Features for DBAs and Developers.pptx
 
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
一比一原版(UMN毕业证)明尼苏达大学毕业证如何办理
 
Webinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for EmbeddedWebinar On-Demand: Using Flutter for Embedded
Webinar On-Demand: Using Flutter for Embedded
 
Preparing Non - Technical Founders for Engaging a Tech Agency
Preparing Non - Technical Founders for Engaging  a  Tech AgencyPreparing Non - Technical Founders for Engaging  a  Tech Agency
Preparing Non - Technical Founders for Engaging a Tech Agency
 
WWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders AustinWWDC 2024 Keynote Review: For CocoaCoders Austin
WWDC 2024 Keynote Review: For CocoaCoders Austin
 
UI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design SystemUI5con 2024 - Bring Your Own Design System
UI5con 2024 - Bring Your Own Design System
 
Lecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptxLecture 2 - software testing SE 412.pptx
Lecture 2 - software testing SE 412.pptx
 
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, FactsALGIT - Assembly Line for Green IT - Numbers, Data, Facts
ALGIT - Assembly Line for Green IT - Numbers, Data, Facts
 
All you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVMAll you need to know about Spring Boot and GraalVM
All you need to know about Spring Boot and GraalVM
 
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf8 Best Automated Android App Testing Tool and Framework in 2024.pdf
8 Best Automated Android App Testing Tool and Framework in 2024.pdf
 
Malibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed RoundMalibou Pitch Deck For Its €3M Seed Round
Malibou Pitch Deck For Its €3M Seed Round
 
Modelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - AmsterdamModelling Up - DDDEurope 2024 - Amsterdam
Modelling Up - DDDEurope 2024 - Amsterdam
 
Project Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdfProject Management: The Role of Project Dashboards.pdf
Project Management: The Role of Project Dashboards.pdf
 
Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)Measures in SQL (SIGMOD 2024, Santiago, Chile)
Measures in SQL (SIGMOD 2024, Santiago, Chile)
 
How to write a program in any programming language
How to write a program in any programming languageHow to write a program in any programming language
How to write a program in any programming language
 
What next after learning python programming basics
What next after learning python programming basicsWhat next after learning python programming basics
What next after learning python programming basics
 
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
在线购买加拿大英属哥伦比亚大学毕业证本科学位证书原版一模一样
 

JavaScript code generator with Yeoman

  • 2. Copyright © 2015 Accenture All rights reserved. 2 Tomi Vanek Senior technology architect by Accenture 25+ years of experience Current focus on modern web applications
  • 3. Copyright © 2015 Accenture All rights reserved. 3Credit: Flickr, photo by Cedward Bricehttps://www.youtube.com/watch?v=2nMD6sjAe8I#t=134
  • 4. Copyright © 2015 Accenture All rights reserved. 4
  • 5. Copyright © 2015 Accenture All rights reserved. 5 - name must be prefixed by generator-. - folder tree reflects available generators generator-angular | |__ package.json | |__ generators | |__ app | | |__ index.js | | | |__ controller | | |__ index.js | | | |__ directive | |__ index.js | |__ templates Initialization Interaction Configuration Generation Installation End
  • 6. Copyright © 2015 Accenture All rights reserved. 6 - name must be prefixed by generator-. - folder tree reflects available generators generator-angular | |__ package.json | |__ generators | |__ app | | |__ index.js | | | |__ controller | | |__ index.js | | | |__ directive | |__ index.js | |__ templates Initialization Interaction Configuration Generation Installation End
  • 7. Copyright © 2015 Accenture All rights reserved. 7 • Start with extending from • generators.Base for default generator • generators.NamedBase for sub-generator • Methods/functions are executed in the order they are defined • Private methods – use underscore or instance method • Execution phases: • Initializing • Prompting • Configuring • Default • Writing • Conflicts • Install • End Initialization Interaction Configuration Generation Installation End
  • 8. Copyright © 2015 Accenture All rights reserved. 8 • Start with extending from • generators.Base for default generator • generators.NamedBase for sub-generator • Methods/functions are executed in the order they are defined • Private methods – use underscore or instance method • Execution phases: • Initializing • Prompting • Configuring • Default • Writing • Conflicts • Install • End Initialization Interaction Configuration Generation Installation End
  • 9. Copyright © 2015 Accenture All rights reserved. 9 • Start with extending from • generators.Base for default generator • generators.NamedBase for sub-generator • Methods/functions are executed in the order they are defined • Private methods – use underscore or instance method • Execution phases: • Initializing • Prompting • Configuring • Default • Writing • Conflicts • Install • End Initialization Interaction Configuration Generation Installation End
  • 10. Copyright © 2015 Accenture All rights reserved. 10 • Start with extending from • generators.Base for default generator • generators.NamedBase for sub-generator • Methods/functions are executed in the order they are defined • Private methods – use underscore or instance method • Execution phases: • Initializing • Prompting • Configuring • Default • Writing • Conflicts • Install • End Initialization Interaction Configuration Generation Installation End
  • 11. Copyright © 2015 Accenture All rights reserved. 11 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, greetDeveloper: function() { this.log('Hello!'); }, createFiles: function() { }, end: function() { }, _helper: function() { } }); Initialization Interaction Configuration Generation Installation End
  • 12. Copyright © 2015 Accenture All rights reserved. 12 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, greetDeveloper: function() { this.log('Hello!'); }, createFiles: function() { }, end: function() { }, _helper: function() { } }); Initialization Interaction Configuration Generation Installation End
  • 13. Copyright © 2015 Accenture All rights reserved. 13 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, greetDeveloper: function() { this.log('Hello!'); }, createFiles: function() { }, end: function() { }, _helper: function() { } }); Initialization Interaction Configuration Generation Installation End
  • 14. Copyright © 2015 Accenture All rights reserved. 14 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, greetDeveloper: function() { this.log('Hello!'); }, createFiles: function() { }, end: function() { }, _helper: function() { } }); Initialization Interaction Configuration Generation Installation End
  • 15. Copyright © 2015 Accenture All rights reserved. 15 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, greetDeveloper: function() { this.log('Hello!'); }, createFiles: function() { }, end: function() { }, _helper: function() { } }); Initialization Interaction Configuration Generation Installation End
  • 16. Copyright © 2015 Accenture All rights reserved. 16 • Arguments • yo angular:controller admin var yg = require('yeoman-generator'); module.exports = yg.generators.NamedBase.extend({ constructor: function(args, options) { yg.generators.NamedBase.apply(this, arguments); }, displayName: function() { this.log(‘Creating ' + this.name + 'Ctrl.'); } }); Interaction Initialization Configuration Generation Installation End
  • 17. Copyright © 2015 Accenture All rights reserved. 17 • Arguments • yo angular:controller admin var yg = require('yeoman-generator'); module.exports = yg.generators.NamedBase.extend({ constructor: function(args, options) { yg.generators.NamedBase.apply(this, arguments); }, displayName: function() { this.log(‘Creating ' + this.name + 'Ctrl.'); } }); Interaction Initialization Configuration Generation Installation End
  • 18. Copyright © 2015 Accenture All rights reserved. 18 • Options • yo angular --coffee --skip-install var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, createFiles: function() { if (this.options['coffee']){ // use CoffeeScript templates } else { // use JavaScript templates } }, install: function() { if (this.options['skip-install']) { // don’t run installation } } }); Interaction Initialization Configuration Generation Installation End
  • 19. Copyright © 2015 Accenture All rights reserved. 19 • Options • yo angular --coffee --skip-install var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, createFiles: function() { if (this.options['coffee']){ // use CoffeeScript templates } else { // use JavaScript templates } }, install: function() { if (this.options['skip-install']) { // don’t run installation } } }); Interaction Initialization Configuration Generation Installation End
  • 20. Copyright © 2015 Accenture All rights reserved. 20 • Options • yo angular --coffee --skip-install var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); }, createFiles: function() { if (this.options['coffee']){ // use CoffeeScript templates } else { // use JavaScript templates } }, install: function() { if (this.options['skip-install']) { // don’t run installation } } }); Interaction Initialization Configuration Generation Installation End
  • 21. Copyright © 2015 Accenture All rights reserved. 21 // list ? What would you like to write scripts with?: > JavaScript CoffeeScript // checkbox ? Which modules would you like to include?: > (•) angular-animate.js ( ) angular-cookies.js (•) angular-route.js ( ) angular-touch.js // confirm ? Would you like to include Bootstrap?: (Y/n) // expand ? Overwrite bower.json?: (Ynaxdh) a >> overwrite this and all others Interaction Initialization Configuration Generation Installation End
  • 22. Copyright © 2015 Accenture All rights reserved. 22 • Prompts – via Inquirer.js • Asking questions • Parsing • Validation • Hierarchical prompts • Error handling • Available prompt types • List • Raw list • Checkbox • Confirm (y/n) • Expand • Input • Password Interaction Initialization Configuration Generation Installation End
  • 23. Copyright © 2015 Accenture All rights reserved. 23 askAboutAngularModules: function() { var ngModules = [{ value: 'ngAnimate', checked: true },{ value: 'ngResource', checked: false },{ value: 'ngCookies', checked: false }]; var cb = this.async(); this.prompt([ { type: 'checkbox’, name: ‘angularModules’, message: ‘Which modules would you like to include?’, choices: ngModules } ], function(answers) { this.angularModules = nswers.angularModules; cb() }.bind(this)); } Interaction Initialization Configuration Generation Installation End
  • 24. Copyright © 2015 Accenture All rights reserved. 24 askAboutAngularModules: function() { var ngModules = [{ value: 'ngAnimate', checked: true },{ value: 'ngResource', checked: false },{ value: 'ngCookies', checked: false }]; var cb = this.async(); this.prompt([ { type: 'checkbox’, name: ‘angularModules’, message: ‘Which modules would you like to include?’, choices: ngModules } ], function(result) { this.angularModules = result.angularModules; cb(); }.bind(this)); } Interaction Initialization Configuration Generation Installation End
  • 25. Copyright © 2015 Accenture All rights reserved. 25 askAboutAngularModules: function() { var ngModules = [{ value: 'ngAnimate', checked: true },{ value: 'ngResource', checked: false },{ value: 'ngCookies', checked: false }]; var cb = this.async(); this.prompt([ { type: 'checkbox’, name: ‘angularModules’, message: ‘Which modules would you like to include?’, choices: ngModules } ], function(answers) { this.angularModules = nswers.angularModules; cb() }.bind(this)); } Interaction Initialization Configuration Generation Installation End
  • 26. Copyright © 2015 Accenture All rights reserved. 26 • Storing user configuration and sharing it between sub-generators: • Source directory • Bootstrap • Routing option • SASS/LESS • HTML/Jade • Path to custom templates • etc. • Configuration Persistence - API • generator.config.save() • generator.config.set() • generator.config.get() • generator.config.getAll() • generator.config.delete() • generator.config.defaults() Interaction Configuration Initialization Generation Installation End
  • 27. Copyright © 2015 Accenture All rights reserved. 27 .yo-rc.json – yeoman configuration file { "generator-angular": { "srcDir": "src/client", "routing": "uiRouter", "bootstrap": true, "ngModules": [ "ngAnimate", "ngSanitize", "ngTouch" ], "extensions": ["js", "html"] }, "generator-node": { "srcDir": "src/server", "socketio": false, "oauth": true } } Interaction Configuration Initialization Generation Installation End
  • 28. Copyright © 2015 Accenture All rights reserved. 28 • Two location contexts: • sourceRoot • destinationRoot • File path is relative to location contexts • File utilities: • template(source, dest [, data]) • copy(source, dest) • dir(source, dest [, data]) • Template data – optional JS object • If not provided – properties of `this` are used • File conflict handling out of box ? Overwrite bower.json?: (Ynaxdh) a >> overwrite this and all others Interaction Configuration Generation Initialization Installation End
  • 29. Copyright © 2015 Accenture All rights reserved. 29 (function() { 'use strict'; angular .module('<%= moduleName %>') .directive('<%= name %>', [<%= name %>]); /* @ngInject */ function <%= name %> () { var directive = { restrict: 'EA', link: link,<% if (separateTemplate) { %> templateUrl: '<%= templateUrl %>‘ <% } else { %> template: '<div><%= name %></div>‘<% } %> }; return directive; function link(scope, element, attrs) { element.text('<%= name %>'); } } })(); Interaction Configuration Generation Initialization Installation End
  • 30. Copyright © 2015 Accenture All rights reserved. 30 (function() { 'use strict'; angular .module('<%= moduleName %>') .directive('<%= name %>', [<%= name %>]); /* @ngInject */ function <%= name %> () { var directive = { restrict: 'EA', link: link,<% if (separateTemplate) { %> templateUrl: '<%= templateUrl %>‘ <% } else { %> template: '<div><%= name %></div>‘<% } %> }; return directive; function link(scope, element, attrs) { element.text('<%= name %>'); } } })(); Interaction Configuration Generation Initialization Installation End
  • 31. Copyright © 2015 Accenture All rights reserved. 31 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); this.sourceRoot('../templates'); this.destinationRoot('.'); this.appName = 'myApp'; }, configFiles: function() { this.copy('_editorconfig', '.editorconfig'); this.dir('code-analysis', '.'); this.dir('pkg-conf', '.', {name: 'demo'}); }, appModule: function() { this.template('module/module.js_', 'src/client/app/app.module.js'); this.template('controller/ctrl.js_', 'src/client/app.controller.js', {name: 'MyAppCtrl', appName: 'myApp')}; } }); Interaction Configuration Generation Initialization Installation End
  • 32. Copyright © 2015 Accenture All rights reserved. 32 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); this.sourceRoot('../templates'); this.destinationRoot('.'); this.appName = 'myApp'; }, configFiles: function() { this.copy('_editorconfig', '.editorconfig'); this.dir('code-analysis', '.'); this.dir('pkg-conf', '.', {name: 'demo'}); }, appModule: function() { this.template('module/module.js_', 'src/client/app/app.module.js'); this.template('controller/ctrl.js_', 'src/client/app.controller.js', {name: 'MyAppCtrl', appName: 'myApp')}; } }); Interaction Configuration Generation Initialization Installation End
  • 33. Copyright © 2015 Accenture All rights reserved. 33 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); this.sourceRoot('../templates'); this.destinationRoot('.'); this.appName = 'myApp'; }, configFiles: function() { this.copy('_editorconfig', '.editorconfig'); this.dir('code-analysis', '.'); this.dir('pkg-conf', '.', {name: 'demo'}); }, appModule: function() { this.template('module/module.js_', 'src/client/app/app.module.js'); this.template('controller/ctrl.js_', 'src/client/app.controller.js', {name: 'MyAppCtrl', appName: 'myApp')}; } }); Interaction Configuration Generation Initialization Installation End
  • 34. Copyright © 2015 Accenture All rights reserved. 34 var yg = require('yeoman-generator'); module.exports = yg.generators.Base.extend({ constructor: function(args, options) { yg.generators.Base.apply(this, arguments); this.sourceRoot('../templates'); this.destinationRoot('.'); this.appName = 'myApp'; }, configFiles: function() { this.copy('_editorconfig', '.editorconfig'); this.dir('code-analysis', '.'); this.dir('pkg-conf', '.', {name: 'demo'}); }, appModule: function() { this.template('module/module.js_', 'src/client/app/app.module.js'); this.template('controller/ctrl.js_', 'src/client/app.controller.js', {name: 'MyAppCtrl', appName: 'myApp')}; } }); Interaction Configuration Generation Initialization Installation End
  • 35. Copyright © 2015 Accenture All rights reserved. 35 • Yeoman runs npm & bower install for you • Spawn CLI commands • Execute in 'install' or 'end' running context _skippedInstl: function() { if (this.options['skip-install']) { this.log('Run npm install & bower install'); } else { this.spawnCommand('grunt', ['wiredep']); } }, end: function() { this.installDependencies({ skipInstall: this.options['skip-install'], skipMessage: this.options['skip-message'], callback: this._skippedInstl.bind(this) }); } Interaction Configuration Generation Initialization Installation End
  • 36. Copyright © 2015 Accenture All rights reserved. 36 • Yeoman runs npm & bower install for you • Spawn CLI commands • Execute in 'install' or 'end' running context _skippedInstl: function() { if (this.options['skip-install']) { this.log('Run npm install & bower install'); } else { this.spawnCommand('grunt', ['wiredep']); } }, end: function() { this.installDependencies({ skipInstall: this.options['skip-install'], skipMessage: this.options['skip-message'], callback: this._skippedInstl.bind(this) }); } Interaction Configuration Generation Initialization Installation End
  • 37. Copyright © 2015 Accenture All rights reserved. 37 • Yeoman runs npm & bower install for you • Spawn CLI commands • Execute in 'install' or 'end' running context _skippedInstl: function() { if (this.options['skip-install']) { this.log('Run npm install & bower install'); } else { this.spawnCommand('grunt', ['wiredep']); } }, end: function() { this.installDependencies({ skipInstall: this.options['skip-install'], skipMessage: this.options['skip-message'], callback: this._skippedInstl.bind(this) }); } Interaction Configuration Generation Initialization End Installation
  • 38. Copyright © 2015 Accenture All rights reserved. 38 Short summary of the result Next manual steps (i.e. on –skip-installation) After running `npm install` & `bower install`, inject your front end dependencies into your source code by running: grunt wiredep Interaction Configuration Generation Initialization Installation End
  • 39. Copyright © 2015 Accenture All rights reserved. 39 Short summary of the result Next manual steps (i.e. on –skip-installation) After running `npm install` & `bower install`, inject your front end dependencies into your source code by running: grunt wiredep Interaction Configuration Generation Initialization Installation End
  • 40. Copyright © 2015 Accenture All rights reserved. 40 Unit Tests • Put each tested type of generator into separate describe block • Mock user interaction and run generator in before block • Test assertions in the it block describe('angular generator', function() { before(function(done) { // run tested generator done(); }); describe('should generate following files', function() { it('bower.json', function() { // assert the file exits // assert correct file content }); it('package.json', function() { }); }); });
  • 41. Copyright © 2015 Accenture All rights reserved. 41 Unit Tests • Put each tested type of generator into separate describe block • Mock user interaction and run generator in before block • Test assertions in the it block describe('angular generator', function() { before(function(done) { // run tested generator done(); }); describe('should generate following files', function() { it('bower.json', function() { // assert the file exits // assert correct file content }); it('package.json', function() { }); }); });
  • 42. Copyright © 2015 Accenture All rights reserved. 42 Unit Tests • Put each tested type of generator into separate describe block • Mock user interaction and run generator in before block • Test assertions in the it block describe('angular generator', function() { before(function(done) { // run tested generator done(); }); describe('should generate following files', function() { it('bower.json', function() { // assert the file exits // assert correct file content }); it('package.json', function() { }); }); });
  • 43. Copyright © 2015 Accenture All rights reserved. 43 Unit Tests describe('angular generator', function() { before(function(done) { helpers.run(path.join(__dirname, '../generators/app') .inDir(path.join(__dirname, './temp'), function(dir) { }) .withArguments([]), .withOptions({'coffee': false}), .withPrompts({'bootstrap': true, 'routing': 'uiRouter'}) .on('ready', function(generator) { generator.on('start', yoOutput.mute); }) .on('end', function() { yoOutput.unmute(); done(); }); }); describe('should generate following files', function() { // test the assertions }); });
  • 44. Copyright © 2015 Accenture All rights reserved. 44 Unit Tests describe('angular generator', function() { before(function(done) { helpers.run(path.join(__dirname, '../generators/app') .inDir(path.join(__dirname, './temp'), function(dir) { }) .withArguments([]), .withOptions({'coffee': false}), .withPrompts({'bootstrap': true, 'routing': 'uiRouter'}) .on('ready', function(generator) { generator.on('start', yoOutput.mute); }) .on('end', function() { yoOutput.unmute(); done(); }); }); describe('should generate following files', function() { // test the assertions }); });
  • 45. Copyright © 2015 Accenture All rights reserved. 45 Unit Tests describe('angular generator', function() { before(function(done) { helpers.run(path.join(__dirname, '../generators/app') .inDir(path.join(__dirname, './temp'), function(dir) { }) .withArguments([]), .withOptions({'coffee': false}), .withPrompts({'bootstrap': true, 'routing': 'uiRouter'}) .on('ready', function(generator) { generator.on('start', yoOutput.mute); }) .on('end', function() { yoOutput.unmute(); done(); }); }); describe('should generate following files', function() { // test the assertions }); });
  • 46. Copyright © 2015 Accenture All rights reserved. 46 Unit Tests describe('angular generator', function() { before(function(done) { // run tested generator done(); }); describe('should generate following files', function() { it('bower.json', function() { // assert the file exits assert.file('bower.json'); // assert correct file content assert.fileContent('bower.json', /bootstrap/); assert.noFileContent('bower.json', /angular-route/); }); it('package.json', function() { }); }); });
  • 47. Copyright © 2015 Accenture All rights reserved. 47 Unit Tests describe('angular generator', function() { before(function(done) { // run tested generator done(); }); describe('should generate following files', function() { it('bower.json', function() { // assert the file exits assert.file('bower.json'); // assert correct file content assert.fileContent('bower.json', /bootstrap/); assert.noFileContent('bower.json', /angular-route/); }); it('package.json', function() { }); }); });
  • 48. Copyright © 2015 Accenture All rights reserved. 48 Modularization • Subgenerators this.composeWith('angular:controller', { arguments: ['admin'], options: {'matchingView': false} } }; • External generators this.composeWith('karma', {}, { local: require.resolve('generator-karma') } }; • Shared templates and utilities
  • 49. Copyright © 2015 Accenture All rights reserved. 49 Modularization • Subgenerators this.composeWith('angular:controller', { arguments: ['admin'], options: {'matchingView': false} } }; • External generators this.composeWith('karma', {}, { local: require.resolve('generator-karma') } }; • Shared templates and utilities
  • 50. Copyright © 2015 Accenture All rights reserved. 50 Modularization • Subgenerators this.composeWith('angular:controller', { arguments: ['admin'], options: {'matchingView': false} } }; • External generators this.composeWith('karma', {}, { local: require.resolve('generator-karma') } }; • Shared templates and utilities
  • 51. Copyright © 2015 Accenture All rights reserved. 51 • Enterprise IT, BPM, B2B • DevOps • API, WS • Language, DSL • Model-Driven Development • Runtime Code Generation • Scaffold • Project Seed • Framework, Platform, SDK • Runtime Module, Component, Library • Copy-Paste • Hand-Written Code Scaffolding in Model-Driven Architecture
  • 52. Copyright © 2015 Accenture All rights reserved. 52 • Asynchronous callbacks in conditional execution • Post-write to files • OS-specific path • Naming • Simplicity vs rich configurability Pitfalls
  • 53. Copyright © 2015 Accenture All rights reserved. 53 Questions Scaffolding in JavaScript Yeoman code generator tomi vanek software architect

Editor's Notes

  1. Steve Jobs in an TV interview: Scientists measured efficiency in locomotion of animals. Condor won, human was in the down third of the list. Efficiency of human riding bicycle - blown away all the animals. Humans are tool makers. Computer is bicycle of our mind.
  2. Yeoman: scaffolding tool for modern web apps Inspired by scaffolding in Ruby. Yeoman helps you kick start new projects, prescribing best practices and tools to help you stay productive. The Yeoman workflow is comprised of three types of tools for improving your productivity and satisfaction when building a web app: the scaffolding tool (yo), the build tool (Grunt, Gulp, etc) and the package manager (like Bower and npm).
  3. 1. A generator is, at its core, a Node.js module. 2. First, create a folder within which you'll write your generator. This folder must be named generator-name (where name is the name of your generator). This is important, as Yeoman relies on the file system to find available generators. 3. Yeoman is deeply linked to the file system and to how you structure your directory tree. Each sub-generator is contained within its own folder.
  4. 1. A generator is, at its core, a Node.js module. 2. First, create a folder within which you'll write your generator. This folder must be named generator-name (where name is the name of your generator). This is important, as Yeoman relies on the file system to find available generators. 3. Yeoman is deeply linked to the file system and to how you structure your directory tree. Each sub-generator is contained within its own folder.
  5. Yeoman offers base generators which you can extend to implement your own behavior. These base generators will add most of the functionality you'd expect to ease your task. Each method directly attached to a Generator prototype is considered to be an action. Each action is run in sequence by the Yeoman environment run loop. Helper and private methods - Prefix method name by an underscore, Use instance methods, Extend a parent generator The run loop is a queue system with priority support. Available priorities are: initializing, prompting, configuring, default, writing, conflicts, install, end
  6. By default Yeoman runs on a terminal, but it also supports custom user interfaces that different tools can provide. For example, nothing prevents a Yeoman generator from being run inside of a graphical tool like an editor or a standalone app. Arguments are passed directly from the command line
  7. Options look a lot like arguments, but they are written as command line flags.
  8. Prompts are the main way a generator interacts with a user. Inquirer.js - A collection of common interactive command line user interfaces. Inquirer should ease the process of asking end user questions, parsing, validating answers, managing hierarchical prompts and providing error feedback. Available prompt types: list, rawlist, checkbox, confirm, expand, input, password
  9. Storing user configuration options and sharing them between sub-generator is a common task. For example, it is common to share preferences like the language (does the user use CoffeeScript?), style options (indenting with spaces or tabs), etc. These configuration can be stored in the .yo-rc.json file through the Yeoman Storage API. This API is accessible through the generator.config object. The .yo-rc.json file is also determining the root of a project. The .yo-rc.json file is a JSON file where configuration objects from multiple generators are stored. Each generator configuration is namespaced to ensure no naming conflicts will occur between generators. This also mean each generator configuration is sandboxed and can only be shared between sub-generators. You cannot share configuration between different generator using the storage API. Use options and arguments during invocation to share data between different generators.
  10. Yeoman file utilities are based on the idea you always have two location contexts on disk. These contexts are important as most file utility methods will act on file path relative to these contexts.
  11. Once you've run your generators, you'll often want to run npm and Bower to install any additional dependencies your generators require. Yeoman provides an abstraction to allow users to spawn any CLI commands. This abstraction will normalize to command so it can run seamlessly in Linux, Mac and Windows system.
  12. 1. Usually the best way to organize your tests is to separate each generator and sub-generator into its own describe block. Then, add a describe block for each option your generator accept. And then, use an it block for each assertion (or related assertion). 2. The code running the generator should be located in a before or beforeEach block - it usually does not belong to your assertions.
  13. Yeoman offers multiple ways for generators to build upon common ground. There's no sense in rewriting the same functionality, so an API is provided to use generators inside other generators.