9、架构:CLI 设计

通常大部分的程序员会更加习惯使用 CLICommand-Line Interface 命令行界面)来辅助开发业务,包括初始化、更新、构建、发布等功能,可以获得沉浸式一站的开发体验。

在之前有一篇企业级 CLI 开发实战介绍过如何开发一款适用团队的 CLI 工具,基于团队规范可以将项目脚手架与 CLI 强制绑定在一起,约束开发者使用的开发语言以及开发规范,但是对于一款通用性的低代码产品,基于业务类型的物料开发经常会存在个性化的需求,强行将构建与 CLI 绑定则会使得 CLI 本身的逻辑变得更加复杂。

所以本次 CLI 的设计会更加较为通用,不再与单纯的业务开发耦合过多。

初始化工程/管理


由于物料会根据业务的不同存在不同的配置属性,每一次开发物料都需要拉取对应的业务模板,所以我们会面对种类非常以及多个版本的情况,以下是拉取模板的流程图:

nodegitdownload-git-repo 和 git-clone 都是用于在 Node.js 环境中从远程 Git 仓库中下载代码的库,它们之间的主要区别如下:

  • 功能:nodegit 是一个完整的 Git 库,提供了一套完整的 Git API,可以用于管理 Git 仓库、提交代码等操作。download-git-repo 和 git-clone 则是专门用于下载 Git 仓库中的代码的库。
  • 依赖:nodegit 和 git-clone 都依赖于 libgit2 库,而 download-git-repo 则不依赖于任何第三方库。
  • 使用方式:nodegit 和 git-clone 都是使用 Git 命令行工具来下载代码,而 download-git-repo 则是直接调用 Git 仓库的 API 来下载代码。

除了拉取模板之外,我们还会借助封装的 CLI 来管理工程,所以最终会选择 nodegit 进行二次封装,简化使用过程中 Git 操作的命令。

权限


使用 Open Api 与用户系统进行交互,通常情况下只有登录与鉴权两个模块。

登录

  • 一般都是登录之后将 token 缓存在本地,过期之后再重新授权。
  • 如果嫌麻烦,也可以直接加密缓存用户名与密码,再过期之后自动调用登录接口维持登录态,这样可以让用户后期无感知使用。

权限

为了保证项目使用的安全性,一般在每一次执行部署操作之前都需要进行权限判断,权限判断的方式也有如下两种:

  • 每一次都直接调用接用户中心的权限接口判断,当然如果碰到网络延时的话,每一步的操作都很艰难。
  • 为了减少网络延时可以在每个工程创建之后就预先缓存对应过程的权限信息,当权限不足进行权限申请,当审批通过后可以手动刷新权限数据或者设定缓存过期时间来定时拉取权限数据。

构建


由于新的 CLI 设计将不再与脚手架耦合,所以构建的具体配置将内置在脚手架中,例如:RollupWebpackVite 等。

CLI 将只接受构建前、构建、构建后三种构建命令并执行,通常情况下可以与脚手架约定俗成比如:

  • npm run pre 构建前执行脚本
  • npm run build 构建脚本
  • npm run did 构建完成之后执行脚本

或者使用配置文件自定义其他的运行命令:

{"pre-build":"npm run pre","build":"npm run build","build-did":"npm run did"
}

除此之外,构建过程还需要区分各个环境并注入对应的环境变量,让实际工程构建的过程中根据环境变量选择不同的配置。

部署


一般前端服务的部署有如下几种:

  1. 静态文件部署:将前端应用程序打包成静态文件,并将这些文件上传到 Web 服务器或 CDN 上。用户在访问网站时,直接从 Web 服务器或 CDN 上获取静态文件,然后在浏览器中渲染。
  2. 容器化部署:使用容器技术,如 Docker,将前端应用程序打包成容器镜像,并在生产环境中部署这些镜像。这种方式可以提高部署的可重复性和可移植性,并且可以更方便地进行版本管理。
  3. 云平台部署:将前端应用程序部署到云平台上,如阿里云、AWS等。这种方式可以提供更好的可扩展性和可靠性,并且可以根据需要自动扩展服务器资源。
  4. 私有部署:将前端应用程序的代码发布到生产环境[私有服务器]中,然后在生产环境中使用类似 Nginx 或 Apache 的 Web 服务器来运行和管理应用程序。

