您的位置:首页 > 编程语言

写一个umi插件 自动生成代码 解放cv的双手

2019-12-09 17:51 2091 查看

引言

最近在写一个中台项目,使用的

react
umi
框架。
各种增删改查。基本是列表页 新建页 详情页这种页面
为了避免不必要的简单重复(主要是想偷懒) 于是想去实现自己的一个代码生成器

探索

首先,在官网上看到了官方写的一个生成器

再去源码里扒一扒 找到关键所在

简而言之,就是利用插件的

api
注册了一个生成model的指令,生成器指向目录里的
model.js

代码如下

import { join } from 'path';
import assert from 'assert';

export default api => {
const { paths, config } = api;
const absTemplatePath = join(__dirname, '../template/generators');

return class Generator extends api.Generator {
writing() {
...
// 判断目录名是models还是model
const models = config.singular ? 'model' : 'models';
const name = this.args[0].toString();
...
// 将模板目录下里的model代码 拷贝到项目的model目录下 并命名为指令输入的文件名
this.fs.copyTpl(
join(absTemplatePath, 'model.js'),
join(paths.absSrcPath, models, `${name}.js`),
{
name,
},
);
}
};
};
../template/generators/model.js

export default {
state: '<%= name %>',
subscriptions: {
setup({ dispatch, history }) {
},
},
reducers: {
update(state) {
return `${state}_<%= name %>`;
},
},
effects: {
*fetch({ type, payload }, { put, call, select }) {
},
},
}

model是一个常规的

dva
model

里面的
<%= name %>
ejs
语法,对应着
copyTpl
方法的第三个参数中的
name

模板js里的这个占位会被参数
name
替换

因为我们项目中习惯将model写到模块文件夹下,而且model里的代码有些我们的自己的书写
所以需要自定义一个生成方法了。

上手

以下是我写的一个生成规则

import { join } from 'path';
const fs=require('fs');
export default api => {
const  {paths} = api;
const configPath=join(paths.absSrcPath,'generatorConfig.js');
const absTemplatePath = join(__dirname, '../template/generators');
return class Generator extends api.Generator {
writing() {
const name = this.args[0].toString();
// assert(!name.includes('/'), `model name should not contains /, bug got ${name}`);
const type =this.args[1]&& this.args[1].toString();
// type即为命令后跟的参数
switch (type) {
case 'list':
if(!fs.existsSync(configPath)) {
api.log.error('新建列表模板缺少generatorConfig.js')
return
}
const genConfig=require(configPath);
this.fs.copyTpl(join(absTemplatePath, 'list.js'),join(paths.absSrcPath, `pages/${name}/${type}`, `index.js`), {
name,
queryFormItems:genConfig[name]['queryFormItems'],
columns:genConfig[name]['columns']
});
}
this.fs.copyTpl(join(absTemplatePath, 'model.js'), join(paths.absSrcPath, `pages/${name}`, `model.js`), {
name
});
this.fs.copyTpl(join(absTemplatePath, 'index.less'), join(paths.absSrcPath, `pages/${name}`, `index.less`), {
name
});
this.fs.copyTpl(join(absTemplatePath, 'service.js'), join(paths.absSrcPath, `pages/${name}`, `service.js`), {
name
});
}
};
};

添加了如下功能

  • 结合项目中的目录结构约定进行目录生成(比如我们约定用service来进行接口方法管理)
  • 增加在命令后面加不同参数 生成不同的特征模块(比如列表 详情)
  • 增加了配置项 可以在node环境下去读取配置 再生成到代码里去(比如
    antd
    的列表的
    columns

再仿照

umi-dva-plugin
的流程进行
命令注册
插件导出

import { join } from 'path';
export default(api, opts = {})=> {
api.registerGenerator('dva:newPage', {
Generator: require('./model').default(api),
resolved: join(__dirname, './model'),
});
}

遇到问题

在探索和上手遇到挺多问题,总结如下
1.阅读源码 加以甄别 ,因为

umi-dva-plugin
的代码贼多,模板功能只是其中的非核心功能,所以也是看了好几遍 发现这个功能其实和其他代码并不存在耦合 可以单独提出来
2.探索模板语法 一开始不知道是
ejs
找了下
copyTpl
方法

然后就恍然大悟,怪不得看起来那么熟悉,顺便学了一下ejs模板
<%= %>
<%- %>
的区别
3.兼容性问题 遇到的一个贼奇怪的问题 node环境兼容的问题
一开始不知道 用babel转成es5了 一直报错
class constructor Generator cannot be invoked without 'new

看上去就是个兼容问题 然后用web版的babel转换器 关闭
preset es2015
调整
node版本
6.4
主要是把对象的
解构赋值要转换掉
不然依赖的三方
Generator
可能不认

总结

现在看来其实写这个插件其实并不难,但是在当时很多知识都不了解的情况下去看,确实还是有些许棘手,了解用法和原理比较有挑战,毕竟不是自己写的代码,所以还是要加强代码方便的阅读。

项目链接

戳我查看

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