当前位置: 首页 > 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 生成项目模板文件

相关文章:

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

前情 开发是个创造型的职业&#xff0c;也是枯燥的职业&#xff0c;因为开发绝大多数都是每天在业务的代码中无法自拨&#xff0c;说到开发工作&#xff0c;就永远都逃不开新建文件的步骤&#xff0c;特别现在组件化开发胜行&#xff0c;每天都是在新建新建组件的道路上一去不…...

Vue框架2(vue搭建方式2:利用脚手架,ElementUI)

一.引入vue第二种搭建方式 在以前的前端项目中,一个项目需要多个html文件实现页面之前的切换,如果页面中需要依赖js或者css文件,那么我们就需要在多个html文件中都需要导入vue.js文件,太过繁琐. 现在前端开发都采用单页面结果,一个项目中只有一个html文件 其他不同的内容都写…...

mac 设置cursor (像PyCharm一样展示效果)

一、注册 Cursor - The AI Code Editor 二、配置Python环境 我之前使用pycharm创建的python项目&#xff0c;以及创建了虚拟环境&#xff0c;现在要使用cursor继续开发。 2.1 选择Python 虚拟环境 PyCharm 通常将虚拟环境存储在项目目录下的 venv 或 .venv 文件夹中&#xf…...

SpringCloudAlibaba微服务架构

技术架构图 SpringCloudAlibaba微服务架构 说明&#xff1a; 1.1、采用SpringCloudAlibaba分布式微服务架构&#xff0c;使用Nginx做代理&#xff0c;服务治理使用Nacos组件&#xff0c;Gateway网关做权限验证、路由、过滤。 1.2、Redis做消息缓存&#xff0c;包括数据大屏、数…...

Java高级 | 【实验三】Springboot 静态资源访问

隶属文章&#xff1a; Java高级 | &#xff08;二十二&#xff09;Java常用类库-CSDN博客 系列文章&#xff1a; Java高级 | 【实验一】Spring Boot安装及测试 最新-CSDN博客 Java高级 | 【实验二】Springboot 控制器类相关注解知识-CSDN博客 目录 一、Thymeleaf 1.1 是什么&…...

C语言_预处理详解

1. 预定义符号 C语言设置了一些预定义符号&#xff0c;可以直接使用&#xff0c;预定义符号也是在预处理期间处理的 1 __FILE__ //进行编译的源文件 2 __LINE__//文件当前的行号 3 __DATE__ //文件被编译的日期 4 __TIME__//文件被编译的时间 5 __STDC__//如果编译器遵循ANSI…...

将前后端分离版的前端vue打包成EXE的完整解决方案

将若依前后端分离版的前端打包成EXE的完整解决方案 将若依前后端分离版的Vue前端打包成Windows可执行文件(.exe),同时保持与后端API的通信,需要使用Electron框架来实现。下面是详细的步骤和解决方案。 一、准备工作 1. 环境要求 Node.js (推荐v16+)npm 或 yarn若依前后端分…...

物联网协议之MQTT(一)基础概念和设备

前言&#xff1a; 本文内容均以实战出发&#xff0c;像MQTT概念这种基础内容建议大家自行百度。 推荐资料&#xff1a; mica-mqtt文档 一、MQTT简单介绍 作为当今物联网的主流协议&#xff0c;MQTT的使用范围非常广&#xff0c;如果你想了解甚至是从事物联网行业&#xff0c;…...

「Java教案」Java程序的构成

课程目标 1&#xff0e;知识目标 能够按照Java标识符的命名规则&#xff0c;规范变量的命名。能够区分Java中的关键字与保留字。能够对注释进行分类&#xff0c;根据注释的用途合理的选择注释方式。 2&#xff0e;能力目标 能编写符合规范的标识符。能识别Java中的关键字和…...

还原Windows防火墙

还原Windows防火墙 1. 背景2. 为何“还原”完胜“关闭”?三大核心优势3. 还原防火墙默认值操作步骤4. 还原防火墙时,系统背后的工作​5. 需要还原防火墙场景一招拯救混乱网络!还原Windows防火墙,找回你的“安全速度”​1. 背景 你是否曾因一时误操作关闭了Windows防火墙?是…...

