当前位置: 首页 > article >正文

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

前情

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

思考

对于这种组件,整体基础结构是一样的,我们可不可以有更好的方式一键生成了,就避免了反反复的拷贝删减动作,有一天我在逛博客论坛的时候我发现了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接口文件,如下图所示
请添加图片描述

实战

生成组件

定义组件生成器:

module.exports = function (plop) {// 导入所需模块const { exec } = require('child_process');const path = require('path');const fs = require('fs');// 定义打开文件的函数function openFile(filePath) {const fullPath = path.resolve(process.cwd(), filePath);if (fs.existsSync(fullPath)) {console.log(`\n正在打开文件: ${fullPath}`);// 根据操作系统选择打开方式const isWin = process.platform === 'win32';// Windows - 尝试使用cursor打开,如果你是用的vs code,请把cursor换成code即可exec(`cursor "${fullPath}"`, (error) => {if (error) {// 如果VS Code不可用,尝试使用默认程序打开console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);}});}return '文件已创建';}// 新建组件 组件生成器plop.setGenerator("component", {description: "新建组件",prompts: [{type: "input",name: "name",message: "要新建的组件名:",},],actions: [{type: "add",path: "components/{{pascalCase name}}/{{pascalCase name}}.vue",templateFile: "plop-templates/Component.vue.hbs",},// 实现生成文件后主动打开的功能function(answers) {const filePath = `components/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}.vue`;return openFile(filePath);}],});
};

这里多做了一个功能,当生成完页面后,使用cursor编辑器主动打开当前生成的文件,其中openFile就是打开当前生成的文件,这个可有可无,加了体验感觉会好一些

模板文件plop-templates/Component.vue.hbs:

<template><div @click="handleClick">\{{ msg }}-\{{ msgIn }}</div>
</template><script setup>import { ref, onMounted } from 'vue';defineOptions({name: "{{camelCase name}}"})const props = defineProps({msg: {type: String,default: 'Hello uniapp!'}})const emit = defineEmits(['update:msg']);const msgIn = ref('Hello world!');const handleClick = () => {emit('update:msg', props.msg + ' ' + msgIn.value);}onMounted(() => {console.log('---- onMounted ----');})
</script><style lang="scss"></style>

演示动图:
请添加图片描述

生成页面

定义生成页生成器:

module.exports = function (plop) {// 导入所需模块const { exec } = require('child_process');const path = require('path');const fs = require('fs');// 定义打开文件的函数function openFile(filePath) {const fullPath = path.resolve(process.cwd(), filePath);if (fs.existsSync(fullPath)) {console.log(`\n正在打开文件: ${fullPath}`);// 根据操作系统选择打开方式const isWin = process.platform === 'win32';// Windows - 尝试使用cursor打开exec(`cursor "${fullPath}"`, (error) => {if (error) {// 如果VS Code不可用,尝试使用默认程序打开console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);}});}return '文件已创建';}// 添加页面到pages.jsonfunction addPageToConfig(answers) {try {const pagesConfigPath = path.resolve(process.cwd(), 'pages.json');if (!fs.existsSync(pagesConfigPath)) {return '无法找到pages.json';}// 读取pages.json文件内容let fileContent = fs.readFileSync(pagesConfigPath, 'utf8');// 查找pages数组的结束括号位置const lastBracketIndex = fileContent.lastIndexOf(']');if (lastBracketIndex === -1) {return '无法在pages.json中找到pages数组';}// 检查pages数组是否为空const pagesArrayContent = fileContent.substring(fileContent.indexOf('"pages"'), lastBracketIndex);// 是否需要添加逗号(如果数组中已有内容)const needComma = pagesArrayContent.includes('{');// 新页面的配置信息const newPageConfig = `${needComma ? ',' : ''}{"path": "pages/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}","style": {"navigationBarTitleText": "${answers.title}"}}`;// 将新页面添加到数组末尾fileContent = fileContent.substring(0, lastBracketIndex) + newPageConfig + fileContent.substring(lastBracketIndex);// 保存更新后的文件fs.writeFileSync(pagesConfigPath, fileContent, 'utf8');return 'pages.json已更新';} catch (error) {console.error('更新pages.json时出错:', error);return `更新配置失败: ${error.message}`;}}// 新建页面plop.setGenerator("page", {description: "新建页面",prompts: [{type: "input",name: "name",message: "要新建的页面名:",},{type: "input",name: "title",message: "要新建的页面标题:",},],actions: [{type: "add",path: "pages/{{pascalCase name}}/{{pascalCase name}}.vue",templateFile: "plop-templates/page.vue.hbs",},addPageToConfig,function(answers) {const filePath = `pages/${plop.getHelper('pascalCase')(answers.name)}/${plop.getHelper('pascalCase')(answers.name)}.vue`;return openFile(filePath);}],});
};

