当前位置:   article > 正文

最前端|一文搞懂利用 plop 生成项目模板文件

最前端|一文搞懂利用 plop 生成项目模板文件

一、概述

  • 认识: plop 是一个微型生成器框架,用于生成符合团队规范的模板文件。它是 inquirer对话框 和 hanldebar模版的简单融合。
  • 作用: 通过自动化工具减少开发中重复代码的书写,从而提高开发效率;
  • 优点: 通过命令快速生成代码文件,免去了在项目中的新建文件、复制、粘贴等重复工作。
  • 细节: plop.js 的终端交互使用了Inquirer.js,所以也可以使用 inquirer 的插件对其功能进行扩展。
  • 应用场景: 日常开发中经常会需要重复创建相同类型的文件,例如每一个 view 页面都会有三个文件(index.vue,index.scss,interface.ts)去组成。如果需要创建一个 view,就要去创建三个文件,并且每一个文件中都要有一些基础代码,这就比较繁琐,而且很难统一每一个文件中基础的代码。Plop 就可以解决这个问题,你只需要通过命令,就可以快速生成 view 模板文件。

二、使用方法

1、安装插件

  1. pnpm iplop -D
  2. // pnpm install -g plop

2、创建配置文件 plopfile.js

在项目跟目录下,创建配置文件 plopfile.js,内容如下:

  1. const viewGenerator = require('./plop-templates/view/prompt')
  2. module.exports = (plop)=>{
  3. plop.setGenerator('view', viewGenerator)
  4. }

plopfile.js 中导出一个函数,该函数接受 plop 对象作为它的第一个参数;plop 对象公开包含 setGenerator(name, config)函数的 plop api 对象。

3、新建模板和脚本命令文件

在项目根目录下新建文件夹(如plop-templates),放置模板(view/index.vue)和脚本命令(view/prompt.js)文件;

目录结构如图:

view/index.vue 模板如下:

  1. <template>
  2. <divclass="{{name}}Container"></div>
  3. </template>
  4. <scriptsetuplang="ts"name="{{name}}">
  5. import{ getCurrentInstance, ref, reactive, onMounted } from"vue";
  6. import{ useRouter } from"vue-router";
  7. const{
  8. proxy: { $Urls, $Request, $Modal }
  9. } = getCurrentInstance() asany;
  10. constrouter = useRouter();
  11. defineExpose({});
  12. onMounted(()=>{
  13. });
  14. </script>
  15. <stylelang="scss"scoped>
  16. @import"./index.scss";
  17. </style>

提示:这里的模板内容,大家可以根据自己的项目需求,进行自定义设置 ,主要目的是方便项目整体复用。

view/index.scss 模板如下:

.{{name}}Container{ }

router/index.vue 模板如下:

  1. {
  2. path: "/{{name}}",
  3. name: "{{name}}",
  4. component: () => import("@/views/{{name}}/index.vue"),
  5. meta: {
  6. title: '{{menu}}'
  7. }
  8. },

