10分钟快速搭建出提高生产效率的 CLI 工具

背景

先来说说为什么我要开发一个 CLI 工具

之前因为业务需求,开发过一段时间的 Koa 项目,由于需要不停的在新老项目之间进行切换,也就经常不避免的会产生了一些重复性的工作,比如

  • 创建新项目
  • 集成项目所需依赖
  • 添加各种项目规范
  • 添加各种配置文件
  • 编写大量重复代码
  • 配置项目打包发布
  • ...

结合以上 10086+ 个痛点,经过简单的构思和研究,我开发出了属于自己的 CLI

  • nost-cli:基于 Koa 的 nodeJs 框架

目的很简单,就是为了简化开发流程,提高生产效率。

虽然现成的 node 框架也很香,但是我不管,我就要卷!!!

预览

现已发布至 npm,可通过 npm install -g nost-cli 安装体验!!!

思路

通过 npm package 的形式进行安装使用

  • 创建项目:可以快速帮我创建一个规范的 koa 项目,开箱即用

  • 运行项目:可以帮我在开发环境下运行该项目并进行实时的热更新

  • 打包项目:可以帮我在即将发布生产环境时进行代码生成和压缩

  • 文件创建:

    • 快速创建 router 模版进行请求和参数处理
    • 快速创建 controller 模版进行内部逻辑处理
    • 快速创建 service 模版进行数据库相关操作
    • 快速创建 middleware 模版进行自定义中间件的编写
    • 快速创建 error 模板进行自定义错误处理
    • 快速创建 config 文件用于新增项目配置
  • 信息查看:

    • 版本信息
    • 更多帮助

nost-cli

nost-cli核心步骤实现

第一步:初始化项目并实现通过命令运行该项目

  • 使用 yarn init -y 初始化项目
  • 配置 package.json 的 bin 字段
  • 新增 index.js 文件并在顶部写入 #!/usr/bin/env node
  • 通过 npm link 实现软链
  • 命令行中输入 nost 敲回车即可查看相关打印

第二步:添加工具的帮助信息和使用说明

  • 安装 commander 工具库
  • 完善 index.js
index.js 复制代码
#!/usr/bin/env node

const { program } = require('commander')
const { version } = require('./package.json')

program.version(version, '-v, --version', 'Output the current version.')
program.option('-h, --help', 'Output usage information.')

program
  .command('init <project-name>')
  .alias('i')
  .description('Initialization Nost application.')
  .action(async (source, destination) => {})

program
  .command('start')
  .description('Run Nost application.')
  .action(async (source, destination) => {})

program
  .command('build')
  .alias('b')
  .description('Build Nost application.')
  .action(async (source, destination) => {})

program
  .command('info')
  .description('Display Nost project details.')
  .action(async (source, destination) => {})

program
  .command('config <config-filename>')
  .alias('cfg')
  .description('Generate a configuration file.')
  .action(async (source, destination) => {})

program
  .command('controller <controller-filename>')
  .alias('c')
  .description('Generate a controller declaration.')
  .action(async (source, destination) => {})

program
  .command('error <error-types-filename>')
  .alias('e')
  .description('Generate a error declaration.')
  .action(async (source, destination) => {})

program
  .command('middleware <middleware-filename>')
  .alias('m')
  .description('Generate a middleware declaration.')
  .action(async (source, destination) => {})

program
  .command('router <router-filename>')
  .alias('r')
  .description('Generate a router declaration.')
  .action(async (source, destination) => {})

program
  .command('service <service-filename>')
  .alias('s')
  .description('Generate a service declaration.')
  .action(async (source, destination) => {})

program.parseAsync(process.argv)
  • 执行 nost [options] [command] 就可以执行不同的命令

第三步:完善每一个命令对应的操作

1. init | i <project-name>

  • 从 action callback 中的 source 获取输入,通过 fs 模块对进行边界判断
  • 安装 chalk 工具库用来美化命令行的日志打印
  • 安装 ora 工具库用来在命令行与用户进行交互
  • 安装 download-git-repo 工具库用来拉取 Koa 项目模板
  • 将 <project-name> 更新到 package.json 中

2. start

  • 通过 child_process 模块执行项目中的脚本用于在开发环境运行项目

3. build | b

  • 通过 child_process模块执行项目中的脚本通过打包工具生成生产代码

4. info

  • 通过 figlet 在线生成"高大上"的命令行 Banner

5. config | cfg <config-filename>

  • 通过 fs 模块在项目的 config 目录中创建配置文件

6. controller <controller-filename>

  • 通过 fs 模块在项目的 controller 目录中根据控制器模板创建指定的控制器文件
