厌烦了Ctrl+CV ?试试用node自动生成重复代码文件

2023-11-17

前言

相信在我们日常遇到的项目中,无论是在前端网站还是后台管理系统中都会有功能类似的页面。我们在开发这些功能类似的页面的时候,为了提高效率,一般都会运用我们的CV大法。但是当我们CV久了之后,会不会觉得这样的开发方式有些许枯燥?我们能不能通过代码来生成代码,进一步提高我们的效率呢?下面我们就来通过一个例子来探索一下怎么通过node来生成我们需要的前端代码。

实例

假设我们正在做一个后台管理系统(react),页面文件目录结构如下图:

image

page文件夹下有两个文件夹:home和network,他们分别代表了不同的模块。稍微观察一下,我们不难发现,这两个模块下面的文件目录结构是一样的,而且部分文件名也是一样的。有些人面对这种情况,包括最开始开发项目的我,可能会想,直接CV,简单快捷。但是这一次,咱先不急,我们再看看js文件需里面的需要的初始代码:

结构基本一样,但是模块和组件的名称却不一样。

在上面的这种情况下,我们是可以对类似的文件夹以及文件进行复制粘贴,但是我们也必须针对不同的模块和组件进行重命名等操作,页面文件少还好说,但是当页面比较多的时候,比如有七八个模块以及几十个页面的时候,我们进行这些无意义的重复操作,会不会比较难受?

所以我们能否想想办法,尽可能的规避这些操作?

泰伦卢:办法?当然是把球传给詹姆斯!

开个玩笑。首先,我们应该再仔细分析一下pages下面的文件,home和network文件夹下面有着相同的文件目录结构,但是部分文件夹下面的文件名称以及内容可能不一样。这有点类似与组件的复用,so我们是否可以利用类似组件复用的思想,编写一个统一的模板,然后给其传递不同的参数,就可以生成不同的组件。

基本思路如下图:

通过配置参数的形式来配置我们的文件夹名称、文件名以及文件模板的参数,然后再一键生成我们的文件夹、文件和文件的内容。

node API

基本思路确定,但是我们怎么去自动生成文件夹和文件呢?我相信后端的小伙伴肯定不陌生,而前端的小伙伴平时在业务中对于这方面的知识可能涉及的就比较少了。但是只要熟悉node,这一切都不是问题了。

这里我们就可以利用node的fs(文件系统)API来帮助我们做这些事。

创建目录

在node中创建文件(目录)夹有两种方式:

第一种(异步):fs.mkdir(path[, options], callback)

参数

  • path - 文件路径。
  • options 参数可以是:
    • recursive - 是否以递归的方式创建目录,默认为 false。
    • mode - 设置目录权限,默认为 0777。
  • callback - 回调函数,没有参数。

基本用法

fs.mkdir('/pages/home', (err) => {
  if (err) throw err;
});

第二种(同步):fs.mkdirSync(path[, options])

基本用法

fs.mkdirSync('/pages/home');

创建文件

创建文件也有两种方式:

第一种(异步):fs.writeFile(file, data[, options], callback)

参数

  • file - 文件名或文件描述符。
  • data - 要写入文件的数据,可以是 String(字符串) 或 Buffer(缓冲) 对象。
  • options - 该参数是一个对象,包含 {encoding, mode, flag}。默认编码为 utf8, 模式为 0666 , flag 为 ‘w’
  • callback - 回调函数,回调函数只包含错误信息参数(err),在写入失败时返回。

基本用法

