用 JS 编写自动化脚本,而不是 bash!

·  阅读 2962

首发于公众号前端从进阶到入院,欢迎关注。

原文:thoughtspile.github.io/2022/02/14/…

导读

Vladimir 发现自己一直讨厌 bash 编写的自动化流程脚本,并且在机缘巧合下发现同事们都有类似的想法,因此他分享了他认为 JavaScript 编写自动化脚本的优势,看看能不能说服大家去共建更好的生态。

与之相关的是,谷歌的 zx 项目正是为此而生,并且在去年的 JavaScript 工具流行趋势调查中获得了第一名。

今年最受欢迎的项目是谷歌的 zx,可在 JavaScript 或 TypeScript 中编写简单的命令行脚本。

zx 支持在代码中嵌入任何 bash 表达式(ls、cat、git 等等),并借助 JavaScript 模板字面量获得结果。

zx 涵盖了多个软件包提供的功能:

node-fetch:使用与浏览器中相同的 API 发出 HTTP 请求

fs-extra:运行文件系统

Globby:匹配给定用户友好模式的文件名

接下来是他所分享的一些看法:

我在日常的工作中也体会到,大家仿佛有共识一般默认写自动化构建脚本时要去用 bash,希望这篇文章可以带给大伙一些不一样的思考,也许 JavaScript 来写会更好?

先看看几个可能的优点:

  • 你的团队可能对 JS 最熟悉

  • dev 和 CI 机器上很可能默认安装了 Node

  • 直接可以访问其他 JS 工具

  • Node 是跨平台的运行时

  • 进程间通信是异步的,而且相当方便

如果你时间不多的话,不妨看看快速比较表格:

这是你团队的主要语言

相比于 bash,大多数前端团队都更熟悉 JS。Node 是具有特殊的 API,但总的来说它有函数一等公民,循环和 promise 等熟悉特性。bash?我搞了几年下来还是不确定它是咋工作的 —— 语法很熟悉,但在意想不到的地方又不一样,大多数变量是字符串,到底存在模块不?如果我错了,也不要纠正我,我不关心了。我一直只是用的时候去谷歌……

每个体面的程序员都需要学习 bash?这是病态的!如果你的后端同事需要在你的项目中做一些紧急改动,那他应该学习一些 JS。C 语言风格的语法让任何人都能大概了解代码的意图。当然从这个角度来看 bash 也差不多,但 JS 在这里起码并不比它差。

在 JS 优先的团队中使用 JS 进行自动化脚本的编写,是最合乎逻辑的选择。

runtime 大概率已经安装了

你的 bash 脚本即使成功运行了,麻烦也没有结束,因为它通常会在另一台机器上失败(说你呢,Alpine Docker 容器……)。各种 shells(SH,ASH,BASH,ZSH)都略有不同,在不同的 Linux 发行版上也不完全通用。你当然可以手动挑选必要的包,或者重新手写逻辑,但是真的很浪费时间。

用 Node 的话,丢失的 runtimes 的问题非常少见 - CI 机器无论如何都可以运行 npm / yarn,这些和 node 绑在一起。此外,一旦 node 程序编写完成,通常每台计算机上都可以运行。

开箱即用的跨平台特性

这就引出了下一点 —— node 是一个跨平台的运行时,在 linux、mac 和 windows 上运行良好。对,MacOS 是兼容 POSIX 的,但是许多命令在选项和输出格式上仍然有细微的差异。现在,你需要 Windows 支持吗?虽然大多数前端开发人员都使用 Mac,而且存在 Win 的 bash 端口。但是,免费支持开箱即用总是很好的:

  • 降低了开源项目的贡献障碍。

  • 一旦我需要匆忙在 Windows 服务器上启动 dev 服务器的时候,一般都很不愉快。

  • 经理想玩玩你的项目,但他用的是 Win 电脑。

Node 团队花了大量时间抽象出操作系统之间的差异。忽视这一点,而去坚持使用 bash,会适得其反。

直接访问其他 JS 工具

前端工作流(webpack/parcel/babel/PostSS)中的大多数工具都开放了 node APIs。甚至像 esbuild 和 swc 这样的非 JS 工具也提供 node bindings。如果你的自动化编排在 node 上运行,那么访问这些 API 就很简单:只需导入包并调用函数。

在 bash 中,有两个麻烦的选项可以与基于 node 的工具集成:

  • 通过奇怪的选项格式调用 CLI。

  • 编写一个最小的 JS 包装器来调用 node API,从 bash 调用它。

另外一个好处是,由于许多工具的 CLI 位于单独的软件包中(如 @babel/CLI),如果直接使用 node API,可以跳过安装,从而节省一点 npm i 时间。

体面的进程间通信

node 作为自动化运行时的一个很棒的方面是它的 IPC 能力。有时候你更喜欢通过 CLI 而不是 node API 使用其他工具。也可以 —— 在 node 中,这可以通过 child_process 异步且跨平台地完成!你甚至可以在不同的进程之间使用管道输出,就像 shell 的管道操作符 |。虽然内置的 Streamchild_process API 可能不太符合人体工程学,但你可以根据自己的口味使用包装器——我比较喜欢execa

bash 也擅长于流程管理,但对我来说,有太多的可能性了——参考这个 stackoverflow 问题:里面提到有五种不同的并行运行命令的方式,如果你不知道自己在做什么,这就很容易让你搬起石头砸自己的脚。

庞大的生态系统

npm 为各种各样的问题提供了很好的解决方案。我最喜欢的是管理子进程的 execa、处理 CLI 选项的yargs和输出样式的chalk

是的,也存在类似的许多命令行工具,但必须使用特定于操作系统的软件包管理器(apt?brew?apk?)安装它们。大伙真的不想处理这种问题。此外,您安装的任何 CLI 软件包也可以通过 spawn/exec 在 node 中使用。


因此,以下是我选择 JS/node 来管理复杂自动化工作流的主要原因:

  • JS 是你们团队的主要语言!

  • 节点运行时通常安装在本地和 CI 中,因为您处理的是 npm/Spread。

  • node 跨平台运行,与 bash 和 make 不同。

  • node 可以直接访问其他 JS 工具。

  • node IPC(用于编排 CLI 工具)非常合适,尤其是使用 execa 时。

  • 在 node 中编写 CLI 工具,有很多好用的软件包。

当然也有理由避免使用 node(比如缺少关于自动化用例的教程,对于不熟悉 node 的人来说,异步的复杂性),但我仍然相信它是 JS 项目中构建自动化流程最可靠的选择。

首发于公众号前端从进阶到入院,更多有趣的前端文章,欢迎关注。

分类:
前端
收藏成功!
已添加到「」, 点击更改