资讯专栏INFORMATION COLUMN

使用 NodeJS 构建现代化的命令行工具

QLQ / 3606人阅读

摘要:前言这是一篇关于如何使用构建高性能高可读性的现代化命令行工具的博客。对于命令行工具来说,运行时的权限是巨大的,但不要因此弄脏用户的系统。

前言
这是一篇关于如何使用 NodeJS 构建高性能、高可读性的现代化命令行工具的博客。

每当我们想要创建一个基于 NodeJS 的命令行工具时,就会衍生出一堆问题需要解决,比如如何准备开发环境,如何打包转译代码,如何使代码在转译后保持可调用的状态同时尽可能的压缩体积,
以及怎样设计项目分配 CommandOption 等等,这会浪费巨大的时间,而且并非一定有成果。这时你可以注意到社区几乎所有的命令行工具都是自成一派,
并没有严谨的框架或约定约束,也无所谓的最佳实践,这使想要特别是第一次想要开发命令行工具的开发者望而却步,或是几番努力最后却不尽如人意。

举个例子来说,腾讯的 omi 是一个有众多使用者的框架,但其命令行工具 omi / omi-cli 却让人贻笑大方。仅一些简单的下载和创建模板的任务,造出长篇大论的文件不说,下载
时依赖数千,包的体积巨大,整体项目毫无设计几乎是随心所欲、天马行空,这就是开发者本身并不擅长此道,只学会了 糊屎。(何谓 糊屎,参阅 JS 优雅指南 2)

FUNC 的出现就是为了解决这些问题。func 本身的实现参阅了社区内诸多基于 NodeJS 的命令行工具的优秀实现,与流行的框架设计思路相结合,以优雅的设计、小体积、高性能 等为目标,
同时关注开发者体验,大幅度的提升了命令行工具项目的可扩展性与可读性,几乎是如今 NodeJS 社区中开发命令行工具的最优解。我们可以尝试使用 func 构建一个命令行工具。

构建项目

在以前流行的一些命令行参数解析的库中,我们在构建项目前需要准备大量的脚本与配置,甚至还要解决文件权限、bin、代码转译等等问题,但使用 func,我们可以仅通过一行命令
初始化项目:

npm init func

项目初始化后进入文件夹,随机使用 npm installyarn 安装依赖,现在就可以正式开发了。
可以注意到,func 的项目模板中为我们准备了 startbuild 2 个脚本,它们都是由 func-service 驱动的,帮助你一键切换开发与生产模式,我们所要做的就是专注于
命令行逻辑本身,实现逻辑就够了。

实现逻辑

我们可以随意的创建一个类,当它被加上 Command 注解时这就是一个命令,而被加上 Option 注解时就会转变为一个选项:

import { Command } from "func"

@Command({ name: "test" })
export class Test {
}

在命令行中运行 test 时,Test 类将会被调用。选项也是同理。你可以在 constructor 中开始自己的代码,这和你在任何地方写 NodeJS 没有什么
不同,当你觉得差不多的时候,运行 npm build 就可以将它打包,一切就是这么简单。

有时候,当我们需要使用到命令行携带的参数时,比如处理 something params -option 这样复杂的输入,你可以直接在类中注入命令行参数,对,就是像 IoC 那样:

@Command({ name: "test" })
export class Test {
  constructor(
    private args: CommandArgsProvider,
  ) {
  }
}

CommandArgsProvider 实际上是一个 class 类型,当你标记一个参数为此类型时,func 会在运行时为你注入所有的命令参数,
同样的也支持 OptionArgsProviderRegisterProvider 等等,你可以在 官方的文档 阅读它们的具体类型。

打包与发布

运行 npm build 可以得到一个打包后的文件,这是由 ncc 编译后的文件,通常它只有一个 (如果携带 extra 可能会有多个,但它们会自动链接),
同时为你链接好了 bin,你要做的唯一一件事就是将包发布出去。为什么 func 使用这种方式发布呢?

我们知道当你在安装一个包或是使用 npx 执行包时 (这在使用命令行工具的人群中很常见),NPM 所花费的时间大约在 3 个部分,即对比包的依赖,下载包,执行。
首先我们知道 func 的项目足够的小,能够大量介绍下载时间,同时也有足够好的性能,现在要解决的就是在大量依赖时的对比分析问题,将文件打包成单文件不依赖
外部环境时会极大的减少所需时间,如果你再将所有的依赖移入 devDependencies 中,几乎能够在一瞬间完成 分析 - 下载 - 运行 这三个步骤。这样的体验是难以想象的。
是的,这里推荐你把所有的依赖当做开发依赖处理,这似乎违背了 NPM Package 的开发哲学,但在使用 func 构建命令行应用时这样做却大有裨益。

