什么是Plop
plop是一个小型的脚手架,可以通过命令行去生成、处理文件模板代码等.
不过plop不会独立使用,一般都会把plop集成到项目中用来创建同类型的项目文件.
如果项目的很多模块的结构骨架都非常相似,引入模版内容相同就可以使用Plop来实现自动化了,Plop旨在根据模板文件自动化创建组件.
plop的基本使用
npm install plop
如果没有全局安装,要在package.json中的script中增加脚本命令:
"scripts": { "plop": "plop" },
创建路由Generator
在根目录创建plop-templates用于存放各种模板
创建一个router目录作为路由的generator,并创建generator的js文件和hbs模板
prompt.js文件来定义脚手架任务
// Plop 入口文件,需要导出一个函数
// 此函数接收一个plop对象,用于创建生成器函数
module.exports = {
description: 'table-temp', //描述这个generate的作用
prompts: [
{
type: 'input', // 问题的类型
name: 'pathName', // 问题对应得到答案的变量名,可以在acitons中使用该变量
message: '文件名称', // 在命令行中的问题
},
],
actions: (data) => {
// 这里可以通过data获取输入的pathname
let name = data.pathName.split('/');
name = name[name.length - 1];
name[0] = name[0].toLocaleUpperCase();
const actions = [
{
type: 'add', // 操作类型 添加文件
path: `src/views/temp/${data.pathName}.vue`, //添加的文件的路径
templateFile: 'src/views/dashboard/analysis/index.vue', //模版文件的路径
data: {
name,
},
},
{
type: 'add', // 添加多个
path: `src/views/temp/${data.pathName}.tsx`,
templateFile: 'src/views/dashboard/analysis/tableData.tsx',
data: {
name,
},
},
];
return actions;
},
};
prompts问题类型 | |
---|---|
type | 接受类型,这里为接受终端输入 |
name | 输入的内容赋给变量pathName,可以在acitons中使用该变量 |
message | 提示内容:输入控制器名称 |
choices | 选择数组或返回一个选择数组的函数。如果定义为函数,则第一个参数将是当前查询程序会话答案。 |
validate | 接收用户输入并回答散列。如果值有效,则返回true,否则返回错误消息(字符串)。如果返回false,则提供一个默认的错误消息。 |
when | 接收当前用户回答的散列,根据是否应该询问这个问题,应该返回true或false。该值也可以是一个简单的布尔值 |
askAnswered | 如果答案已经存在,强制提示问题 |
... |
index.hbs编写生成文件的模版内容,可自己根据项目需求进行定义
require('module-alias/register');
import BaseController from '@base/baseController';
import { AController } from '@lib/aRouter';
export default class {{ name }}Controller extends BaseController {
}
项目的根目录下创建plopfile.js文件
plopfile从低级节点模块开始,它导出一个函数,该函数接受plop对象作为它的第一个参数。
plop对象公开包含setGenerator(name, config)函数的plop api对象。这是用来为这个plopfile创建生成器的函数。当plop从目录中的终端运行时,将显示这些生成器的列表。
const routerGenerator = require('./plop-templates/router/prompt');
module.exports = function (plop) {
plop.setGenerator('table-temps', routerGenerator);
plop.setGenerator('info-temps', routerGenerator);
plop.setHelper('upperCase', function (text) {
return text.toUpperCase();
});
plop.setPartial('myTitlePartial', '<h1>{{titleCase name}}</h1>');
};
如果要用module.exports = function (plop)
方式,需要安装CommonJS
运行plop
npm run plop
根据提示输入文件名即可
绕开提示器
一旦你已经熟悉了项目以及其中的生成器,你可能希望在运行生成器时就为它提供答案,而不是等它提出问题后才给出答案。比如,我有一个名为component的生成器,它会向我提一个问题要求我输入一个名字,我就可以使用下面这样的命令:$ plop componnet "componentname" ,它就会立即执行就像我在提示器中输入答案一样。如果这个生成器还有第二个问题,那用户在上面命令中可以输入第二个值作为第二个问题的答案。
像confirm和list这样的提示确保你的输入时有含义的。比如输入y/yes/t/true中的一个作为一个需要一个布尔值的确认性提问的答案。你可以从一个列表来选择使用他们的值、索引、键或者名称。Checkbox类型的提示器可以接受一个用逗号分割开的值列表来实现多选。
ps: 如果你想为第二个提问(而非第一个问题)提供答案,你可以使用下划线来跳过。
Plofile API
TypeScript 声明
plop捆绑了TypeScript声明。无论用不用ts声明,编辑器都会通过这些声明提供代码帮助 。
常用方法
方法名 | 参数 | 返回值 | 说明 |
---|---|---|---|
setGenerator | String,GeneratorConfig | GeneratorConfig | 设定一个生成器 |
setHelper | String,Function | 设定一个辅助方法 | |
setPartial | String,String | 设定一个片段 | |
setActionType | String,CuscomAction | 注册一个自定义动作类型 | |
setPrompt | String,InquirePrompt | 注册一个自定义的提示器类型 | |
load | Array[String],Object,Object | 从另一个plopfile或npm模块加载生成器、辅助类或片段 |
setHelper
setHelper直接对应于handlebars方法registerHelper。
`
plop.setHelper('upperCase', function (text) {
return text.toUpperCase();
});
// or in es6/es2015
plop.setHelper('upperCase', (txt) => txt.toUpperCase());
`
setPartial
setPartial直接对应于handlebars的方法方法registerPartial。
module.exports = function (plop) { plop.setPartial('myTitlePartial', '<h1>{{titleCase name}}</h1>'); // used in template as {{> myTitlePartial }} };
setActionType
setActionType允许您创建可以在plopfile中使用的自己的操作(类似于添加或修改)。这些基本上是高度可重用的自定义操作函数。
参数 | 类型 | 说明 |
---|---|---|
answer | Object | 对提问的回答 |
config | Action Config | 生成器的“动作”数组中的对象 |
plop | PlopfileApi | 运行此动作的plopfile的plop api |
`
module.exports = function (plop) {
plop.setActionType('doTheThing', function (answers, config, plop) {
// do something
doSomething(config.configProp);
// if something went wrong
throw 'error message';
// otherwise
return 'success status message';
});
// or do async things inside of an action
plop.setActionType('doTheAsyncThing', function (answers, config, plop) {
// do something
return new Promise((resolve, reject) => {
if (success) {
resolve('success status message');
} else {
reject('error message');
}
});
});
// use the custom action
plop.setGenerator('test', {
prompts: [],
actions: [{
type: 'doTheThing',
configProp: 'available from the config param'
}, {
type: 'doTheAsyncThing',
speed: 'slow'
}]
});
}
`
setGenerator
配置对象应该包含prompts与actions 属性(description属性是可选的)。prompts数组是在终端中的提示问题。而 actions 数组是要执行的操作的列表。
GeneratorConfig 接口
属性 | 类型 | 说明 |
---|---|---|
description | [String] | 简短说明生成器的用途 |
prompts | Array[InquirerQuestion] | 向用户提的问题 |
actions | Array[ActionConfig] | 可执行的动作 |
ActionConfig 接口
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
type | Striing | 动作类型(如 add、modify、addMany等等) | |
force | Boolean | false | 是否强制执行动作(根据动作表示不同的内容) |
data | Object/Function | {} | 指定在运行此操作时应与用户提示答案混合的数据 |
abortOnFail | Boolean | true | 如果此动作由于任何原因失败,则终止所有未来动作 |
其他方法
方法 | 参数 | 返回值 | 说明 |
---|---|---|---|
getHelper | String | Function | 获取辅助类 |
getHelperList | Array[String] | 获取辅助类名称列表 | |
getPartial | String | String | 根据名称获取handlebars模板片段 |
getPartialList | Array[String] | 获取模板片段名称列表 | |
getActionType | String | CustomAction | 根据名称获取动作类型 |
getActionTypeList | Array[String] | 获取动作类型名称列表 | |
setWelcomeMessage | String | 自定义在运行$ plop命令时要求您选择生成器的显示消息 | |
getGenerator | String | GeneratorConfig | 根据名称获取生成器配置 |
getGeneratorList | Array[Object] | 获取生成器数组,每个生成器包含名称和描述 | |
setPlopfilePath | String | 设置plopfilePath值,该值在内部用于定位模板文件等资源 | |
getPlopfilePath | String | 返回plopfile的绝对路径 | |
getDestBasePath | String | 返回创建文件时使用的基本路径 | |
setDefaultInclude | Object | Object | 设置plopfile的默认配置,如果它被使用plop.load()的另一个plopfile使用,则该配置将用于那个plopfile |
getDefaultInclude | String | Object | 获取将用于此plopfile的默认配置(另一个plopfile可以使用plop.load()使用该配置) |
renderString | String,Object | String | 使用第二个参数(对象)作为数据,通过handlebars的模板渲染器运行第一个参数(字符串)。返回渲染后的模板 |
内置action的一些动作
add
add 动作被用来向你的项目中新增一个文件,path 属性指定生成文件的路径,它本身是一个handlebars模板,用户输入的文件名称将作为变量嵌入其中。文件内容将由template或templateFile决定。
属性 | 类型 | 默认值 |
---|---|---|
path | Sring | 一个符合handlebars模板规范的字符串,它是新文件的路径 |
template | String | 被用来创建新文件的handlebars模板 |
templateFile | String | 一个包含模板的文件路径 |
skipIfExists | Boolean | 如果要创建的文件已经存在,则跳过(而非报错) |
force | Boolean | 继承自ActionConfig(如果文件存在则覆盖) |
data | Object | 继承自ActionConfig |
abortOnFail | Boolean | 继承自ActionConfig |
AddMany
addMany 动作可以一步创建多个文件。destination属性是用来指定生成文件所在目录的,它是一个handlebars模板,意味着该属性中定义的目录路径可以是动态的。base属性可以用于更改在创建文件时应该忽略模板路径的哪些部分。 如果您希望添加的文件名是唯一的,则templateFiles glob位于的路径可以在它们的文件/文件夹名称中使用handlebars语法
|属性 |类型 默认值| 说明|
| -------- | -------- | -------- | -------- |
|destination| String | |规定新文件要创建到的目录(是一个handlebars模板)|
|base |String | |当文件要被创建到目录中时需要忽略的路径部分|
|templateFiles |Glob | |匹配要添加的多个模板文件的glob模式|
|stripExtensions| [String]| [‘hbs’] |文件扩展名,在将其添加到目标文件时,应该从模板文件名称中删除这些扩展名|
|globOptions |Object | |更改如何与要添加的模板文件匹配的glob选项|
|verbose |Boolean| true |打印每个成功添加的文件路径|
|skipIfExisits |Boolean| false |继承自Add接口|
|force |Boolean| false |继承自 ActionConfig 对象|
|data| Object| {} |继承自 ActionConfig 对象|
|abortOnFail |Boolean |true |继承自 ActionConfig 对象|
Modify
modify 修改动作将使用pattern属性在指定路径(path)下的文件中查找/替换文本。
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
path | String | 要修改的文件的路径(是一个handlebars模板) | |
pattern | RegExp | end-of-file | 一个正则表达式,用来匹配需要被替换的文本 |
template | String | 一个handlebars模板,用它取代所匹配的模式。捕获组的值有2等 | |
templateFile | String | 是一个包含模板的路径 | |
data | Object | {} | 继承自ActionConfig |
abortOnFail | Boolean | true | 继承自ActionConfig |
Append
append 追加操作是一个常用功能,它是modify接口的子集。它用于将数据附加到文件中的特定位置。
属性 | 类型 | 默认值 | 说明 |
---|---|---|---|
path | String | 需要被修改的文件路径(是一个handlebars模板) | |
pattern | RegExp,String | 一个正则表达式,用于匹配附加文本的正则表达式 | |
unique | Boolean | true | 是否删除相同的项 |
separator | String | new line | 分割符 |
template | String | 项要用的handlebars模板 | |
templateFile | String | 包含模板的文件模板 | |
data | Object | {} | 继承自ActionConfig |
abortOnFail | Boolean | true | 继承自ActionConfig |
Custom(动作函数)
add和modify操作将处理plop要处理的几乎所有情况 .但是,plop 提供一些自定义动作的函数。
- 自定义动作函数将被plop执行,这时会使用相同的 CustomAction 动作签名;
- 在执行下一个动作前,plop 将会等待自定义动作执行完。
- 这个函数必须通过返回值来告诉plop,发生了什么。如果您返回的是一个 Promise对象,那plop 不会开始其它动作,直到Promise 达到解决状态。如果您返回一条消息(字符串),plop 将知道动作已经完成,它将在动作的状态中报告消息。
- 当Promise变为拒绝态或者函数抛出一个异常,自定义动作将失败。