js 复制代码
const controllerName = source[0].toUpperCase()}${source.substring(1)
const controllerTemplate = `
import { Context, Next } from 'koa'
class ${controllerName}Controller {
  async list(ctx: Context, next: Next) {
    ctx.body = 'list'
    await next()
  }
    
  async info(ctx: Context, next: Next) {
    ctx.body = 'info'
    await next()
  }
}

const ${source}Controller = new ${controllerName}Controller()
export default ${source}Controller
`  

7. error | e <error-types-filename>

  • 通过 fs 模块在项目的 error 目录中创建 errorTypes 文件
js 复制代码
const errorTypesTempalte = `
export const ERRORTYPE = 'error message'
`

8. middleware | m <middleware-filename>

  • 通过 fs 模块在项目的 middleware 目录中根据中间件模板创建指定的中间件文件
js 复制代码
const middlewareTemplate = `
import { Context, Next } from 'koa'

export const customMiddleware = async (ctx: Context, next: Next) => {
  // do something...
  console.log(ctx.request.params, ctx.request.body)
  await next()
}
`

9. router | r <router-filename>

  • 通过 fs 模块在项目的 router 目录中根据路由模板创建指定的路由文件
js 复制代码
const routerTemplate = `
import Router from '@koa/router'

const router = new Router({ prefix: '/${source}' })

router.get('/list')
router.post('/list/:id')

export default router
`    

10. service | s <service-filename>

  • 通过 fs 模块在项目的 service 目录中根据模型模板创建指定的路由文件
js 复制代码
const serviceName = source[0].toUpperCase()}${source.substring(1)
const serviceTemplate = `
// import connection from "../mysql"
class ${serviceName}Service {
  // 操作 mysql 获取数据
  // async list() {
  //     const statement = 'SELECT * FROM ${source};'
  //     const [result] = await connection.execute(statement)
  //     return result
  // }
  async list() {
    return []
  }
}
const ${source}Service = new ${serviceName}Service()
export default ${source}Service
`

第四步:编写一个简单的 markdown 并执行 npm publish 进行发布

Koa 项目模板

  • 项目概述
    • 包管理工具使用 yarn
    • 默认使用 ts 进行编写
    • 规范使用 eslint
    • 格式化使用 prettier
    • 打包使用 rollup
  • 源码(src)目录结构
    • main.ts - 入口文件
    • app.ts - 创建 app 并导出
    • router - 路由目录
    • controller - 控制器目录
    • service - sql 目录
    • config - 配置目录
    • middleware - 中间件目录
    • mysql - sql-connection 目录
    • error - 错误处理目录
  • 完整目录结构
md 复制代码
.
├── .eslintignore
├── .eslintrc.json
├── .gitignore
├── .prettierrc
├── LICENSE
├── README.md
├── env.d.ts
├── package-lock.json
├── package.json
├── rollup.config.mjs
├── src
│   ├── app.ts
│   ├── config
│   │   ├── db.config.ts
│   │   └── server.config.ts
│   ├── controller
│   │   └── user.controller.ts
│   ├── error
│   │   ├── index.ts
│   │   └── user.errorTypes.ts
│   ├── main.ts
│   ├── middleware
│   │   ├── user.middleware.ts
│   │   └── wrapper.middle.ts
│   ├── mysql
│   │   └── index.ts
│   ├── router
│   │   ├── index.ts
│   │   └── user.router.ts
│   └── service
│       └── user.service.ts
├── tsconfig.json
└── yarn.lock

总结

有实践! 有思考! 有收获! 有提高!!

相关推荐
子兮曰7 小时前
把 649 种文件格式塞进一个网页里:一个「文件不出浏览器」的预览器
前端·javascript·后端
paopaokaka_luck10 小时前
基于springboot+vue的智慧家政管理系统(AI问答、 WebSocket实时沟通、ECharts运营分析、订单规则与服务追踪)
java·javascript·spring boot·数据分析·echarts·mybatis
sm_9267870510 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
IMPYLH10 小时前
HTML 的 <video> 元素
前端·html
溪语流沙11 小时前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
Interview Aid11211 小时前
SoFi 面试流程全解析:技术面试、OA 与备考指南
面试·职场和发展
逐光者93311 小时前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
To_OC11 小时前
同样是让 AI 写全栈,为什么别人一句话就够了
前端·前端框架·next.js
CDwenhuohuo11 小时前
electron pc项目打包成桌面端
前端·javascript·electron
前端大斗师12 小时前
「大于 1000」把 1000 元那单也算进去了:我在 Vue3 订单页对了 10 句话
前端·人工智能·typescript·大模型·原力计划