一般来说,纯前端的项目直接使用静态文件部署即可,所以我们的 CLI 需要内置一些 OSS 的工具函数,方便将资源上传到对应的 OSS 服务。

非纯前端的项目建议走 Docker 发布,配合 k8s 的可以更方便的伸缩扩容,同时配合启动环境变量注入,使得多环境中代码可以保持一致,减少错误。

无论是哪种模式都需要针对不同的平台进行适配,比如不同服务商的 OSS 工具以及不同 k8s 平台等,虽然一般的小团队不会有很多的选择性,直接内置在 CLI 中也问题不大,但作为通用性的工具,我们在开发过程这一会设计成拓展插件,减少用户的接入成本。

自定义插件


除了上述一些基础服务之外,CLI 还应该具备拓展插件的能力,使之功能更加完善,例如上一步骤中部署到各个环境的工具类就可以以对应的拓展插件提供。

CLI 需要先对命令进行分析判断是基础命令还是拓展服务,所以需要一个类似 Router 的主入口,包含内置与第三方插件的命令,在用户输入命令之后,调用不同的插件,流程图如下所示:

对于主 CLI 来说,很难接受规范不一致的三方插件注册,这样会影响 CLI 的结构,所以我们需要对 CLI 插件的模板做一个约束,除了输出的格式与上述内置插件格式保持一致之外,我们还需要对插件名称、依赖等等做一个约束,并且提供各种 Hook 方便插件开发,可以参考 Webpack 的 tapable 实现。

对于 @Ignition/cli 来说,将只接受 @Ignition/cli-plugin-*** 命名格式的插件进来。这种规则可以根据团队的命名规范来约定,并不是唯一规范。

所以在添加插件的时候需要做两次校验,第一层校验是通过校验名字,第二层是安装依赖,如果依赖安装失败也不会添加成功。

在之前工程化里面有对自定义插件有一些实战的介绍,有想先试试的同学可以先参考前端工程化实战 - 自定义 CLI 插件开发玩起来,后期出实战篇的时候,会比之前的更加详细。

注意


以上 CLI 所有的操作都是基于开发者的本地环境进行操作,与云上 CI/CD 不同,在开发者本地进行构建部署是依赖本地的环境,大部分的时候都存在分支管理、依赖不同步的问题。

为了避免构建代码遗失以及环境不一致的问题,我们需要根据下述流程来约束:

当然 CLI 可以不做本地构建,而是触发远程构建命令直接走云上构建,将结果实时反馈到本地,虽然会更加可靠,但是开发工作量也就相对增加了,如果有能力我建议选择云上构建。

额外拓展


避免有些同学对文章开头所说的 CLI 与脚手架剥离有误会,这里对这两者进行一些简单的介绍。

首先 CLI 和脚手架都是可以用于快速生成项目代码的工具,但它们的作用和功能略有不同:

  • CLI 是一个命令行界面工具,可以用来执行一系列命令,完成各种操作,如代码构建、打包、测试等,也可以用来管理项目依赖、配置文件等。同时 CLI 可以非常灵活地适应不同的项目需求,可以通过编写插件和扩展来实现更多的功能。
  • 脚手架(Scaffolding)是一个用于生成项目代码的工具,通常包含了项目的基本结构、依赖、配置等信息,可以帮助开发者快速创建一个新项目,并提供一些基础设施和工具,如构建工具、测试框架、代码风格检查等。减少开发者的重复工作,提高开发效率,同时也可以保证项目的一致性和可维护性。

综上所述,虽然 CLI 和脚手架都具备快速初始化项目的能力,但 CLI 更加灵活,可以根据具体需求来执行各种任务,而脚手架则更加专注于项目结构和基础设施的搭建。

将脚手架的能力从 CLI 分离之后,为了拓展性更好、更规范的话,通常会创建一个基础的脚手架,以此脚手架再拓展各个业务模板,但想节约工作量或者各个业务需求的差异化更大的话,可以直接根据不同的模板定制脚手架就好。

写在最后

如果你有什么疑问或者更好的建议,欢迎在评论区提出。 👏

9 架构:CLI 设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/9863.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java中如何将一个集合list转成以逗号隔开的字符串

事例代码 代码&#xff1a; package com.air.app;import java.util.ArrayList; import java.util.List;public class ListToStringTest {public static void main(String[] args) {//定义list集合List<String> list new ArrayList<>();list.add("1");…

