找回密码
 立即注册
首页 业界区 业界 使用Plop.js高效生成模板文件

使用Plop.js高效生成模板文件

痕伯 3 天前
前情

开发是个创造型的职业,也是枯燥的职业,因为开发绝大多数都是每天在业务的代码中无法自拨,说到开发工作,就永远都逃不开新建文件的步骤,特别现在组件化开发胜行,每天都是在新建新建组件的道路上一去不返,我们做的最多就是直接拷贝一个旧代码组件,重命下名再删减删减完成新组件的创建
思考

对于这种组件,整体基础结构是一样的,我们可不可以有更好的方式一键生成了,就避免了反反复的拷贝删减动作,有一天我在逛博客论坛的时候我发现了Plop.js,发现它正是解决这种场景的
Plop.js介绍

官网:Consistency Made Simple : PLOP
官网的介绍:Plop is a little tool that saves you time and helps your team build new files with consistency,翻译就是:Plop是一个小工具,可以节省您的时间,并帮助您的团队构建一致的新文件
工作主流程:我用过后对它的工作整体流程理解是这样的,通过plopfile.js定义一个一个生成器,每一个生成器根据你传的配置再调用指定目录(一般是plop-template目录)下的hbs模板文件,再通过模板渲染生成最终符合特定结构的文件
需求描述

最近我手上的项目主要是uni-app项目,我们就以uni-app项目做实验,我每天可能都会重复的工作有新建组件、页面、API接口文件,如下图所示
1.png

实战

生成组件

定义组件生成器:
  1. module.exports = function (plop) {
  2.   // 导入所需模块
  3.   const { exec } = require('child_process');
  4.   const path = require('path');
  5.   const fs = require('fs');
  6.   // 定义打开文件的函数
  7.   function openFile(filePath) {
  8.     const fullPath = path.resolve(process.cwd(), filePath);
  9.     if (fs.existsSync(fullPath)) {
  10.       console.log(`\n正在打开文件: ${fullPath}`);
  11.       // 根据操作系统选择打开方式
  12.       const isWin = process.platform === 'win32';
  13.       // Windows - 尝试使用cursor打开,如果你是用的vs code,请把cursor换成code即可
  14.       exec(`cursor "${fullPath}"`, (error) => {
  15.         if (error) {
  16.           // 如果VS Code不可用,尝试使用默认程序打开
  17.           console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);
  18.         }
  19.       });
  20.     }
  21.     return '文件已创建';
  22.   }
  23.   // 新建组件 组件生成器
  24.   plop.setGenerator("component", {
  25.     description: "新建组件",
  26.     prompts: [
  27.       {
  28.         type: "input",
  29.         name: "name",
  30.         message: "要新建的组件名:",
  31.       },
  32.     ],
  33.     actions: [
  34.       {
  35.         type: "add",
  36.         path: "components/{{pascalCase name}}/{{pascalCase name}}.vue",
  37.         templateFile: "plop-templates/Component.vue.hbs",
  38.       },
  39.       // 实现生成文件后主动打开的功能
  40.       function(answers) {
  41.         const filePath = `components/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}.vue`;
  42.         return openFile(filePath);
  43.       }
  44.     ],
  45.   });
  46. };
复制代码
这里多做了一个功能,当生成完页面后,使用cursor编辑器主动打开当前生成的文件,其中openFile就是打开当前生成的文件,这个可有可无,加了体验感觉会好一些
模板文件plop-templates/Component.vue.hbs:
  1. <template>
  2. <template>
  3.     \{{ msg }}
  4. </template>-\{{ msgIn }}
  5. </template>
复制代码
演示动图:
2.gif

生成页面

