摘要
随着 Web 2.0 和 HTML 5 的流行,现在的 Web 应用所能提供的功能和交互能力比之前传统的 Web 应用要强大很多。应用的很多实现逻辑被转移到了浏览器端来实现。浏览器不再只提供单一的数据接收和展现功能,而是提供更多的用户交互能力。浏览器端所包含的 HTML、CSS 和 JavaScript 代码也变得更加复杂。对于日益复杂的前端代码,需要有更好的流程和工具来管理开发的各个方面,包括初始的代码结构、开发流程和自动化测试等。 是一个新兴的工具。它结合了 Yo、Grunt 和 Bower 等工具,组成了一个完整的工具集合,提供各种 Web 应用开发中所需的实用功能。
正文
1. yeoman
可以帮助我们创建新的开发项目,为我们提供更好的工具来使我们的项目更多样化。
2. yeoman-generator
是yeoman生态系统的积木,是通过yo命令运行而为终端用户生产文件的插件。
3. 构建创建自己的generator
1. 创建 node module
{
"name": "generator-name",
"version": "0.1.0",
"description": "",
"files": [
"app",
"router"
],
"keywords": ["yeoman-generator"],
"dependencies": {
"yeoman-generator": "^0.20.2"
}
}
其中 name 属性必须以generator-前缀。keywords 属性必须包含"yeoman-generator" 并且repo必须有一个引用索引的描述。
你必须保证引用了最新版本的yeoman-generator 模块作为依赖.可以通过 npm install --save yeoman-generator来实现。
2.目录树
下面是示例项目的文件夹结构
├───package.json
├───app/
│ └───index.js
└───router/
└───index.js
通过命令 yo name 和 yo name:router 可以显示出来generator。
所以前一个示例的结构也可用定义成如下:
├───package.json
└───generators/
├───app/
│ └───index.js
└───router/
└───index.js
{
"files": [
"generators/app",
"generators/router"
]
}
3. 扩展generator
当到了这一步你就可用去实现generator的具体内容了
yeoman提供了一个基础的generator让我们扩展使用以实现自己的目标.基础的generator提供了大部分的功能来缓解你的任务量。
下面是扩展基础generator的方法:
var generators = require('yeoman-generator');
module.exports = generators.Base.extend();
extend 允许你在基础的class上扩展新的自己想要的prototype规范.他的功能是通过模块得来的。如果你用过backbone,你会觉得他很熟悉。在生态系统中,我们指定扩展的generator使用module.export来让其有效,就像
4. 重写constructor方法
有些generator方法只有定义在构造方法内才能被调用到.这些特殊的方法可以做的一些重要的操作等,而这些操作可能在构造之外无法正常运行。
module.exports = generators.Base.extend({
// The name `constructor` is important here
constructor: function () {
// Calling the super constructor is important so our generator is correctly set up
generators.Base.apply(this, arguments);
// Next, add your custom code
this.option('coffee'); // This method adds support for a `--coffee` flag
}
});
5. 添加自定义方法
当generator被调用时,通常情况下里面定义的方法会按照顺序执行,但是我们将在下一节中看到的,一些特殊的方法名称将触发特定的运行秩序。
下面的一段代码是创建两个自定义的方法
module.exports = generators.Base.extend({
method1: function () {
console.log('method 1 just ran');
},
method2: function () {
console.log('method 2 just ran');
}
});
当运行generator 你会看到会用log打印出来。
6. 运行generator
7.找到工程根目录
4. 完善generator
1.创建用户交互
我们推荐在prompting 方法内来定义prompt与用户交互,定义方法如下:
module.exports = generators.Base.extend({
prompting: function () {
return this.prompt([{
type : 'input',
name : 'name',
message : 'Your project name',
default : this.appname // Default to current folder name
}, {
type : 'confirm',
name : 'cool',
message : 'Would you like to enable the Cool feature?'
}]).then(function (answers) {
this.log('app name', answers.name);
this.log('cool feature', answers.cool);
}.bind(this));
}
})
2. 运行上下文
在generator内,所有的静态方法都会被作为action而自定执行,当然generator也提供了可以声明不自动执行的辅助函数,generator提供了三种可以创建辅助函数的方法.
1 通过下划线开头定义函数,如:CopyFiles
2 使用实例函数声明:
generators.Base.extend({
constructor: function () {
this.helperMethod = function () {
console.log('won\'t be called automatically');
};
}
});
3 继承一个父级generator:
var MyBase = generators.Base.extend({
helper: function () {
console.log('methods on the parent generator won\'t be called automatically');
}
});
module.exports = MyBase.extend({
exec: function () {
this.helper();
}
});
3.运行顺序
运行顺序
Yeoman是按照优先级顺序依次执行所定义的方法。当你定义的函数名字是Yeoman定义的优先级函数名时,会自动将该函数列入到所在优先级队列中,否则就会列入到 default 优先层级队列中。
基本上执行的顺序如下:
initializing
prompting
configuring
default
writing
conflicts
install
end
4.generator Arguments
Arguments是在命令行中直接传递的。 如:yo webapp my-project,接受键值对的条件。
desc:描述argument
required:定义是否必须
optional:是否可选择的
type:参数类型,支持的类型有String Number Array Object
defaults: argument默认值
banner:字符串显示的使用说明(这是默认提供)
注意:参数必须的定义在construct函数内,否则当你使用generator调用命令(如:yo webapp --help)的时候,不能够输出相关的帮助信息。
示例:
var _ = require('lodash');
module.exports = generators.Base.extend({
// note: arguments and options should be defined in the constructor.
constructor: function () {
generators.Base.apply(this, arguments);
// This makes `appname` a required argument.
this.argument('appname', { type: String, required: true });
// And you can then access it later on this way; e.g. CamelCased
this.appname = _.camelCase(this.appname);
}
});
5. Options
option和argument很相似,但是option是作为命令行标识使用的,如yo webapp --coffee。
我们可可以通过generator.option()添加option。
示例:
module.exports = generators.Base.extend({
// note: arguments and options should be defined in the constructor.
constructor: function () {
generators.Base.apply(this, arguments);
// This method adds support for a `--coffee` flag
this.option('coffee');
// And you can then access it later on this way; e.g.
this.scriptSuffix = (this.options.coffee ? ".coffee": ".js");
}
});
6. 输出消息
输出消息是通过generator.log模块来处理实现的。不建议使用console.log输出命令。
示例:
module.exports = generators.Base.extend({
myAction: function () {
this.log('Something has gone wrong!');
}
});
7. 处理依赖关系
一般当你运行你的generator的时候,你经常需要通过 和 来安装一些generator用到的依赖模块。而这些任务是非常繁琐的,为了方便,yeoman将这部分任务抽离了出来。
npm
你只需要调用generator.npmInstall() 命令就可以执行npm安装命令,yeoman确保了npm install只执行了一次,即使他被多个generator调用。
例如你想安装lodash作为dev dependency:
generators.Base.extend({
installingLodash: function() {
this.npmInstall(['lodash'], { 'saveDev': true });
}
});
上面代码等同于调用了npm install lodash --save-dev命令。
Bower
你只需要调用generator.bowerInstall()即可启动安装命令。yeoman确保了bower install只执行了一次,即使他被多个generator调用。
npm && Bower
调用enerator.installDependencies()即可同时运行npm 和 bower。
其他tools
yeoman抽离了spawn命令,这个抽离保证了我们可以在Linux ,mac 以及windows系统上可以很好的运行。
假如你是一个PHP狂热爱好者,你想运行composer命令,你可以这样做:
generators.Base.extend({
install: function () {
this.spawnCommand('composer', ['install']);
}
});
请确保面spawn命令在install队列里。因为您的用户不愿意等待在那儿直到安装命令完成。
8. 上下文路径
为了方便文件流的输入输出,Yeoman使用两种位置环境。
1. 目标上下文
你可以通过generator.destinationRoot()命令获取目标路径,也可以通过generator.destinationPath('sub/path')来拼一个路径:
// Given destination root is ~/projects
generators.Base.extend({
paths: function () {
this.destinationRoot();
// returns '~/projects'
this.destinationPath('index.js');
// returns '~/projects/index.js'
}
});
2. 模板上下文
generators.Base.extend({
paths: function () {
this.sourceRoot();
// returns './templates'
this.templatePath('index.js');
// returns './templates/index.js'
}
});
3. “内存”文件系统
当涉及到覆盖用户的文件的时候,yeoman非常的谨慎,基本上,每一个write动作都是一个为已经存在的文件解决冲突的过程。帮助用户严重需要覆盖的内容。
4. 文件工具
generator的this.fs暴露出所有的文件方法,通过.
其他相关介绍请看
9.完整示例
'use strict';
var generators = require('yeoman-generator');
var mkdirp = require('mkdirp');
var yosay = require('yosay');
var chalk = require('chalk');
module.exports = generators.Base.extend({
constructor: function() {
generators.Base.apply(this, arguments);
this.option('coffee');
this.scriptSuffix = (this.options.coffee ? ".coffee": ".js");
},
initializing: function() {
var message = chalk.bgBlack.bold('\nWelcome to webApp\n') + chalk.underline('webApp.github.io\n');
this.log(yosay(message));
},
prompting: function() {
var prompts = [{
type:'input',
name: 'appName',
message: 'input app name .',
default: 'webApp'
}];
this.prompt(prompts, function (answers) {
this.log(answers);
}.bind(this));
},
configuring: function() {
this.config.save();
},
selfFunction: function () {
this.log("执行了自定义方法");
},
writing: function() {
this.fs.copyTpl(
this.templatePath('index.html'),
this.destinationPath('public/index.html'),
{ title: 'Templating with Yeoman' }
);
},
});
作者信息
原文链接:
翻译自力谱宿云 LeapCloud 团队_UX成员:Jerry Zhang
力谱宿云 LeapCloud 团队首发:
欢迎关注微信订阅号:从移动到云端
欢迎加入我们的力谱宿云 LeapCloud 活动QQ群:555973817,我们将不定期做技术分享活动。
若有转载需要,请转发时注意自带作者信息一栏并本自媒体公号:力谱宿云,尊重原创作者及译者的劳动成果~ 谢谢配合~