区块链可投会议CCF B--EDBT 2026 截止10.8 附录用率

Conference&#xff1a;EDBT: 29th International Conference on Extending Database Technology CCF level&#xff1a;CCF B Categories&#xff1a;数据库&#xff0f;数据挖掘&#xff0f;内容检索 Year&#xff1a;2026 Conference time&#xff1a;24th March - 27th…...

经典ReLU回归!重大缺陷「死亡ReLU问题」已被解决

来源 &#xff5c; 机器之心 在深度学习领域中&#xff0c;对激活函数的探讨已成为一个独立的研究方向。例如 GELU、SELU 和 SiLU 等函数凭借其平滑梯度与卓越的收敛特性&#xff0c;已成为热门选择。 尽管这一趋势盛行&#xff0c;经典 ReLU 函数仍因其简洁性、固有稀疏性及…...

在VSCode中开发一个uni-app项目

创建项目 使用命令行工具&#xff08;例如 vue-cli&#xff09;来创建一个新的 uni-app 项目。 创建以JavaScript开发的工程 npx degit dcloudio/uni-preset-vue#vite my-vue3-project //或者 npx degit dcloudio/uni-preset-vue#vite-alpha my-vue3-project创建以TypeScript…...

quic为什么没有被大规模应用?

一、成本 将应用程序从 HTTP/2 迁移到 HTTP/3&#xff0c;或从 TCP 迁移到 UDP 需要付出一定的努力。它需要将整个应用层实现和传输层实现转换到UDP&#xff0c;并在服务器端和客户端构建一个全新的解决方案。对于资源有限的小型流媒体供应商来说&#xff0c;这是一个不小的挑…...

Delft3D软件介绍及建模原理和步骤;Delft3D数值模拟溶质运移模型建立;地表水环境影响评价报告编写思路

&#x1f4da; 教程以地表水数值模拟软件 Delft3D 4.03.00 的操作为核心内容&#xff0c;系统涵盖地表水水动力建模、基础资料获取、边界条件设定、模型率定与验证以及数据分析处理等关键环节。通过全面讲解&#xff0c;学员将掌握地表水数值模拟的全过程实际操作技术。 &…...

书籍在其他数都出现k次的数组中找到只出现一次的数(7)0603

题目 给定一个整型数组arr和一个大于1的整数k。已知arr中只有1个数出现了1次&#xff0c;其他的数都出现了k次&#xff0c;请返回只出现了1次的数。 解答&#xff1a; 对此题进行思路转换&#xff0c;可以将此题&#xff0c;转换成k进制数。 k进制的两个数c和d&#xff0c;…...

开源模型应用落地-OpenAI Agents SDK-集成Qwen3-8B-function_tool(二)

一、前言 在人工智能技术迅猛发展的今天,OpenAI Agents SDK 为开发者提供了一个强大的工具集,用于构建基于 Python 的智能代理应用。这些代理可以执行从简单任务到复杂决策的一系列操作,极大地提升了应用程序的智能化水平。 通过 OpenAI Agents SDK,可以利用 Python 编程语…...

Python - 爬虫;Scrapy框架之插件Extensions(四)

阅读本文前先参考 https://blog.csdn.net/MinggeQingchun/article/details/145904572 在 Scrapy 中&#xff0c;扩展&#xff08;Extensions&#xff09;是一种插件&#xff0c;允许你添加额外的功能到你的爬虫项目中。这些扩展可以在项目的不同阶段执行&#xff0c;比如启动…...

Spark实战能力测评模拟题精析【模拟考】

