Node还能用来摸鱼?(适用部分大量重复工作的数据展示项目)

1,120 阅读3分钟

20年下半年做了好多b端项目,大多数都是数据展示页面,这样的过程实在是枯燥无味,负责相关项目的全栈大佬及我这个前端菜逼也是"饱受折磨",虽然都是ctrl C+V的功能,但是遭不住量大啊...

解决方向

公司技术栈从Vue转型到React之后,后台管理页面项目的目光也从vue系列UI库的Pro Admin方向聚焦到Umi及Ant Pro相关

本着能少写代码就少写的理念,开始打起了生成代码的念头,毕竟能多点摸鱼的时间是一点多给自己提升能力的机会是好的

Umi Ui可视化编程辅助工具的影响,我们这种大量C+V的功能也可以写一个类似一键生成代码的脚本

因为是自用,主要是记录一下这种思路,所以没有太多繁琐的逻辑和边界判断,整个过程很快啊,pa的一下就好了~

该文章只适合大量逻辑相同的展示页面,大量逻辑不相同的页面本身也不适合生成对不对 <_<

目录结构

|-- result
|-- template
	|--index.js
|-- index.js
// * result  用来放置生成结果的文件夹
// * template  用来放置需要生成的模板文件
// * template/index.js  用来举例用的文件
// * index  入口文件

我们可以用Node的什么?

主要用node的fs模块,我们需要用到的api:

  • access 测试用户对 path 指定的文件或目录的权限
  • readdir 读取目录的内容
  • mkdir 异步地创建目录
  • readFile 异步地读取文件的全部内容
  • writeFile 异步地将数据写入到一个文件,如果文件已存在则覆盖该文件
writeFile 中的data 可以是字符串或 buffer 这个地方是重点

支棱起来

准备工作做得差不多了,把这几个api拼接起来就是我们想要的了

  • 先用access函数检查一下我们的输出/输入目录是否存在,否则给它建一个
// * index.js
const start = ({ sourceURL, targetURL, sourceData }) =>
  fs.access(targetURL, (err) => {
    if (err) { // *不存在进行mkdir
      fs.mkdir(targetURL, () => {
        copy({ sourceURL, targetURL, sourceData });
      });
    } else { // *已存在进行copy
      copy({ sourceURL, targetURL, sourceData });
    }
  });
  • 接着完善copy函数
// * index.js
const copy = ({ sourceURL, targetURL, sourceData }) =>
  fs.readdir(sourceURL, (err, paths) => { // *读取目录
    if (err) {
      if (err.code === 'ENOENT') {
        console.error('源路径不存在');
        return;
      }
  
      throw err;
    };

    paths.forEach(path => { // *遍历readdir反馈的结果
      const _source = `${sourceURL}/${path}`, // *本次输入地址
        _target = `${targetURL}/${path}`; // *本次输出地址

      fs.stat(_source, (err, st) => { // *读取文件状态,我们要区分本次操作的是目录还是文件
        if (err) {
          console.error(`目标: ${_source} 状态:读取状态失败`);
          return;
       	}

        if (st.isFile()) { // *判断是否为文件
          fs.readFile(_source, 'utf8', (err, data) => { // *读取文件的数据
            if (err) {
                console.error(`目标: ${_source} 状态:读取失败`);
                return;
             }

            // *替换开始---
            // *code...
            // *替换结束---
            
            // !为新地址生成文件
            fs.writeFile(_target, data, 'utf8', (err) => {
              if (err) {
                console.error(`目标: ${_target} 状态:写入失败`);
                console.log(`\u001b[42m biu \u001b[0m目标: \u001b[34m${_target}\u001b[0m 状态: \u001b[31m写入失败\u001b[0m`)
                return;
              }
              
              console.log(`\u001b[42m biu \u001b[0m目标: \u001b[34m${_target}\u001b[0m 状态: \u001b[32m写入成功\u001b[0m`)
            });
          });
        } else if (st.isDirectory()) { // *如果是目录则递归调用自身
          start({
            sourceURL: _source,
            targetURL: _target,
            sourceData,
          })
        }
      });
    });
  });

搞到这里一个基本的文件查找/读取/写入已经完成了,最重要的一步“如何把模板文件替换成我们需要的文件”

正则替换文件内容(摸鱼核心)

我们在readFile函数中可以得到正常的文件信息,然后可以用replace去替换指定内容,完成大量相同逻辑页面的一键生成

// * index.js

// *定义我们要替换的数据
const sourceData = {
  btnTitle: '天猫商品TOP10',
};

// !中间省略部分重复代码...

// *替换开始---
const { btnTitle } = sourceData;
data = data.replace(/__btnTitle__/, JSON.stringify(btnTitle));
// *替换结束---
// * template/index.js
// * 大量代码省略
<Button>__btnTitle__</Button>
// * 大量代码省略

__btnTitle__是在文件中需要用来替换数据的占位符,可以根据自己喜好,随便写,只要可以和index.js中的replace对上号即可

完事运行node index.js,查看result文件夹的内容,直接✈✈✈

这时候就有会人说,你这还是要配置sourceDate才可以,和C+V没啥区别啊,不慌,这时候可以给后台大佬商量下,让他直接给你对应页面的sourceDate,让他按照这个格式给你,省了写swagger的时间了,什么?你说swagger都是自动化生成的,那也不慌,“矿刷新了,用钟师傅带他挖矿”🤣,总知,要么后台老哥人好我们啥都不用写直接node一下就好,不然自己就动手搞一下sourceData也好

脚本扩展

上面例子写了一个很简单的替换功能,开发中预设好字段就可以一键替换【api接口/table的Columns配置/文案】等等,或者直接给sourceURL/targetURL路径改为实际项目页面存放的页面都是可以的,至于脚本生成出来的文件格式不好看,这个好说,不是有eslint嘛

关键是看自己工作中遇到啥,能搞就搞,不能搞还是要老老实实的写嘛