基于eBPF技术的云原生可观测实践

** 基于eBPF技术的云原生可观测实践 ** eBPF技术是Linux内核3.15版本中引入的全新设计&#xff0c;自从2014年发布以来&#xff0c;一直都备受瞩目。在过去几年中&#xff0c;基于eBPF技术的实践和工程落地层出不穷&#xff0c;出现了爆发式的增长。2015年微软、Google、Face…

C++案例

目录 一、while循环猜数组 二、 水仙花数 三、for循环敲桌子游戏 四、99乘法表 五、一维数组--元素逆置 六、冒泡排序 七、封装一个函数--利用冒泡排序&#xff0c;实现对整型数组的升序排序 八、结构体嵌套结构体 九、结构体排序 一、while循环猜数组 说明&#x…

【vue3中使用swiper组件】

【vue3中使用swiper组件】超详细保姆级教程 效果展示简介版本安装Swiper用法完整代码展示html静态展示js逻辑展示&#xff08;vue3 --- ts&#xff09;官方文档导入模块 css样式展示 &#xff08;自行更改所需&#xff09;官方文档样式 效果展示 简介版本 安装Swiper 项目终端中…

国产自研开源大数据管理平台DataSophon

【背景】 几天在朋友圈看到开源社区Datavane发布了一个新开源项目DataSophon&#xff1b;一个致力于快速实现部署、管理、监控以及自动化运维大数据云原生平台&#xff0c;帮助快速构建起稳定、高效、可弹性伸缩的大数据云原生平台&#xff1b;从介绍内容来看非常优秀&#xff…

golang Redis的新数据类型github.com/go-redis/redis/v8实践

Redis的新数据类型# 在redis中&#xff0c;后面添加了几个比较高级的数据类型 hyperloglog基数统计、GEO存储地理位置、bitmap位图、stream为消息队列设计的数据类型 这 4 种数据类型。 HyperLogLog类型# HyperLogLog简介# HyperLogLog 是一种用于数据统计的集合类型&#x…

计算机网络_ 1.3 网络核心 (数据交换_电路交换)

计算机网络_数据交换_电路交换 计算机网络_数据交换_电路交换 计算机网络_数据交换_电路交换 最典型电路交换网络&#xff1a;电话网络电路交换的三个阶段 建立连接&#xff08;呼叫/电路建立&#xff09;通信释放连接&#xff08;拆除电路&#xff09; 独占资源 电路交换网络…

RNN LSTM

参考资料&#xff1a; 《机器学习2022》李宏毅史上最详细循环神经网络讲解&#xff08;RNN/LSTM/GRU&#xff09; - 知乎 (zhihu.com) LSTM如何来避免梯度弥散和梯度爆炸&#xff1f; - 知乎 (zhihu.com) 1 RNN 的结构 首先考虑这样一个 slot filling 问题&#xff1a; 注意…

postgresql内核分析 spinlock与lwlock原理与实现机制

​专栏内容&#xff1a; postgresql内核源码分析 手写数据库toadb 并发编程 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 概述 在postgresql 中&#xff0c;有大量的并发同步&#xff0…

硬件速攻-激光测距传感器VL530L0X

介绍 VL53L0X是一种时间飞行&#xff08;Time-of-Flight&#xff0c;TOF&#xff09;技术的激光测距传感器芯片。TOF技术利用红外激光发射器发送短脉冲光束&#xff0c;并通过测量光束从传感器到目标物体返回的时间来计算距离。 外观 现象 串口打印数据 接线 VCC 3.3V G…

MFC 单文档模式

Doc类利用自带框架存数据 void CCADDoc::Serialize(CArchive& ar) {if (ar.IsStoring()){// TODO: 在此添加存储代码//保存数据到文件ar << m_nShapeCount;for (int i 0; i < m_arrShapes.GetSize(); i){CShape* pShape NULL;pShape (CShape*)m_arrShapes[i];…

Prometheus 时序数据

一 时序索引 Prometheus 存储的是时序数据&#xff0c;时间戳&#xff08;timestamp&#xff09;来源于服务端本地的系 统时间。Prometheus 使用 Unix 时间戳&#xff08;即自 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数&#xff09;表示时间。 数 据 格 式 &#xff1a; …