今晚不加班——从0到1为公司定制代码生成器

923 阅读5分钟

记一次node+typescript 开发 cli(类似于vue cli)过程

开发背景

此次内容来自公司的一次版本迭代

由于公司flutter开发中状态管理使用的是get(注意,此get非http请求方式的get,属于flutter状态管理器框架)

这次迭代新增了 8 个左右的新页面

先来看看 在项目中新增一个页面 开发人员需要做的操作(以订单列表页面OrderList为例):

  1. 新建四个文件

    image.png

  2. 增加路由配置(找到路由文件,在最下面增加一行代码)

    class GlobalRouter {
      final String welcome = '/welcome';
      final String login = '/login';
      final String feedback = '/feedback';
      ....
      /// 订单列表
      final String orderList = '/orderList';
    }
    
  3. 增加GetPage配置(6行代码 + 导包)

    /// 这里需要导包
    import 'xxxxxx';
    class Global {
      static final List<GetPage> pages = [
        GetPage(
          title: '整体架构',
          name: MyRouters.global.home,
          page: () => HomePage(),
          binding: HomeBindings(),
        ),
        /// 在下面需要配置新写的页面
        GetPage(
          title: '订单列表',
          name: MyRouters.global.orderList,
          page: () => OrderListPage(),
          binding: OrderListBindings(),
        )
      ];
    }
    

    以上代码仅供参考,实际代码OrderList应该配置在对应的业务文件而不是在Global中

    好像也还行,能接受。

    但是此次迭代一共有 8 个这样的页面,没错!是 8 个!!!

    这样一个个加文件,写路由,这能忍???

    image.png

    于是

    果断放弃手上的活(迭代时间比较充裕),花了半天时间来解决这个问题。

    之前在进行小程序开发的时候,有用过工具生成Page,所以也马上就能想到用node生成文件,做成cli的方式来实现它。

开始动手

项目选型

个人还是比较喜欢用ts写(对强类型语言情有独钟),所以此项目的技术选型是 typescript + node

整理需求

总结下来就以下几个功能:

  1. 通过命令行操作
  • (这里可以联想到以前小程序的框架生成页面 xxx -create-page xxxx)
  • 所以我们这里以公司名称命名 jsy-flutter -create <文件夹路径> <文件夹名称> [类名]
    /// 示例
    jsy-flutter -create D://work-proejct/flutter/my-app order_list OrderList
    
    注意:这里有个细节可以处理一下,如果第三个参数 [类名] 没输入,则直接取 文件夹名称 然后转成大驼峰
  1. 根据上面的命令生成下面四个文件,并写入指定代码
  • bindings.dart
  • controller.dart
  • index.dart
  • page.dart
  1. 根据给定的类名,覆盖文件中默认的类名
  • 如下
    class OrderListPage extends GetView<OrderListController>{...}
    
  1. 根据路径写好路由文件
  • 在路由链接文件最后加上路由语句
    class GlobalRouter {
    ......
    /// 订单列表
    final String orderList = '/orderList';
    }
    
  • 在Get路由表中配置,并导入对应的包
    /// 这里导入语句
    import 'package:xxxxxxx/order_list/index.dart'
    
    class Global {
      static final List<GetPage> pages = [
        ......
        GetPage(
          title: '订单列表',
          name: MyRouters.global.orderList,
          page: () => OrderListPage(),
          binding: OrderListBindings(),
        )
      ];
    }
    

搭建项目

创建好文件夹,上来一把梭

初始化项目

初始化项目

// 生成package.json
npm init

// 安装依赖
npm install nodemon --save-dev
npm install typescript --save-dev
npm install concurrently --save-dev
npm install @types/node --save

// 更改package.json scripts
"scripts": {
  "dev:build": "tsc -watch",
  "dev:start": "nodemon dist/index.js",
  "dev": "concurrently npm:dev:*"
},

初始化tsconfig.json配置

// 初始化tsconfig.json文件
tsc --init

// 更改tsconfig.json文件,留下部分配置即可
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./src",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "exclude": [
    "node_modules"
  ]
}

配置文件不过多描述,详情文档点这里

创建入口 index.ts 文件

  • 在项目根目录创建 src 文件夹
  • 创建 /src/index.ts
  • 随便写两个输出语句

测试运行

npm run build

能正常打印即ok

因为我们需要用到命令行工具,所以可以直接用

npm run build

每当.ts文件更新,会自动编译

安装commander

这是一款开源的命令行操作工具,详情文档点这里

npm install commander --save

编写业务逻辑

简单来说就是生成文件,写入字符串内容

这里就不过多展示了,项目已经给你们准备好了 gitee.com/XieTS/jsy-f…

配置 bin

在package.json 文件中加入 bin 配置

"bin": {
  "jsy-flutter": "./dist/index.js"
},

注意:前面的jsy-flutter 随意,后面的入口运行文件路径不能错

在 ./dist/index.js 入口文件首行添加 代码 #!node

#! node
... 下面是逻辑代码

这个千万不能少,否则无法正常运行

本地测试

使用node命令测试

node ./dist/index.js -create d://project order_list

或者

npm link

image.png

命令行输入 jsy-flutter -h

image.png

ok 成功了

删除测试用的命令,亲测 npm unlink 不好用,直接删除文件比较管用

where jsy-flutter

image.png

删除这两个对应的文件,顺带删除上面文件夹中 node_modules 内的 jsy-flutter 文件

搞定!接着发布到 npm

发布到 私有库 / 公开库

npm publish

全局安装依赖

npm install jsy-flutter -g

接下来就可以在任意地方使用 jsy-flutter 命令

下面测试一下我们的成果

jsy-flutter -create D://project/ order_list OrderList

image.png

搞定!!!

image.png

思路总结

整个的开发实际上比较简单,就是写好一些指定代码,通过node的fs模块创建文件,并写入文件,路由修改的逻辑稍微复杂一点点,但实际上我们能拿到所有需要的数据就能

写在最后

其实在我们的日常开发过程中,有很多类似这样的重复操作,这种操作对于我们自身不会有任何的提升,就是一味地浪费自己的时间,我们更多的可以使用代码去完成这些事,这里只是一个小小的案例,接下来会根据公司实际情况,创造出更多的cli工具,解决我们日常开发大量cv的过程!

奋斗吧,前端人!