在运行 func build 完成的包时,我们注意到几乎无需任何依赖,这是因为在单个文件中已经 bundle 了所有的所需资源,也就意味着用户在运行 .js 文件时,
堆栈中真的就只有 .js 文件内的内容,不会引用其他,不会加载任何无关紧要的东西。此时我们也就无需用户关心 dependencies,甚至可以移除它们,这样一来,
下载或即时运行时就直接跳过了 对比依赖版本 这一步,这其中省略了无数的请求也就会会极大的增加速度,npm init func 能够在 1 秒左右立刻开始安装也是这样的道理。

优化与经验

现在你已经知道了怎样快速的构建一个合格且优雅的命令行工具,那怎样做的更好呢?通常来说你需要遵循这几点:

不因为小功能引入巨大的包,不引入依赖爆炸的包。

举例来说,download-git-repo 是一个很不错的包,它能够为你节约很多时间,但请注意它依赖了 download,如果你仅为了下载单个文件或只有很少的下载需求时,
这就显得有些大材小用,download 会为你增加约 450 kb 的重量,却只做了一件你 5 分钟可以搞定的事情。同样你的用户也会为此付出巨大的时间代价。

不要显示错误堆栈信息。

在多数情况下我们都需要尽可能的显示堆栈或是引用的错误信息便于 debug,但是在命令行工具中这样做只会使你的用户非常困惑。这主要归结于命令行中不能很好高亮
的显示代码块,大量的代码信息会使用户不知所措。建议你始终构建一个错误处理模块来解决问题,同时为用户提供良好的反馈,最后可以提供类似于 --debug
选项让开发者调试。

不要太依赖同步操作。

在 NodeJS 与其社区流行的 I/O 库中,我们通常会有异步和同步函数两种选择,如 readFilereadFileSync,虽然同步函数可以为你节约一些开发时间,
但也会阻塞你的代码,很多情况下会有难以理解的问题。比如当你设置定时器显示一个 Loading 图标的同时操作了同步 API,那么你的 Loading 图标就会因为阻塞
而无法运动 (因为无法 render 到终端),或是你同时操作多个文件,同步的 API 会使你花费巨大的时间。

不要发布无用信息。

命令行工具很多时候的角色是充当复杂的脚本,性能和体验是至关重要的,发布无用的信息在你的 package 中会使下载时间更长。(使用 files 来约束发布的文件)

不要修改临时文件夹与配置区以外的信息。

对于命令行工具来说,运行时的权限是巨大的,但不要因此弄脏用户的系统。你可以使用 require("os").tmpdir() 获取用户操作系统的临时文件夹目录,无论何时,
你都拥有这里的写权限。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/104921.html

相关文章

  • GitHub 值得收藏前端项目[每月更新...]

    摘要:也是一款优秀的响应式框架站点所使用的一套框架为微信服务量身设计的一套框架一组很小的,响应式的组件,你可以在网页的项目上到处使用一个可定制的文件,使浏览器呈现的所有元素,更一致和符合现代标准。 GitHub 值得收藏的前端项目 整理与收集的一些比较优秀github项目,方便自己阅读,顺便分享出来,大家一起学习,本篇文章会持续更新,版权归原作者所有。欢迎github star与fork 预...

    maxmin 评论0 收藏0
  • 45个必备JavaScript Web开发工具

    摘要:幸运的是,为了完成独特的任务,无以计数的工具已经被开发者发布。图像显示的是一个针对该框架的在线开发工具。是用创建的命令行工具,用于压缩文件。是一组处理所有跟文件相关的工作的组件库。是一个基于任务的命令行项目构建工具。 JavaScript是一种灵活多变的脚本语言,它在全世界被广泛的应用在Web页面和服务器应用中。你可以因为任何目的去使用它,但是你需要一些工具。幸运的是,为了完成独特的任...

    不知名网友 评论0 收藏0
  • 前端构建_webpack

    摘要:一个文件,一张图片一个文件都是一个模块,都能用导入模块的语法的,的导入进来。自身只能读懂类型的文件,其它的都不认识。 webpack 是什么? webpack是一个前端模块化打包工具指(由于模块化开发,所以需要打包,这里所说的模块化开发主要指JS) 由于现代前端应用程序越来越复杂,需要采用模块化进行开发,但浏览器还未支持模块化开发,所以webpack才诞生 webpack默认只支持js...

    ethernet 评论0 收藏0
  • 用100代码,完成自己前端构建工具

    摘要:行代码,你将拥有一个现代化规范测试驱动高延展性的前端构建工具。在阅读前,给大家一个小悬念什么是链式操作中间件机制如何读取构建文件树如何实现批量模板渲染代码转译如何实现中间件间数据共享。函数将参数中的挂载到上,并返回以便于链式操作即可。 ES2017+,你不再需要纠结于复杂的构建工具技术选型。 也不再需要gulp,grunt,yeoman,metalsmith,fis3。 以上的这些构建...

    haitiancoder 评论0 收藏0

发表评论

0条评论

QLQ

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<