生成页面比生成组件需要多做一个功能,就生成页面后,需要向pages.json中添加路由申明,其中addPageToConfig就实现路由申明的

模板文件plop-templates/page.vue.hbs:

<template><div>\{{ msg }}</div>
</template><script setup>import { ref, onMounted } from 'vue';defineOptions({name: "{{camelCase name}}"})const msg = ref('Hello uniapp!');onMounted(() => {console.log('---- onMounted ----');})</script><style lang="scss"></style>

演示动图:
请添加图片描述

生成接口文件

定义接口文件生成器:

module.exports = function (plop) {// 导入所需模块const { exec } = require('child_process');const path = require('path');const fs = require('fs');// 定义打开文件的函数function openFile(filePath) {const fullPath = path.resolve(process.cwd(), filePath);if (fs.existsSync(fullPath)) {console.log(`\n正在打开文件: ${fullPath}`);// 根据操作系统选择打开方式const isWin = process.platform === 'win32';// Windows - 尝试使用cursor打开exec(`cursor "${fullPath}"`, (error) => {if (error) {// 如果VS Code不可用,尝试使用默认程序打开console.log(`打开文件失败: ${error},文件路径: ${fullPath}`);}});}return '文件已创建';}// 新建接口文件plop.setGenerator("api", {description: "新建接口文件",prompts: [{type: "input",name: "name",message: "要新建的接口文件名:",},],actions: [{type: "add",path: "api/{{pascalCase name}}.js",templateFile: "plop-templates/api.js.hbs",},function(answers) {const filePath = `api/${plop.getHelper('pascalCase')(answers.name)}.js`;return openFile(filePath);}],});
};

模板文件plop-templates/api.js.hbs:

import request from "../utils/request.js";/*** 获取数据*/
export const queryList = async (id) => {return request.request(`/api/test/${id}`, {}, {method: "GET"})
};

至此,生成模板文件的需求也就基本完成了,生成api接口文件就不录屏了,跟生成组件基本是一样的流程

代码我上传到gitee仓库,可以clone下来跑跑试试,仓库地址:xiewu/plopjsTest

小结

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

这里只是抛砖引玉,对于聪明的你,也一定知道怎么把Plop.js应用到自己的项目中了,也期待你的留言和分享👀

Plop.js入门好文推荐:
Plop.js:一键生成代码模板,提升开发效率的利器-CSDN博客
前端工程化-使用 plop 生成项目模板文件

http://www.lryc.cn/news/2400957.html

相关文章:

  • Vue框架2(vue搭建方式2:利用脚手架,ElementUI)
  • mac 设置cursor (像PyCharm一样展示效果)
  • SpringCloudAlibaba微服务架构
  • Java高级 | 【实验三】Springboot 静态资源访问
  • C语言_预处理详解
  • 将前后端分离版的前端vue打包成EXE的完整解决方案
  • 物联网协议之MQTT(一)基础概念和设备
  • 「Java教案」Java程序的构成
  • 还原Windows防火墙
  • 区块链可投会议CCF B--EDBT 2026 截止10.8 附录用率
  • 经典ReLU回归!重大缺陷「死亡ReLU问题」已被解决
  • 在VSCode中开发一个uni-app项目
  • quic为什么没有被大规模应用?
  • Delft3D软件介绍及建模原理和步骤;Delft3D数值模拟溶质运移模型建立;地表水环境影响评价报告编写思路
  • 书籍在其他数都出现k次的数组中找到只出现一次的数(7)0603
  • 开源模型应用落地-OpenAI Agents SDK-集成Qwen3-8B-function_tool(二)
  • Python - 爬虫;Scrapy框架之插件Extensions(四)
  • Spark实战能力测评模拟题精析【模拟考】
  • 【OSG学习笔记】Day 15: 路径动画与相机漫游
  • PostgreSQL(PostGIS)触发器+坐标转换案例
  • Constraints and Triggers
  • 基于windows系统的netcore架构与SqlServer数据库,实现双机热备。
  • 【转bin】EXCEL数据转bin
  • BERT:让AI真正“读懂”语言的革命
  • 【计算机组成原理】SPOOLing技术
  • 冷雨泉教授团队:新型视觉驱动智能假肢手,拟人化抓握技术突破,助力截肢者重获生活自信
  • CanvasGroup篇
  • [Java 基础]银行账户程序
  • 2025.6.4总结
  • 将音频数据累积到缓冲区,达到阈值时触发处理