什么是Plop和Handlebars以及相关配置与常用API(plop篇)

什么是Plop

plop是一个小型的脚手架,可以通过命令行去生成、处理文件模板代码等.

不过plop不会独立使用,一般都会把plop集成到项目中用来创建同类型的项目文件.

如果项目的很多模块的结构骨架都非常相似,引入模版内容相同就可以使用Plop来实现自动化了,Plop旨在根据模板文件自动化创建组件.

plop的基本使用

npm install plop

如果没有全局安装,要在package.json中的script中增加脚本命令:
"scripts": { "plop": "plop" },

创建路由Generator

在根目录创建plop-templates用于存放各种模板

创建一个router目录作为路由的generator,并创建generator的js文件和hbs模板

image.png

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从目录中的终端运行时,将显示这些生成器的列表。
image.png
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

image.png
根据提示输入文件名即可

绕开提示器

一旦你已经熟悉了项目以及其中的生成器,你可能希望在运行生成器时就为它提供答案,而不是等它提出问题后才给出答案。比如,我有一个名为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模板,用它取代所匹配的模式。捕获组的值有1、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变为拒绝态或者函数抛出一个异常,自定义动作将失败。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,264评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,549评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,389评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,616评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,461评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,351评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,776评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,414评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,722评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,760评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,537评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,381评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,787评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,030评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,304评论 1 252
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,734评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,943评论 2 336

推荐阅读更多精彩内容