React项目优化(5)-使用PlopJs生成模板文件

807 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

上一篇:React项目优化(4)-使用错误边界(ErrorBoundry)解决白屏问题


1、PlopJs是什么 ?

简而言之:PlopJs是一个根据模板生成代码的工具。只需要安装一个依赖包,写一个配置文件。就可以执行 plop 命令生成代码。

2、我为什么要使用PlopJs

  1. 项目特点

    项目的功能能节点多,其中每一个功能节点(模块)都是一个独立的单页面应用,这些单页面应用彼此独立,但是目录结构相同,除了具体的业务逻辑不同以外,其他的诸如: service.jsmodel.jsapp.jsapi.http 等文件内容基本一致。 即使不一致,也有很强的规律性。

image.png

  1. 方便管理

    每个开发的操作习惯不一致。对代码的理解程度不一样,解决思路不一致,导致原本相同的事情,会出现不同的版本,甚至导致不同的BUG出现。或许开发者A已经解决的问题,开发者B会重新处理一次。
    如果能够直接通过脚手架生成基础性的代码。那些规律性的,可预见的基础问题,在代码生成时,就一次性解决的,这是不是很哇塞。

  2. 开发效率

    开发中,机械性的、重复性、复制、粘贴的体力劳动比较多,同时开发效率有比较低。所以,有必要通过plopJs解放劳动力。

    所以说:使用PlopJs生成代码,可以提高开发效率,统一代码风格,规避一些不必要的错误。

3、项目实战

安装依赖

可以全局安装,也可以在项目中安装

   npm install -g plop // 全局安装

示例一:牛刀小试,生成一个组件模板

  1. 在项目的根目录下新建文件夹命名为plop-template
  2. plop-template新建Component文件夹
  3. Component文件夹下新建两个文件plop.jsindex.hbs
  4. 其中plop.js 是用于配置交互收集处理的模块
    代码如下:
module.exports = {
  description: "生成React组件",
  prompts: [
    {
      type: "input", // 交互类型
      name: "name", //参数名称
      message: "请输入组件名称:", // 交互提示
    },
  ],
  actions: (data) => {
    const name = "{{ name }}"; // 这个变量来之控制台输入,在模板文件中可以使用。
    return [
        {
          type: "add",  // 新增文件
          path: `ucf-common/src/components/${name}/index.js`, // 生成文件的路径
          templateFile: "plop-template/component/index.hbs", // 模板文件的路径
        },
        {
          type: "add",
          path: `ucf-common/src/components/${name}/index.less`,
          templateFile: "plop-template/component/style.hbs",
        },
   ];
 },
};
  1. 其中index.hbs是模板文件,生成的文件是啥样,由它决定。

模板文件是 HandleBars文件。了解更多
简单说: 把你希望生成的文件的后缀名改成hbs。 内容中使用双花括号{{}}语法来读取变量。

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Classnames from "classnames";
import { Button } from 'tinper-bee';
import './index.less'
import { Error } from "utils";
const propTypes = {
	title: PropTypes.string,//
};
const defaultProps = {
	title:"标题",
};

// 组件模板
class {{properCase name}} extends Component {
  constructor(props) {
    super(props);
	this.state = {

	};
  }
  componentDidMount() {
    // componentDidMount...
  }

  render() {
	let {title}=this.props;
	return (
	  <div className="{{dashCase name}}-wrap">
		<span>Test</span>
    <span>{{a}}</span>
	  </div>
    )
  }
}

{{properCase name}}.propTypes = propTypes;
{{properCase name}}.defaultProps = defaultProps;
export default {{properCase name}};

配置文件编写

在项目的根目录下新建plopfile.js配置文件 使用plop.setGenerator这个方法将模板文件注入,再讲这个模块导出即可。

代码示例如下:

// 1. 引入写好的组件配置
const compGenerator = require("./plop-template/component/prop");
module.exports = function (plop) {
 // 使用生成器,注入配置[component为名称]
 plop.setGenerator("component", compGenerator); // 生成React组件文件模板
}

生成模板操作

打开控制台运行plop命令,根据提示输入相应内容即可

easy.gif

示例二:大显身手,生成项目文件夹

基本步骤与生成一个组件一致,但是有如下不同。

  1. 生成的是一组有不同层级的文件,而非一个文件。
  2. 生成的项目文件夹之前前需要输入一系列的提示项,传入较多的变量。
  3. 命令行输入时,增加提示语,默认值,长度及合法性校验方法。
  4. 处理输入字符外,提供了类似下拉选的单选模式。

配置文件代码示例:

module.exports = {
  description: "生成节点模板",
  prompts: [
    {
      type: "input",
      name: "nodeName",
      message: "请输入文件夹名称[eg:fls-contract]",
      default: "fls-demo",
      validate: function (val) {
        if (/.+/.test(val)) {
          if (val.length < 6 || val.length > 20) {
            return "文件夹名称长度[6-20]的小写英文单词";
          }
          return true;
        } else {
          return "文件夹名称不能为空!";
        }
      },
    },
   
    {
      type: "input", // 交互类型,字符输入
      name: "funCode", //参数名称
      message: "请输入节点编码[eg:fls0001]", // 交互提示
      default: "fls0000",
      validate: function (val) {
        if (!!val && val.length == 7) {
          return true;
        } else {
          return "请保持节点编码长度为7";
        }
      },
    },
    {
      type: "list", // 交互类型: 上下键选择
      name: "server", //参数名称
      message: "请选择后端服务:", // 交互提示
      choices: [
        "imfbp-fls-before-web",
        "imfbp-fls-after-web",
        "imfbp-crm-web",
        "imfbp-invoice-web",
      ],
      default: "imfbp-fls-before-web",
    },
  ],
  actions: (data) => {
    const nodeName = "{{ nodeName }}";
    return [
      {
        type: "addMany", // 增加多个文件
        base: "plop-template/layout/", // 生成,目标路径会去掉这写路径
        stripExtensions: true,
        destination: `ucf-apps/${nodeName}/`, // 目标路径
        templateFiles: "plop-template/layout/src/**/**",  // 配置的模板文件路径.
      },
    ];
  },
};

模板文件夹目录:

image.png

如果需要一些特殊的逻辑处理,可以通过plop.setHelper校验方法:

// 方法:用于根据输入的前缀获取请求数据的常量
  plop.setHelper("getConstPrefix", function (text) {
    let retText = "";
    switch (text) {
      case "imfbp-fls-before-web":
        retText = "GROBAL_FLS_BEFORE_HTTP_CTX";
        break;
      ...
      default:
        retText = "模板文件未配置";
        break;
    }
    return retText;
  });
  // 方法:用于在模板中输出双花括号格式
  plop.setHelper("bracket", function (num, options = num) {
    const i = Number.isInteger(num) ? num : 1;
    const open = "{".repeat(i);
    const close = "}".repeat(i);
    return `${open}${options.fn(this)}${close}`;
  });

生成代码操作

test4.gif

总结

使用 PlopJs 生成文件的过程不复杂,如果在使用中需要问题,查看官方的文档即可:
PlopJs官方文档
HandleBar官网

4、其他问题

使用plopJs可以根据模板生成代码。但是随之而来的是另一个问题,由于我们项目中业务逻辑比较复杂,尤其是其中的表单和表格,一个表单中表单项动辄几十个。每一手写或复制也是不小的工作量, 如果能够根据后端的字段通过某种方式直接生成表单。那将是开发效率的又一次提升。

具体如何实现? 下一篇文章见!