自定义生成器
概述
要说Sails中哪个可以自动化重复工作来让你编程更加容易的话那非Generator莫属。Generators可以在你的Sails工程中使用命令行通过模板自动生成一些文件。实际上,Sails内核使用generators来创建Sails工程。所以当你输入:
~/ $ sails new myProject
...sails便会使用generators来构建一个有初始目录结构的Sails app,结构如下:
myProject
|_api
|_assets
|_config
|_node_modules
|_tasks
|_views
.gitignore
.sailsrc
app.js
Gruntfile.js
package.json
README.md
在Sails内核中generators的其他例子:
- sails-generate-adapter
- sails-generate-backend
- sails-generate-controller
- sails-generate-frontend
- sails-generate-model
- sails-generate-new
- sails-generate-views
- sails-generate-views-jade
- 虽然不是一个独立的模块,但是可以通过
sails generate api
访问其他的generators
为了开始生成一个生成器的过程你可以使用sails-generate-generator
。
注意:通过调用generators来创建一个generators的想法看起来像是疯狂的无限循环但是请不要怀疑这种做法,因为它不会创建一个虫洞到另外一个邪恶的世界的。
创建一个生成器
首先我们需要一个Sails工程。如果你还没有创建那么可以在你的终端输入:
~/ $ sails new myProject
cd
进myProject
或者任何已经存在的Sails工程然后在命令行中创建一个名为awesome的generator:
~/ $ sails generate generator awesome
如果你看到提示:info: Created a new generator!
,那说明generator已经创建成功了。
使能一个生成器
为了使能generator你需要通过\myProject\.sailsrc
来告诉Sails。如果你正在使用一个已存在的生成器那么你将会在.sailsrc
中链接到一个npm模块然后使用npm install
安装它。因为你正在开发一个生成器,所以你可以直接地链接。为了创建链接请回到终端然后cd
进入awesome
generator文件夹并输入:
~/ $ pwd
pwd
命令将会返回一个完整的generator的文件夹路径(比如:/Users/irl/sails_projects/myProject/awesome
)。
拷贝该路径然后打开myProject/.sailsrc
。在modules
属性中添加awesome
关键词并粘贴刚才复制的awesome
generator路径。
注意:你可以命名generator为任意你想要的名字,现在我们只是假设为
awesome
:
{
"generators": {
"modules": {
"awesome": "/Users/irl/sails_projects/myProject/awesome"
}
}
}
注意:你在
.sailsrc
文件中命名的generator的名字将会用在终端命令行中执行。
最后,你需要在终端中做一个npm install
,这是为了安装那些添加到生成器的package.json
需要的模块。
使用生成器
回到终端并输入:sails generate awesome example
。让我们看看这会生成些什么。
Generator会创建些什么?
使用文本编辑器打开你的工程,你会注意到有一个新创建的文件夹叫做hey_look_a_folder
,并且还有一个名为example
的文件:
/**
* This is just an example file created at Wed Jun 04 2014 17:35:59 GMT-0500 (CDT).
*
* You can use underscore templates, see?
*/
module.exports = function () {
// ...
};
这个文件夹和文件表明了generator的强大,因为它不仅创建了元素而且还使用命令行中的arguments
来影响文件的内容。比如,文件名称--example
,使用了命令行参数sails generate awesome example
的一个元素。
基本的生成器配置
所有有关awesome
generator的配置都包含在\myProjects\awesome\Generator.js
。Generator.js
的主要部分是before()
函数和targets
目录。
注意:我们指的是使用
{}
作为一个目录的JavaScript对象。
配置before()函数
让我们仔细查看myProject/awesome/Generator.js
文件:
...
before: function (scope, cb) {
// scope.args are the raw command line arguments.
if (!scope.args[0]) {
return cb( new Error('Please provide a name for this awesome.') );
}
// scope.rootPath is the base path for this generator
if (!scope.rootPath) {
return cb( INVALID_SCOPE_VARIABLE('rootPath') );
}
// Attach defaults
_.defaults(scope, {
createdAt: new Date()
});
// Decide the output filename for use in targets below:
scope.filename = scope.args[0];
// Add other stuff to the scope for use in our templates:
scope.whatIsThis = 'an example file created at '+scope.createdAt;
// When finished, we trigger a callback with no error
// to begin generating files/folders as specified by
// the `targets` below.
cb();
},
...
每个generator都可以访问到scope
目录,该目录在generator被执行的时候你想要获取参数的时候有用。
如果你的默认awesome
generator是一个新的关键词,createdAt:
在scope中被创建。我们临时看一下某个模板的这个字段:
...
// Attach defaults
_.defaults(scope, {
createdAt: new Date()
});
...
接下去,当执行awesome
generator(比如sails generate awesome <theargument>
)的时候,scope.arg
中参数数组是可用的。在我们默认的awesome
generator,属性filename
被添加到scope
中并为scope.arg
数组中的第一个元素的值赋值。比如:
...
scope.filename = scope.args[0];
...
最后,另外一个属性(比如scope.whatIsThis)也被添加到scope
目录。
...
scope.whatIsThis = 'an example file created at '+scope.createdAt;
...
配置目标目录
现在我们仔细查看myProject\awesome\Generator.js
中的targets
字段来更好理解这个文件夹(比如hey_look_a_folder)和文件(比如example)是怎样生成的。
...
targets: {
// Usage:
// './path/to/destination.foo': { someHelper: opts }
// Creates a dynamically-named file relative to `scope.rootPath`
// (defined by the `filename` scope variable).
//
// The `template` helper reads the specified template, making the
// entire scope available to it (uses underscore/JST/ejs syntax).
// Then the file is copied into the specified destination (on the left).
'./:filename': { template: 'example.template.js' },
// Creates a folder at a static path
'./hey_look_a_folder': { folder: {} }
},
...
·template和
folder`辅助者看起来很像路由。这些辅助者执行的操作就像它们的名字一样。
template helper
对template辅助者基于一个模板创建一些文件一点儿也不会感到惊讶。记住,模板中是可以访问到scope
字段的。
...
'./:filename': { template: 'example.template.js' },
...
左手边的参数指定了路径和文件名称,而右边参数则是表明generator会使用哪个模板去创建文件。注意你在before
函数中的scopre.args
的第一个参数中的scope.filename
中使用filename
。这个模板可以在myProject\awesome\templates
可以找到。在awesome
generator你正在使用example.template.js
:
/**
* This is just <%= whatIsThis %>.
*
* You can use underscore templates, see?
*/
module.exports = function () {
// ...
};
注意:在属性scope中的
whatIsThis
是作为你重新调用使用的createdAt:属性在before
函数中创建。
folder helper
folder辅助者用来生成文件夹。
...
'./hey_look_a_folder': { folder: {} }
...
左手边的参数指定了路径和文件名称,而右边参数指定任何可选地参数。比如,默认,如果在那个位置中已经存在一个文件夹,那么将会出现一个错误:Something else already exists at ::<path of folder>
。如果你想要generator去重写覆盖一个已经存在的文件夹你有两种方法:你可以在选项参数中通过指定force:true
来让folder辅助者覆盖一个已经存在的文件夹:
...
'./hey_look_a_folder': { folder: { force: true} }
...
你也可以在命令行中执行generator的时候使用--force
参数来配置所有的辅助者覆盖已经存在的文件夹:
~/ $ sails generate awesome test --force
在一个生成器中使用一个生成器
为了利用其它编程者的劳动成果,generators可以被其它的generators使用。这就是传递给所有的generators的scope
字段的强大之处。
比如,Sails内核有一个叫做sails-generate-model
的生成器。因为它是内建到Sails内核的,所以无需安装。将它添加到我们的awesome生成器是很容易的。在myProject\awesome\Generator.js
通过插入./': ['model']
来包含它:
...
targets: {
// './:filename': { template: 'example.template.js' },
'./': ['model'],
// './hey_look_a_folder': { folder: {} }
},
...
注意:通过使用
./
作为路径,生成器被执行的任何文件夹中的的任何模型都会被放在在\api\models
文件夹中。
就是这么简单!现在我们在awesome生成器中创建一个模型。在终端中输入:
~/ $ sails generate awesome user name:string email:email
如果你查看了myProject\api\models
那么你将会看到一个新的文件叫做User.js
已经被创建了并且包含了之前指定的模型属性:
/**
* User
*
* @description :: TODO: You might write a short summary of how this model works and what it represents here.
* @docs :: http://sailsjs.org/#!documentation/models
*/
module.exports = {
attributes: {
name : { type: 'string' },
email : { type: 'email' }
}
};
福利:发布你的生成器到npmjs.org
为了发布awesome生成器到npmjs.org,请进入myProject\awesome\package.json
文件然后改变它的文件名、作者和其他基本的信息(比如许可证)。
从myProject\awesome
文件夹中在终端输入:
~/ $ npm publish
注意:如果你还没有一个NPM账号,可以到(npmjs.org)[https://www.npmjs.org/]中创建一个
想要取消发布某个模块可以输入:
~/ $ npm unpublish` --force
改变myProject\.sailsrc
为:
{
"generators": {
"modules": {
"awesome": "whatever you named the module in package.json"
}
}
}
从awesome generator文件中在终端输入:
~/ $ npm install