fs.writeFile('文件.txt', '你好~', (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

第二种(同步):fs.writeFileSync(file, data[, options])

基本用法

fs.writeFileSync('文件.txt', '你好~');

生成目录和文件

基本的知识我们已经有所了解,接下来就可进行代码的编写了。当然电脑上需要有node环境,关于node环境一般来说大家都应该配置的有,如果实在没有网上搜一下就OK了~

建立项目文件

首先搭建好我们的项目:

主要关注红框里面的文件夹和文件

  • index.js为我们的主程序,文件夹(目录)和文件的生成的程序逻辑都在里面,也是最终运行的文件
  • pages里面为我们生成的文件夹(目录)和文件
  • template里面有两个文件
    • data.js为我们的配置文件,包含了文件夹(目录)和文件名称以及文件模板的参数等配置
    • template.js为我们的各种文件的模板

这里说一下,因为我们这里是假设是在react的项目下,所以其它的文件基本上是与react相关的。红框里面的代码逻辑与react不耦合,其它框架下也同样适用。

生成文件夹(目录)

回到开始的实例,我们需要在pages文件夹下生成下图格式种的文件夹和文件:

这里需要注意的是,无论是fs.mkdir()还是fs.mkdirSync(),他们都是已有的文件夹上进行创建的,例如我们要在pages下创建list文件夹,我们不能直接如下所写:

index.js

const fs = require("fs");
fs.mkdirSync('./page/home/list'); //报错

因为这里的home文件夹是不存在的,所以list文件夹也不会创建成功。正确的应该这样写:

const fs = require("fs");
fs.mkdirSync('./page/home'); 
fs.mkdirSync('./page/home/list');

当然我们不可能直接就这样来写,我们可以利用递归的方式来创建目录:

index.js

const fs = require("fs");
const path = require("path");

function mkdirsSync(dirname) {
    if (fs.existsSync(dirname)) { // 这里是检测文件目录是否已经存在
        return true;
    } else {
        if (mkdirsSync(path.dirname(dirname))) {
            fs.mkdirSync(dirname);
            return console.log(`创建目录成功-${dirname}`);
        }
    }   
}
mkdirsSync('./page/home/list');

接下来是配置文件:

data.js

exports.data = [
    {
        folder:'home',
    },
    {
        folder:'home/list',
    },
    {
        folder:'home/images'
    },
    {
        folder:'home/form',
    },
    {
        folder:'network',
    },
    {
        folder:'network/list',
    },
    {
        folder:'network/images'
    },
    {
        folder:'network/form',
    }
]

引入配置文件,并进行遍历生成文件:

index.js

const fs = require("fs");
const path = require("path");
//引入配置文件
const profileData = require("./template/data");
// 递归创建目录 同步方法
function mkdirsSync(dirname) {
    if (fs.existsSync(dirname)) {
        return true;
    } else {
        if (mkdirsSync(path.dirname(dirname))) {
            fs.mkdirSync(dirname);
            return console.log(`创建目录成功-${dirname}`);
        }
    }   
}
//遍历配置文件并调用创建目录方法
profileData.data.forEach((item) => {
    if(item.folder){
        mkdirsSync(`./pages/${item.folder}`)
    }
})

生成文件

我们把目录生成了,生成文件时就主要关注于文件名和文件内容就行了。首先我们要定义好文件的模板,这里主要要用到模板字符串(``)。因为其中的一些文件内容种的 class的名称不一样, 所以在定义模板的时候, 可以为这类模板定义一个参数, 如下所示的className :

template.js

exports.page = function (className) {
    return `
import * as React from 'react';

export class ${className} extends React.Component{
    constructor(props){
        super(props);

        this.state = {}
    }

    componentDidMount(){

    }

    render() {
        return (
            <div></div>
        )
    }
}
    ` 
}

exports.api = `const API = "localhost://8080/my-api";`

exports.route = `
import * as React from 'react';

export const route = [];
`

模板定义好后, 继续在配置文件data.js添加相应的阿配置项,如下所示的fileclassName:

data.js

exports.data = [
    {
        folder:'home',
        file:'api.js'
    },
    {
        folder:'home',
        file:'route.js'
    },
    {
        folder:'home/list',
        file:'home.js',
        className:'Home'
    },
    {
        folder:'home/images'
    },
    {
        folder:'home/form',
        file:'modal.js',
        className:'homeModal'
    },
    {
        folder:'network',
        file:'api.js',
    },
    {
        folder:'network',
        file:'route.js'
    },
    {
        folder:'network/list',
        file:'network.js',
        className:'Network'
    },
    {
        folder:'network/images'
    },
    {
        folder:'network/form',
        file:'modal.js',
        className:'networkModal'
    }
]

最后进行的就是文件生成代码的编写:

index.js

const fs = require("fs");
const path = require("path");
//引入配置文件
const profileData = require("./template/data")
//引入文件模板
let template = require("./template/template");
let page = template.page;
let api = template.api;
let route = template.route;


//遍历创建文件
profileData.data.forEach((item) => {
    if(item.file){
        //创建API文件
        if(item.file.indexOf("api") != -1){
            fs.writeFile(`./pages/${item.folder}/${item.file}`, api, function(err){
                if(err){
                    return console.log('创建失败', err);
                }
                console.log(`创建文件成功!-${item.file}`);
            })
        }
        
        //创建route文件
        if (item.file.indexOf("route") != -1){
            fs.writeFile(`./pages/${item.folder}/${item.file}`, route, function(err){
                if(err){
                    return console.log('创建失败', err);
                }
                console.log(`创建文件成功!-${item.file}`);
            })
        }

        //创建主体页面
        if (item.className){
            fs.writeFile(`./pages/${item.folder}/${item.file}`, page(item.className), function(err){
                if(err){
                    return console.log('创建失败', err);
                }
                console.log(`创建文件成功!-${item.file}`);
            })
        } 
    }
})

最后, 我们可以直接运行index.js:

我们可以看见控制台打印出来的信息是是我们创建成功了文件夹(目录)和文件, 最后在看看pages文件夹下面的目录与文件:

我们可以把的到的目录和文件与开始实例中的文件相对比, 发现我们已经成功生成了想要得到的目录和文件了~

大功告成~

完整的代码和例子我已经放在了我的GitHub上面了,小伙伴们可以根据自己的实际需求来进行修改,提高自己的开发效率。

参考

https://www.runoob.com/nodejs/nodejs-fs.html

http://nodejs.cn/api/fs.html

最后

上述通过文件配置和模板调用的方式,自动生成了重复的代码文件。这种方式在一定程度上可以减少我们复制粘贴的重复劳动,提高我们的工作效率。这种方式也是我在开发中的一种尝试,其中还有很多不足之处。如果有小伙伴在工作中也有过类似提高开发效率的尝试,欢迎和大家一起分享~

文中若有错误的地方,也欢迎提出来~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

厌烦了Ctrl+CV ?试试用node自动生成重复代码文件 的相关文章

随机推荐

  • 基于SpringBoot的共享单车管理系统

    末尾获取源码 开发语言 Java Java开发工具 JDK1 8 后端框架 SpringBoot 前端 采用HTML和Vue技术开发 数据库 MySQL5 7和Navicat管理工具结合 服务器 Tomcat8 5 开发软件 IDEA Ec
  • 《剑指Offer》62:圆圈中最后剩下的数字(约瑟夫环)

    题目 0 1 2 n 1这n个数字排成一个圆圈 从数字0开始 每次从这圆圈你删除第m个数字 求出这个圆圈里剩下的最后一个数字 例如 0 1 2 3 4这5个数字组成一个圆圈 从数字0开始每次删除第3个数字 则删除的前4个数字依次2 0 4
  • 踩了大坑:https 证书访问错乱

    文章目录 一 问题排查及解决 问题一 证书加载错乱 问题二 DNS 解析污染问题 问题三 浏览器校验问题 二 终极解决方法 2 1 可外网访问域名 2 2 只能内网访问域名 2 3 内网自动化配置 2 4 错误解决 一 问题排查及解决 今天
  • 用SpringBoot开发工商银行平台公众号及小程序埋名聚合支付(微信小程序支付)

    因为项目需求的原因 需要开发小程序支付 采取的支付流程是用工商银行 以下简称工行 的埋名聚合支付 接口 进行小程序支付开发 工行 开发指南业务申请 https open icbc com cn icbc apip docs intro ht
  • 阿里云配置MINIO图床

    阿里云 ECS服务器 CENTOS7系统部署MINIO图床 1 下载MINIO的二进制文件 注 阿里云ECS网速过慢 但可以接受 wget https dl minio io server minio release linux amd64
  • AES加密,128-192-256,方案一

    AES加密 直接粘贴代码 异常什么的自己要处理 做个总结记录 package com xiao aes util import java io UnsupportedEncodingException import java securit
  • jmeter压测报错socket closed解决方法

    socket closed 问题原因 在JMeter下 发送http 请求时 一般都是默认选择了use keepAlive 这个是连接协议 JMeter坑就在这里 默认勾选了这个 如果不勾选的话 也不会保存 但其配置JMeter prope
  • 6个Python代码简化方法

    ython开发代码简化除了采用规范化的编程规则之外 代码编写的逻辑性和对内置规则的掌握也对其有一定的影响 以下是Python3支持的用法 合理的利用可以极大的简化代码的书写复杂度 列表推导式 对于一组列表 如果想让其所有元素翻倍 很多人都会
  • A notion of time

    1 simulation kernel用sc time数据类型来跟踪仿真时间 指定delay和timeouts sc time是用一个64bit的无符号整型数来表示 SC SEC seconds 10 0 秒 SC MS milliseco
  • 接口测试:postman发送POST请求

    Postman发送POST请求 postman发送POST请求 示例 微信公众平台创建用户标签接口 业务操作如下 1 打开微信公众平台 微信扫码登录 2 打开微信开放文档 找到用户管理 用户标签管理的接口信息 3 打开postman 新建一
  • 谷歌Chrome浏览器安装插件Hackerbar

    谷歌Chrome浏览器安装插件Hackerbar 因为google浏览器的应用市场 https chrome google com webstore category extensions 在国内无法访问 所以无法在线安装插件 这里提供开发
  • 刷脸和无感支付是社会科学发展的产物和动力

    手机支付不应该多过 而且有自动与支付余额联机 刷手机才是赚钱的出路 对比来看 手机支付操作简单但基础好 有相当多用户加入的话 就没有任何风险了 自动与支付余额联机有效 而对于支付余额联机更有效 但比安全性较低 不利于用户操作 而对于与银行合
  • python打包whl文件

    应用场景 在python的使用过程中 当遇到通过pip无法安装包 可以通过去Python安装包大全中 whl包下载 下载 whl 包来安装解决问题 也可以在别处打包成 whl 文件 拷贝过来运行 介绍 whl 文件是以 wheel 格式保存
  • PySerial:Python串口通信库的详细介绍、安装及使用方法攻略

    PySerial Python串口通信库的详细介绍 安装及使用方法攻略 一 PySerial 简介 PySerial 是 Python 的一个串口通信库 支持不同平台下的串口操作 在 Python 应用中 使用 PySerial 可以非常方
  • 《Programming in Lua 3》读书笔记(七)

    Compilation Executioin and Errors Lua的assert函数 assert v mess 相当于C的断言 当v为nil或者false将触发错误 mess为发生错误时返回的信息 dofile函数不仅会加载chu
  • 蓝桥杯中的阶乘(求1000的阶乘)

    首先这个题 它是求1000的阶乘 他最后的值太大了 以至于不能用int long long int 来求 那要怎求呢 那肯定是用最简单的数组来求鸭 用数组来代表它的每一个位 include
  • 如何判断链表有环

    如何判断单链表是否存在环 有一个单向链表 链表当中有可能出现 环 就像题图这样 如何用程序判断出这个链表是有环链表 不允许修改链表结构 时间复杂度O n 空间复杂度O 1 方法一 穷举遍历 方法一 首先从头节点开始 依次遍历单链表的每一个节
  • 网关模式/网桥模式/旁路模式的区别

    网关模式 网桥模式 旁路模式的区别如下 EG设备有三种工作模式 网关模式 网桥模式和旁路模式 比较常用的是网关模式和桥模 式 1 网关模式是把设备当作网络出口 支持NAT和路由选路下报文转发的部署方式 2 桥模式是把设备作为桥接 串接在内网
  • 【SqlServer】如何把本地SqlServer数据库部署到远程服务器上

    这里笔者使用的使用SqlServer2012 本机和远程环境均为Win7 1 选中需要部署的数据库 右击 任务 分离 选中删除连接 2 现在在左侧的表中就看不见刚才那个数据了 3 在本地找到分离出来的数据库的位置 该位置就是读者建立数据库的
  • 厌烦了Ctrl+CV ?试试用node自动生成重复代码文件

    前言 相信在我们日常遇到的项目中 无论是在前端网站还是后台管理系统中都会有功能类似的页面 我们在开发这些功能类似的页面的时候 为了提高效率 一般都会运用我们的CV大法 但是当我们CV久了之后 会不会觉得这样的开发方式有些许枯燥 我们能不能通