1.println(Array(1,2,3,4,5).filter(_%20).toList() 输出结果是&#xff08;B&#xff09; A. 2 4 B. List(2,4) C. List(1,3,5) D. 1 3 5 2.println(Array("tom","team","pom") .filter(_.matches("")).toList) 输出结果为(List(tom,…...

【OSG学习笔记】Day 15: 路径动画与相机漫游

本章来学习下漫游相机。 路径动画与相机漫游 本届内容比较简单&#xff0c;其实就是实现物体的运动和相机的运动 当然这两个要一起执行。 贝塞尔曲线 贝塞尔曲线&#xff08;Bzier curve&#xff09;是一种在计算机图形学、动画制作、工业设计等领域广泛应用的参数曲线&am…...

PostgreSQL(PostGIS)触发器+坐标转换案例

需求&#xff0c;只录入一份坐标参考为4326的数据&#xff0c;但是发布的数据要求坐标必须是3857 对这种需求可以利用数据库触发器实现数据的同步 步骤&#xff1a; 1. 使用ArcGIS Pro创建一个名字为testfc_4326的图层&#xff0c;坐标参考为4326 2. 使用Pro再创建一个名字…...

Constraints and Triggers

目录 Kinds of Constraints Single-Attribute Keys Multiattribute Key Foreign Keys Expressing Foreign Keys Enforcing Foreign-Key Constraints Actions Taken Attribute-Based Checks Timing of Checks Tuple-Based Checks Assertions Timing of Assertion Ch…...

基于windows系统的netcore架构与SqlServer数据库,实现双机热备。

以下是基于 SQL Server Always On 可用性组 和 故障转移群集 的详细配置步骤&#xff0c;用于实现双机热备。 步骤 1&#xff1a;准备环境 1.1 硬件和软件准备 两台服务器&#xff1a;分别作为主服务器和备用服务器。SQL Server版本&#xff1a;确保两台服务器上安装的SQL S…...

【转bin】EXCEL数据转bin

如果DEC2BIN函数的默认设置无法满足需求&#xff08;它最多只能处理10位的二进制转换&#xff09;&#xff0c;可以通过VBA宏方法来处理较大数的二进制转换并提取特定位置的数字&#xff1a; 十进制转二进制&#xff08;不限位宽&#xff09; 1、打开VBA编辑器&#xff08;Al…...

BERT:让AI真正“读懂”语言的革命

BERT&#xff1a;让AI真正“读懂”语言的革命 ——图解谷歌神作《BERT: Pre-training of Deep Bidirectional Transformers》 2018年&#xff0c;谷歌AI团队扔出一篇核弹级论文&#xff0c;引爆了整个NLP领域。这个叫BERT的模型在11项任务中屠榜&#xff0c;甚至超越人类表现…...

【计算机组成原理】SPOOLing技术

SPOOLing技术 关键点内容核心思想通过输入/输出井虚拟化独占设备&#xff0c;实现共享&#xff0c;即让多个作业共享一台独占设备依赖条件1. 外存&#xff08;井文件&#xff09;2. 多道程序设计虚拟实现多道程序技术磁盘缓冲数据流方向输入设备 → 输入井 → CPU → 输出井 →…...

冷雨泉教授团队:新型视觉驱动智能假肢手,拟人化抓握技术突破,助力截肢者重获生活自信

研究背景&#xff1a;日常生活中&#xff0c;健康人依靠手完成对物体的操作。对于手部截肢患者&#xff0c;手部的缺失导致他们难以有效地操作物体&#xff0c;进而影响正常的日常生活。拥有一个能够实现拟人地自然抓取多种日常物体的五指动力假手是手部截肢患者的夙愿&#xf…...

CanvasGroup篇

&#x1f3af; Unity UI 性能优化终极指南 — CanvasGroup篇 &#x1f9e9; 什么是 CanvasGroup&#xff1f; CanvasGroup 是UGUI的透明控制器&#xff0c;用于整体控制一组UI元素的&#xff1a; 可见性 (alpha)交互性 (interactable)射线检测 (blocksRaycasts) &#x1f3af…...

[Java 基础]银行账户程序

编写一个 Java 控制台应用程序&#xff0c;模拟一个简单的银行账户。该程序应允许用户执行以下操作&#xff1a; 查询账户余额。 账户初始余额设置为 1000.0 元。向账户存入资金。 用户可以输入存款金额&#xff0c;程序应更新账户余额。存款金额必须为正数。从账户提取资金。…...

2025.6.4总结

工作&#xff1a;今天效率比较高&#xff0c;早上回归4个问题&#xff0c;下午找了3个bug&#xff0c;晚上二刷了科目一&#xff08;贪吃蛇系统&#xff09;&#xff0c;写了四个点&#xff0c;唯一没达标的就是两自动化没完成。美中不足的是电脑上下载不了PC版的番茄工作软件。…...