定义生成页生成器:
  1. module.exports = function (plop) {
  2.   // 导入所需模块
  3.   const { exec } = require('child_process');
  4.   const path = require('path');
  5.   const fs = require('fs');
  6.   // 定义打开文件的函数
  7.   function openFile(filePath) {
  8.     const fullPath = path.resolve(process.cwd(), filePath);
  9.     if (fs.existsSync(fullPath)) {
  10.       console.log(`\n正在打开文件: ${fullPath}`);
  11.       // 根据操作系统选择打开方式
  12.       const isWin = process.platform === 'win32';
  13.       // Windows - 尝试使用cursor打开
  14.       exec(`cursor "${fullPath}"`, (error) => {
  15.         if (error) {
  16.           // 如果VS Code不可用,尝试使用默认程序打开
  17.           console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);
  18.         }
  19.       });
  20.     }
  21.     return '文件已创建';
  22.   }
  23.   // 添加页面到pages.json
  24.   function addPageToConfig(answers) {
  25.     try {
  26.       const pagesConfigPath = path.resolve(process.cwd(), 'pages.json');
  27.       if (!fs.existsSync(pagesConfigPath)) {
  28.         return '无法找到pages.json';
  29.       }
  30.       // 读取pages.json文件内容
  31.       let fileContent = fs.readFileSync(pagesConfigPath, 'utf8');
  32.       // 查找pages数组的结束括号位置
  33.       const lastBracketIndex = fileContent.lastIndexOf(']');
  34.       if (lastBracketIndex === -1) {
  35.         return '无法在pages.json中找到pages数组';
  36.       }
  37.       // 检查pages数组是否为空
  38.       const pagesArrayContent = fileContent.substring(
  39.         fileContent.indexOf('"pages"'),
  40.         lastBracketIndex
  41.       );
  42.       // 是否需要添加逗号(如果数组中已有内容)
  43.       const needComma = pagesArrayContent.includes('{');
  44.       // 新页面的配置信息
  45.       const newPageConfig = `${needComma ? ',' : ''}
  46.         {
  47.             "path": "pages/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}",
  48.             "style": {
  49.                 "navigationBarTitleText": "${answers.title}"
  50.             }
  51.         }`;
  52.       // 将新页面添加到数组末尾
  53.       fileContent = fileContent.substring(0, lastBracketIndex) +
  54.                     newPageConfig +
  55.                     fileContent.substring(lastBracketIndex);
  56.       // 保存更新后的文件
  57.       fs.writeFileSync(pagesConfigPath, fileContent, 'utf8');
  58.       return 'pages.json已更新';
  59.     } catch (error) {
  60.       console.error('更新pages.json时出错:', error);
  61.       return `更新配置失败: ${error.message}`;
  62.     }
  63.   }
  64.   // 新建页面
  65.   plop.setGenerator("page", {
  66.     description: "新建页面",
  67.     prompts: [
  68.       {
  69.         type: "input",
  70.         name: "name",
  71.         message: "要新建的页面名:",
  72.       },
  73.       {
  74.         type: "input",
  75.         name: "title",
  76.         message: "要新建的页面标题:",
  77.       },
  78.     ],
  79.     actions: [
  80.       {
  81.         type: "add",
  82.         path: "pages/{{pascalCase name}}/{{pascalCase name}}.vue",
  83.         templateFile: "plop-templates/page.vue.hbs",
  84.       },
  85.       addPageToConfig,
  86.       function(answers) {
  87.         const filePath = `pages/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}.vue`;
  88.         return openFile(filePath);
  89.       }
  90.     ],
  91.   });
  92. };
复制代码
生成页面比生成组件需要多做一个功能,就生成页面后,需要向pages.json中添加路由申明,其中addPageToConfig就实现路由申明的
模板文件plop-templates/page.vue.hbs:
  1. <template>
  2.     \{{ msg }}
  3. </template>
复制代码
演示动图:
3.gif

生成接口文件

定义接口文件生成器:
  1. module.exports = function (plop) {
  2.   // 导入所需模块
  3.   const { exec } = require('child_process');
  4.   const path = require('path');
  5.   const fs = require('fs');
  6.   // 定义打开文件的函数
  7.   function openFile(filePath) {
  8.     const fullPath = path.resolve(process.cwd(), filePath);
  9.     if (fs.existsSync(fullPath)) {
  10.       console.log(`\n正在打开文件: ${fullPath}`);
  11.       // 根据操作系统选择打开方式
  12.       const isWin = process.platform === 'win32';
  13.       // Windows - 尝试使用cursor打开
  14.       exec(`cursor "${fullPath}"`, (error) => {
  15.         if (error) {
  16.           // 如果VS Code不可用,尝试使用默认程序打开
  17.           console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);
  18.         }
  19.       });
  20.     }
  21.     return '文件已创建';
  22.   }
  23.   // 新建接口文件
  24.   plop.setGenerator("api", {
  25.     description: "新建接口文件",
  26.     prompts: [
  27.       {
  28.         type: "input",
  29.         name: "name",
  30.         message: "要新建的接口文件名:",
  31.       },
  32.     ],
  33.     actions: [
  34.       {
  35.         type: "add",
  36.         path: "api/{{pascalCase name}}.js",
  37.         templateFile: "plop-templates/api.js.hbs",
  38.       },
  39.       function(answers) {
  40.         const filePath = `api/${plop.getHelper('pascalCase')(answers.name)}.js`;
  41.         return openFile(filePath);
  42.       }
  43.     ],
  44.   });
  45. };
复制代码
模板文件plop-templates/api.js.hbs:
  1. import request from "../utils/request.js";
  2. /**
  3. * 获取数据
  4. */
  5. export const queryList = async (id) => {
  6.   return request.request(`/api/test/${id}`, {}, {
  7.     method: "GET"
  8.   })
  9. };
复制代码
至此,生成模板文件的需求也就基本完成了,生成api接口文件就不录屏了,跟生成组件基本是一样的流程
代码我上传到gitee仓库,可以clone下来跑跑试试,仓库地址:xiewu/plopjsTest
小结

通过上面几个示例我相信你已经基本了解了Plop.js的大致使用方式,上面示例工程还是可以优化,对于uni-app项目,很大可能需要代码分包的,而上面代码只是实现了在主包中增加组件,这我也尝试做了,你可以把上面代码clone下来后切换到feat-complete分支即可。

这里只是抛砖引玉,对于聪明的你,也一定知道怎么把Plop.js应用到自己的项目中了,也期待你的留言和分享
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册