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

3,283 阅读7分钟

前言

相信在我们日常遇到的项目中,无论是在前端网站还是后台管理系统中都会有功能类似的页面。我们在开发这些功能类似的页面的时候,为了提高效率,一般都会运用我们的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上面了,小伙伴们可以根据自己的实际需求来进行修改,提高自己的开发效率。

参考

www.runoob.com/nodejs/node…

nodejs.cn/api/fs.html

最后

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

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