別再用 bash 寫前端自動化腳本了!
導讀
Vladimir[1] 發現自己一直討厭 bash 編寫的自動化流程腳本,並且在機緣巧合下發現同事們都有類似的想法,因此他分享了他認爲 JavaScript 編寫自動化腳本的優勢,看看能不能說服大家去共建更好的生態。
與之相關的是,谷歌的 zx[2] 項目正是爲此而生,並且在去年的 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[3](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[4] 異步且跨平臺地完成!你甚至可以在不同的進程之間使用管道輸出,就像 shell 的管道操作符 |
。雖然內置的 Stream
和child_process
API 可能不太符合人體工程學,但你可以根據自己的口味使用包裝器——我比較喜歡execa
。
bash 也擅長於流程管理,但對我來說,有太多的可能性了——參考這個 stackoverflow 問題:裏面提到有五種不同的並行運行命令的方式 [5],如果你不知道自己在做什麼,這就很容易讓你搬起石頭砸自己的腳。
龐大的生態系統
npm 爲各種各樣的問題提供了很好的解決方案。我最喜歡的是管理子進程的 execa[6]、處理 CLI 選項的 yargs[7] 和輸出樣式的 chalk[8]。
是的,也存在類似的許多命令行工具,但必須使用特定於操作系統的軟件包管理器(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 項目中構建自動化流程最可靠的選擇。
Vladimir
https://thoughtspile.github.io/2022/02/14/js-automation
參考資料
[1]
Vladimir: https://twitter.com/thoughtspile
[2]
zx: https://github.com/google/zx
[3]
各種 shells: https://en.wikipedia.org/wiki/Shell_script
[4]
child_process: https://nodejs.org/api/child_process.html
[5]
裏面提到有五種不同的並行運行命令的方式: https://stackoverflow.com/questions/3004811/how-do-you-run-multiple-programs-in-parallel-from-a-bash-script
[6]
execa: https://github.com/sindresorhus/execa
[7]
yargs: https://github.com/yargs/yargs
[8]
chalk: https://github.com/chalk/chalk
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/4BLXvRaVMS4-kPZ39DhRIg