view/prompt.js 脚本命名如下:

  1. module.exports = {
  2. description: '新建一个页面',
  3. prompts: [
  4. {
  5. type: 'input',
  6. name: 'name',
  7. message: '页面名称:',
  8. validate(name) {
  9. if (!name) {
  10. return '请输入页面名称'
  11. }
  12. return true
  13. },
  14. },
  15. {
  16. type: 'checkbox',
  17. name: 'blocks',
  18. message: '需要包含什么:',
  19. choices: [
  20. {
  21. name: '<template>',
  22. value: 'template',
  23. checked: true,
  24. },
  25. {
  26. name: '<script>',
  27. value: 'script',
  28. checked: true,
  29. },
  30. {
  31. name: '<style>',
  32. value: 'style',
  33. checked: true,
  34. },
  35. ],
  36. validate(value) {
  37. if (!value.includes('template') || !value.includes('script') || !value.includes('style')) {
  38. return '<template>|<script>|<style> 是必须的'
  39. }
  40. return true
  41. },
  42. },
  43. {
  44. type: 'confirm',
  45. name: 'wantCps',
  46. message: '你想要给新页面添加组件吗?',
  47. },
  48. {
  49. type: 'input',
  50. name: 'cpsName',
  51. message: '组件名称:',
  52. when: function (answer) {
  53. // 当wantCps为true的时候才会到达这步
  54. return answer.wantCps // 只有我return true才会这个confirm
  55. },
  56. validate(name) {
  57. if (!name) {
  58. return '请输入组件名称'
  59. }
  60. return true
  61. },
  62. },
  63. {
  64. type: 'confirm',
  65. name: 'wantRouter',
  66. message: '你想要给新页面添加路由吗?',
  67. },
  68. {
  69. type: 'input',
  70. name: 'menu',
  71. message: '左侧菜单名称:',
  72. when: function (answer) {
  73. return answer.wantRouter
  74. },
  75. validate(name) {
  76. if (!name) {
  77. return '请输入菜单名称'
  78. }
  79. return true
  80. },
  81. },
  82. ],
  83. actions: (data) => {
  84. const name = '{{camelCase name}}'
  85. let actions = [
  86. {
  87. type: 'add',
  88. path: `src/views/${name}/index.vue`,
  89. templateFile: 'plop-templates/view/index.vue',
  90. },
  91. {
  92. type: 'add',
  93. path: `src/views/${name}/index.scss`,
  94. templateFile: 'plop-templates/view/index.scss',
  95. },
  96. {
  97. type: 'add',
  98. path: `src/views/${name}/interface.ts`,
  99. },
  100. ]
  101. let cpsName = '{{properCase cpsName}}'
  102. const cpsItem = [
  103. {
  104. type: 'add',
  105. path: `src/views/${name}/components/${cpsName}/index.vue`,
  106. templateFile: 'plop-templates/view/components/index.cps.vue',
  107. },
  108. {
  109. type: 'add',
  110. path: `src/views/${name}/components/${cpsName}/index.scss`,
  111. templateFile: 'plop-templates/view/components/index.cps.scss',
  112. },
  113. ]
  114. const routerItem = [
  115. {
  116. type: 'append',
  117. pattern: /routes*\:* \[/,
  118. path: 'src/router/index.ts',
  119. templateFile: 'plop-templates/router/index.vue',
  120. data: {
  121. name: '{{name}}',
  122. menu: '{{menu}}',
  123. },
  124. },
  125. ]
  126. if (data.wantCps && data.wantRouter) {
  127. return [...actions, ...cpsItem, ...routerItem]
  128. } else if (data.wantCps) {
  129. return [...actions, ...cpsItem]
  130. } else if (data.wantRouter) {
  131. return [...actions, ...routerItem]
  132. }
  133. return actions
  134. },
  135. }

4、设置自定义命令

在 package.json 添加 script 脚本

  1. {
  2. "scripts": {
  3. "plop": "plop"
  4. },
  5. }

5、运行命令

pnpm run plop view

三、操作方法和文件生成

输入命令 pnpm run plop view

生成文件如下:

dataScreen/index.vue 模板内容如下:

dataScreen/index.scss 模板样式如下:

router/index.ts 路由内容如下:

四、Plofile API

plopfile api 是由 plop 对象公开的方法的集合,大部分工作都是由 setGenerator 完成的,当然也有很多其他有用的方法 。

(一)主要方法

这些是创建 plopfile 时通常使用的方法。

//setGenerator

配置对象中 prompts 和 actions 属性,是必须的;description 属性是可选的;prompts 数组会被传递给 inquirer。而 actions 数组是要执行的操作列表。

示例如下:

  1. module.exports = function(plop) {
  2. // 创建一个生成器
  3. plop.setGenerator('component', {
  4. description: '新增一个公共组件', //可选;描述,在终端里生成器后面显示的内容
  5. prompts: [], // 提示,用于捕获用户输入
  6. actions: [], // 行为,具体执行的内容
  7. })
  8. }

GeneratorConfig 接口

//setHelper

setHelper 主要用于自定义相应一个工具方法,setHelper 直接对应于 handlebars 方法 registerHelper。

示例如下:

  1. module.exports = function(plop){
  2. plop.setHelper('upperCase', function(text){
  3. returntext.toUpperCase()
  4. })
  5. // or in es6/es2015
  6. plop.setHelper('upperCase', (txt) => txt.toUpperCase())
  7. }

//setPartial

setPartial 直接对应于 handlebars 的方法方法 registerPartial。

  1. module.exports = function(plop) {
  2. plop.setPartial('myTitlePartial', '<h1>{{titleCase name}}</h1>')
  3. // used in template as {{> myTitlePartial }}
  4. }

(二)其他方法

其他的方法,如 setPartial、setActionType、setPrompt、load 等等,具体用法,大家可以参见官网

五、Plop Api

plop 最基本和最核心的内容:prompts 和 actions

//prompts

prompts 即是 inquirer在新窗口打开的 prompts,更多配置可参考inquirer文档(GitHub - SBoudrias/Inquirer.js: A collection of common interactive command line user interfaces.)。

提示:prompts 数组里的 type 类型:input,number,confirm,list,rawlist,expand,checkbox,password,editor。当然也是支持 inquirer 插件的。

//actions

actions 函数配置属性包含:

name

认识:name 用于生成文件或文件夹的名称;

name 命名规则如下:

  1. camelCase:将字符串转为驼峰表示法,一般应用于文件夹命名。示例:(changeFormatToThis)
  2. properCase/pascalCase:单词首字母大写表示法,一般应用于组件文件夹命名。示例:(ChangeFormatToThis)
  3. lowerCase :小写表示法 (change format to this)
  4. snakeCase:下划线表示法(change_format_to_this)
  5. dashCase/kebaCase:短划线表示法(change-format-to-this)
  6. dotCase:点语法表示法(change.format.to.this)
  7. pathCase:路径表示法(change/format/to/this)
  8. sentenceCase: 整句首字母大写法(Change format to this)
  9. constantCase: 全部大写下划线连接 (CHANGE_FORMAT_TO_THIS)
  10. titleCase :标题表示法 (Change Format To This)

ActionConfig

属性如下:

提示:在 ActionConfig 里面,data 属性可以是一个返回普通对象的函数;也可以是一个返回 Promise 对象的函数,但这个 Promise 对象必须 resolve 一个对象 。

内置动作

您可以在 GeneratorConfig 中使用几种类型的内置动作。您可以指定操作的类型(所有路径都基于 plopfile 的位置)和要使用的模板 。

Add

add 动作被用来向你的项目中新增一个文件;

相关属性如下:

AddMany

addMany 动作可以一次创建多个文件。

细节:如果您希望添加的文件名是唯一的,则 templateFiles glob 位于的路径可以在它们的文件或文件夹名称中使用 handlebars 语法。

相关属性如下:

Modify

modify 修改动作将使用 pattern 属性进行匹配,从而修改或替换指定路径(path)下的文件。

Append

append 追加操作是一个常用功能,它是 modify 接口的子集。它用于将数据追加到文件中的特定位置。

//动态 actions

如果 actions 需要根据 prompts 的 answer 来决定,那么可以使用动态 actions

示例如下:

  1. module.exports = function(plop) {
  2. plop.setGenerator('test', {
  3. prompts: [{
  4. type: 'confirm',
  5. name: 'wantTacos',
  6. message: 'Do you want tacos?'
  7. }],
  8. actions: function(data) {
  9. varactions = [];
  10. if(data.wantTacos) {
  11. actions.push({
  12. type: 'add',
  13. path: 'folder/{{dashCase name}}.txt',
  14. templateFile: 'templates/tacos.txt'
  15. });
  16. } else{
  17. actions.push({
  18. type: 'add',
  19. path: 'folder/{{dashCase name}}.txt',
  20. templateFile: 'templates/burritos.txt'
  21. });
  22. }
  23. returnactions;
  24. }
  25. });

//源码地址

GitHub - wdlhao/vue3-plop: plopJS,plop

参考资料:

1、plopjs (Learning to Plop : PLOP (http://plopjs.com))

2、Inquirer.js(https://github.com/SBoudrias/Inquirer.js#objects

3、handlebarsjs(Expressions | Handlebars (http://handlebarsjs.com))

作者:吴冬林|前端开发工程师

版权声明:本文由神州数码云基地团队整理撰写,若转载请注明出处。

公众号搜索神州数码云基地,了解更多技术干货。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/70974
推荐阅读
相关标签
  

闽ICP备14008679号