社區精選|如何使用 zx 編寫 shell 腳本

計算科學與信息化 發佈 2024-04-05T13:53:00.948629+00:00

前言在這篇文章中,我們將學習谷歌的 zx 庫提供了什麼,以及我們如何使用它來用 Node.js 編寫 shell 腳本。然後,我們將學習如何通過構建一個命令行工具來使用 zx 的功能,幫助我們為新的 Node.js 項目引導配置。


前言


在這篇文章中,我們將學習谷歌的 zx 庫提供了什麼,以及我們如何使用它來用 Node.js 編寫 shell 腳本。然後,我們將學習如何通過構建一個命令行工具來使用 zx 的功能,幫助我們為新的 Node.js 項目引導配置。


編寫 Shell 腳本的問題


創建一個由 Bash 或者 zsh 執行的 shell 腳本,是自動化重複任務的好方法。Node.js 似乎是編寫 shell 腳本的理想選擇,因為它為我們提供了許多核心模塊,並允許我們導入任何我們選擇的庫。它還允許我們訪問 JavaScript 提供的語言特性和內置函數。


如果你嘗試編寫運行在 Node.js 中的 shell 腳本,你會發現這沒有你想像中的那麼順利。你需要為子進程編寫特殊的處理程序,注意轉義命令行參數,然後最終與 stdout(標準輸出)和 stderr(標準錯誤)打交道。這不是特別直觀,而且會使 shell 腳本變得相當笨拙。


Bash shell 腳本語言是編寫 shell 腳本的普遍選擇。不需要編寫代碼來處理子進程,而且它有內置的語言特性來處理 stdout 和 stderr。但是用 Bash 編寫 shell 腳本也不是那麼容易。語法可能相當混亂,使得它實現邏輯,或者處理諸如提示用戶輸入的事情非常困難。


谷歌的 zx 庫有助於讓使用 Node.js 編寫的 shell 腳本變得高效和舒適。


前置條件


往下閱讀之前,有幾個前置條件需要遵循:


  • 理想情況下,你應該熟悉 JavaScript 和 Node.js 的基礎知識。
  • 你需要適應在終端中運行命令。
  • 你需要安裝 Node.js >= v14.13.1。

本文中的所有代碼都可以從 gitHub https://link.segmentfault.com/?enc=ysCUhsc%2BhqUmtqCo55t8jw%3D%3D.aWhjUaPje6eTlkcFFdhW%2FeIVYyAz5G%2FoPbGuXjsxlpcJphMKguwz3NoHWQ9o2vDb47Nfnm9kpIP6Ol5r6Euc8A%3D%3D 上獲得。


zx 如何運作


Google 的 zx 提供了創建子進程的函數,以及處理這些進程的 stdout 和 stderr 的函數。我們將使用的主要函數是$函數。下面是它的一個實際例子:


import { $ } from "zx";
await $`ls`;


下面是執行上述代碼的輸出:


$ ls
bootstrap-tool
hello-world
node_modules
package.json
README.md
TypeScript


上面的例子中的 JavaScript 語法可能看起來有點古怪。它使用了一種叫做帶標籤的模板字符串 https://link.segmentfault.com/?enc=VUkodq5er%2Fynbhfl3MUQZA%3D%3D.%2Flx6oaDCVK4XuYyYLqvDi2QMWjCwW1jKBvNQgfaGG0AVwpl7I2CYD4sJYHuonDSA6jj1qSSypc0aGVO%2BYuBMUiibG6pBkVwusg%2Bai1hbMXetqlwMTWVUEAbtabMCbXIs 的語言特性。它在功能上與編寫 await $("ls")相同。


谷歌的 zx 提供了其他幾個實用功能,使編寫 shell 腳本更容易。比如:


  • cd()。允許我們更改當前工作目錄。
  • question()。這是 Node.js readline 模塊的包裝器。它使提示用戶輸入變得簡單明了。


除了 zx 提供的實用功能外,它還為我們提供了幾個流行的庫,比如:


chalk。https://link.segmentfault.com/?enc=%2FL15Y8OQNrp05Scx6N4iaQ%3D%3D.r8AZkfcE1Ye%2BlNUznFA9RNJMhfyM0lttTiD0TmqjJQwoi7zjQjs5YiLjI%2FWDEooY 這個庫允許我們為腳本的輸出添加顏色。


minimist。https://link.segmentfault.com/?enc=5tMQ5d6qJ4STEHZeuiN0MA%3D%3D.x9GPOpXVZp5TGKknZCkwA10QP%2Ftw%2BW7fwnpYGg%2BnlJPJLK3RboT3jqy5WuPLFwPZ 一個解析命令行參數的庫。然後它們在 argv 對象下被暴露出來。


fetch。https://link.segmentfault.com/?enc=71LC44tCu%2FZoLOY2B7MfuA%3D%3D.GO%2FMi37T0KTmj8UXau9xdFUBiIk1I%2F8M%2FHk2hZYrhRb%2Fd3Vl0bzlr05hanNxzuVb Fetch API 的 Node.js 實現。我們可以用它來進行 HTTP 請求。


fs-extra。https://link.segmentfault.com/?enc=cPZzXniTRFJdbq87FdwLWw%3D%3D.IsmhSUEjIcZAqw8FDidbUnNhhIVPT1gsFSo%2BchiXCAs9AaxUVT%2FEgbIvswUDVmK2 一個暴露 Node.js 核心 fs 模塊的庫,以及一些額外的方法,使其更容易與文件系統一起工作。


現在我們知道了 zx 給了我們什麼,讓我們用它創建第一個 shell 腳本。


zx 如何使用


首先,我們先創建一個新項目:


mkdir zx-shell-scripts
cd zx-shell-scripts
npm init --yes


然後安裝 zx 庫:


npm install --save-dev zx


注意:zx 的文檔建議用 npm 全局安裝該庫。通過將其安裝為我們項目的本地依賴,我們可以確保 zx 總是被安裝,並控制 shell 腳本使用的版本。


頂級 await


為了在 Node.js 中使用頂級 await,也就是 await 位於 async 函數的外部,我們需要在 ES 模塊的模式下編寫代碼,該模式支持頂級 await。

我們可以通過在 package.json 中添加 "type": "module" 怎麼怎麼來表明項目中的所有模塊都是 ES 模塊。或者我們可以將單個腳本的文件擴展名設置為 .mjs 。在本文的例子中,我們將使用 .mjs 文件擴展名。


運行命令並捕獲輸出


創建一個新腳本,將其命名為 hello-world.mjs 。我們將添加一個 Shebang 行,它告訴作業系統(OS)的內核要用 node 程序運行該腳本:


#! /usr/bin/env node


然後,我們添加一些代碼,使用 zx 來運行命令。


在下面的代碼中,我們運行命令執行 ls 程序。ls 程序將列出當前工作目錄(腳本所在的目錄)中的文件。我們將從命令的進程中捕獲標準輸出,將其存儲在一個變量中,然後列印到終端:


// hello-world.mjs
import { $ } from "zx";
const output = (await $`ls`).stdout;
console.log(output);


注意:zx 文檔建議把/usr/bin/env zx 放在我們腳本的 shebang 行中,但我們用/usr/bin/env node 代替。這是因為我們已經安裝 zx,並作為項目的本地依賴。然後我們明確地從 zx 包中導入我們想要使用的函數和對象。這有助於明確我們腳本中使用的依賴來自哪裡。


我們使用 chmod 來讓腳本可執行:


chmod u+x hello-world.mjs


運行項目:


./hello-world.mjs


可以看到如下輸出:


$ ls
hello-world.mjs
node_modules
package.json
package-lock.json
README.md
hello-world.mjs
node_modules
package.json
package-lock.json
README.md


你會注意到:


  • 我們運行的命令(ls)被包含在輸出中。
  • 命令的輸出顯示兩次。
  • 在輸出的末尾多了一個新行。


zx 默認以 verbOSe 模式運行。它將輸出你傳遞給$函數的命令,同時也輸出該命令的標準輸出。我們可以通過在運行 ls 命令前加入以下一行代碼來改變這種行為:


$.verbose = false;


大多數命令行程序,如 ls,會在其輸出的結尾處輸出一個新行字符,以使輸出在終端中更易讀。這對可讀性有好處,但由於我們要將輸出存儲在一個變量中,我們不希望有這個額外的新行。我們可以用 JavaScript String#trim()函數把它去掉:


- const output = (await $`ls`).stdout;
+ const output = (await $`ls`).stdout.trim();


再次運行腳本,結果看起來好很多:


hello-world.mjs
node_modules
package.json
package-lock.json


引入 TypeScript


如果我們想在 TypeScript 中編寫使用 zx 的 shell 腳本,有幾個微小的區別我們需要加以說明。


注意:TypeScript 編譯器提供了大量的配置選項,允許我們調整它如何編譯我們的 TypeScript 代碼。考慮到這一點,下面的 TypeScript 配置和代碼是為了在大多數 TypeScript 版本下工作。


首先,安裝需要運行 TypeScript 代碼的依賴:


npm install --save-dev typescript ts-node


ts-node 包提供了一個 TypeScript 執行引擎,讓我們能夠轉譯和運行 TypeScript 代碼。


需要創建 tsconfig.json 文件包含下面的配置:


{
"compilerOptions": {
  "target": "es2017",
  "module": "commonjs"
}
}


創建新的腳本,並命名為 hello-world-typescript.ts。首先,添加 Shebang 行,告訴 OS 內核使用 ts-node 程序來運行我們的腳本:


#! ./node_modules/.bin/ts-node


為了在我們的 TypeScript 代碼中使用 await 關鍵字,我們需要把它包裝在一個立即調用函數表達式(IifE)中,正如 zx 文檔所建議的那樣:


// hello-world-typescript.ts
import { $ } from "zx";
void (async function () {
  await $`ls`;
})();


然後需要讓腳本可執行:


chmod u+x hello-world-typescript.ts


運行腳本:


./hello-world-typescript.ts


可以看到下面的輸出:


$ ls
hello-world-typescript.ts
node_modules
package.json
package-lock.json
README.md
tsconfig.json


在 TypeScript 中用 zx 編寫腳本與使用 JavaScript 相似,但需要對我們的代碼進行一些額外的配置和包裝。


構建項目啟動工具


現在我們已經學會了用谷歌的 zx 編寫 shell 腳本的基本知識,我們要用它來構建一個工具。這個工具將自動創建一個通常很耗時的過程:為一個新的 Node.js 項目的配置提供引導。


我們將創建一個交互式 shell 腳本,提示用戶輸入。它還將使用 zx 內置的 chalk 庫,以不同的顏色高亮輸出,並提供一個友好的用戶體驗。我們的 shell 腳本還將安裝新項目所需的 npm 包,所以它已經準備好讓我們立即開始開發。


準備開始


首先創建一個名為 bootstrap-tool.mjs 的新文件,並添加 shebang 行。我們還將從 zx 包中導入我們要使用的函數和模塊,以及 Node.js 核心 path 模塊:


#! /usr/bin/env node
// bootstrap-tool.mjs
import { $, argv, cd, chalk, fs, question } from "zx";
import path from "path";


與我們之前創建的腳本一樣,我們要使我們的新腳本可執行:


chmod u+x bootstrap-tool.mjs


我們還將定義一個輔助函數,用紅色文本輸出一個錯誤信息,並以錯誤退出代碼 1 退出 Node.js 進程:


function exitWithError(errorMessage) {
  console.error(chalk.red(errorMessage));
  process.exit(1);
}


當我們需要處理一個錯誤時,我們將通過我們的 shell 腳本在各個地方使用這個輔助函數。


檢查依賴


我們要創建的工具需要使用三個不同程序來運行命令:Git、node 和 npx。我們可以使用 which 庫來幫助我們檢查這些程序是否已經安裝並可以使用。


首先,我們需要安裝 which:


npm install --save-dev which


然後引入它:


import which from "which";


然後創建一個使用它的 checkRequiredProgramsExist 函數:


async function checkRequiredProgramsExist(programs) {
  try {
    for (let program of programs) {
      await which(program);
    }
  } catch (error) {
    exitWithError(`Error: Required command ${error.message}`);
  }
}


上面的函數接受一個程序名稱的數組。它循環遍歷數組,對每個程序調用 which 函數。如果 which 找到了程序的路徑,它將返回該程序。否則,如果該程序找不到,它將拋出一個錯誤。如果有任何程序找不到,我們就調用 exitWithError 輔助函數來顯示一個錯誤信息並停止運行腳本。


我們現在可以添加一個對 checkRequiredProgramsExist 的調用,以檢查我們的工具所依賴的程序是否可用:


await checkRequiredProgramsExist(["git", "node", "npx"]);


添加目標目錄選項


由於我們正在構建的工具將幫助我們啟動新的 Node.js 項目,因此我們希望在項目的目錄中運行我們添加的任何命令。我們現在要給腳本添加一個 --directory 命令行參數。


zx 內置了 minimist 包,它能夠解析傳遞給腳本的任何命令行參數。這些被解析的命令行參數被 zx 包作為 argv 提供:


讓我們為名為 directory 的命令行參數添加一個檢查:


let targetDirectory = argv.directory;
if (!targetDirectory) {
  exitWithError("Error: You must specify the --directory argument");
}


如果 directory 參數被傳遞給了我們的腳本,我們要檢查它是否是已經存在的目錄的路徑。我們將使用 fs-extra 提供的 fs.pathExists 方法:


targetDirectory = path.resolve(targetDirectory);
if (!(await fs.pathExists(targetDirectory))) {
  exitWithError(`Error: Target directory '${targetDirectory}' does not exist`);
}


如果目標路徑存在,我們將使用 zx 提供的 cd 函數來切換當前的工作目錄:‍


cd(targetDirectory);


如果我們現在在沒有--directory 參數的情況下運行腳本,我們應該會收到一個錯誤:


$ ./bootstrap-tool.mjs
Error: You must specify the --directory argument


檢查全局 Git 設置


稍後,我們將在項目目錄下初始化一個新的 Git 倉庫,但首先我們要檢查 Git 是否有它需要的配置。我們要確保提交會被 GitHub 等代碼託管服務正確歸類。


為了做到這一點,這裡創建一個 getGlobalGitSettingValue 函數。它將運行 git config 命令來檢索 Git 配置設置的值:


async function getGlobalGitSettingValue(settingName) {
  $.verbose = false;
  let settingValue = "";
  try {
    settingValue = (
      await $`git config --global --get ${settingName}`
    ).stdout.trim();
  } catch (error) {
    // Ignore process output
  }
  $.verbose = true;
  return settingValue;
}


你會注意到,我們正在關閉 zx 默認設置的 verbose 模式。這意味著,當我們運行 git config 命令時,該命令和它發送到標準輸出的任何內容都不會被顯示。我們在函數的結尾處將 verbose 模式重新打開,這樣我們就不會影響到我們稍後在腳本中添加的任何其他命令。


現在我們添加 checkGlobalGitSettings 函數,該函數接收 Git 設置名稱組成的數組。它將循環遍歷每個設置名稱,並將其傳遞給 getGlobalGitSettingValue 函數以檢索其值。如果設置沒有值,將顯示警告信息:


async function checkGlobalGitSettings(settingsToCheck) {
  for (let settingName of settingsToCheck) {
    const settingValue = await getGlobalGitSettingValue(settingName);
    if (!settingValue) {
      console.warn(
        chalk.yellow(`Warning: Global git setting '${settingName}' is not set.`)
      );
    }
  }
}


讓我們給 checkGlobalGitSettings 添加一個調用,檢查 user.name 和 user.email 的 Git 設置是否已經被設置:


await checkGlobalGitSettings(["user.name", "user.email"]);


初始化 Git 倉庫


我們可以通過添加以下命令在項目目錄下初始化一個新的 Git 倉庫:


await $`git init`;


生成 package.json


每個 Node.js 項目都需要 package.json 文件。這是我們為項目定義元數據的地方,指定項目所依賴的包,以及添加實用的腳本。


在我們為項目生成 package.json 文件之前,我們要創建幾個輔助函數。第一個是 readPackageJson 函數,它將從項目目錄中讀取 package.json 文件:


async function readPackageJson(directory) {
  const packageJsonFilepath = `${directory}/package.json`;
  return await fs.readJSON(packageJsonFilepath);
}


然後我們將創建一個 writePackageJson 函數,我們可以用它來向項目的 package.json 文件寫入更改:


async function writePackageJson(directory, contents) {
  const packageJsonFilepath = `${directory}/package.json`;
  await fs.writeJSON(packageJsonFilepath, contents, { spaces: 2 });
}


我們在上面的函數中使用的 fs.readJSON 和 fs.writeJSON 方法是由 fs-extra 庫提供的。


在定義了 package.json 輔助函數後,我們可以開始考慮 package.json 文件的內容。


Node.js 支持兩種模塊類型:


  • CommonJS Modules (CJS)。https://link.segmentfault.com/?enc=KTweLvts6a1zOlUbn0cnCA%3D%3D.WRSoJ3t37Y2GYjanjStt81N%2BkCOGoR11gK8pv6Fck09uaKTSXHq5mvMcWutIRxYU 使用 module.exports 來導出函數和對象,在另一個模塊中使用 require()加載它們。
  • ECMAScript Modules (ESM)。https://link.segmentfault.com/?enc=OUbF%2BkjeOpAlt3Fo9PFGFw%3D%3D.Ex%2BQVnop7rVNKtYxrnp%2Fhcm08eFRE7K2XLUBlFFQ7D4%3D 使用 export 來導出函數和對象,在另一個模塊中使用 import 加載它們。


Node.js 生態系統正在逐步採用 ES 模塊,這在客戶端 JavaScript 中是很常見的。當事情處於過渡階段時,我們需要決定我們的 Node.js 項目默認使用 CJS 模塊還是 ESM 模塊。讓我們創建一個 promptForModuleSystem 函數,詢問這個新項目應該使用哪種模塊類型:


async function promptForModuleSystem(moduleSystems) {
  const moduleSystem = await question(
    `Which Node.js module system do you want to use? (${moduleSystems.join(
      " or "
    )}) `,
    {
      choices: moduleSystems,
    }
  );
  return moduleSystem;
}


上面函數使用的 question 函數由 zx 提供。


現在我們將創建一個 getNodeModuleSystem 函數,以調用 promptForModuleSystem 函數。它將檢查所輸入的值是否有效。如果不是,它將再次詢問:


async function getNodeModuleSystem() {
  const moduleSystems = ["module", "commonjs"];
  const selectedModuleSystem = await promptForModuleSystem(moduleSystems);
  const isValidModuleSystem = moduleSystems.includes(selectedModuleSystem);
  if (!isValidModuleSystem) {
    console.error(
      chalk.red(
        `Error: Module system must be either '${moduleSystems.join(
          "' or '"
        )}'\n`
      )
    );
    return await getNodeModuleSystem();
  }
  return selectedModuleSystem;
}


現在我們可以通過運行 npm init 命令生成我們項目的 package.json 文件:


await $`npm init --yes`;


然後我們將使用 readPackageJson 輔助函數來讀取新創建的 package.json 文件。我們將詢問項目應該使用哪個模塊系統,並將其設置為 packageJson 對象中的 type 屬性值,然後將其寫回到項目的 package.json 文件中:


const packageJson = await readPackageJson(targetDirectory);
const selectedModuleSystem = await getNodeModuleSystem();
packageJson.type = selectedModuleSystem;
await writePackageJson(targetDirectory, packageJson);


提示:當你用--yes 標誌運行 npm init 時,要想在 package.json 中獲得合理的默認值,請確保你設置了 npminit-*的配置設置 https://link.segmentfault.com/?enc=X0aVKO8sVtj0bgZhFmgjVw%3D%3D.hxYbJxX5X2odlcPpk5MdIVLkT7ESAsFMhFnFSRBftI2c2BjNTUCtV1gwdXnpxWGI


安裝所需項目依賴


為了使運行我們的啟動工具後能夠輕鬆地開始項目開發,我們將創建一個 promptForPackages 函數,詢問要安裝哪些 npm 包:


async function promptForPackages() {
let packagesToInstall = await question(
  "Which npm packages do you want to install for this project? "
);
packagesToInstall = packagesToInstall
  .trim()
  .split(" ")
  .filter((pkg) => pkg);
return packagesToInstall;
}


為了防止我們在輸入包名時出現錯別字,我們將創建一個 identifyInvalidNpmPackages 函數。這個函數將接受一個 npm 包名數組,然後運行 npm view 命令來檢查它們是否存在:


async function identifyInvalidNpmPackages(packages) {
  $.verbose = false;
  let invalidPackages = [];
  for (const pkg of packages) {
    try {
      await $`npm view ${pkg}`;
    } catch (error) {
      invalidPackages.push(pkg);
    }
  }
  $.verbose = true;
  return invalidPackages;
}


讓我們創建一個 getPackagesToInstall 函數,使用我們剛剛創建的兩個函數:


async function getPackagesToInstall() {
  const packagesToInstall = await promptForPackages();
  const invalidPackages = await identifyInvalidNpmPackages(packagesToInstall);
  const allPackagesExist = invalidPackages.length === 0;
  if (!allPackagesExist) {
    console.error(
      chalk.red(
        `Error: The following packages do not exist on npm: ${invalidPackages.join(
          ", "
        )}\n`
      )
    );
    return await getPackagesToInstall();
  }
  return packagesToInstall;
}


如果有軟體包名稱不正確,上面的函數將顯示一個錯誤,然後再次詢問要安裝的軟體包。

一旦我們得到需要安裝的有效包列表,就可以使用 npm install 命令來安裝它們:


const packagesToInstall = await getPackagesToInstall();
const havePackagesToInstall = packagesToInstall.length > 0;
if (havePackagesToInstall) {
  await $`npm install ${packagesToInstall}`;
}


為工具生成配置


創建項目配置是我們用項目啟動工具自動完成的最佳事項。首先,讓我們添加一個命令來生成一個.gitignore 文件,這樣我們就不會意外地提交我們不希望在 Git 倉庫中出現的文件:


await $`npx gitignore node`;


上面的命令使用 gitignore https://link.segmentfault.com/?enc=V%2FIoxipE2WxmNECDRNKMqg%3D%3D.7Y4d34n%2BoUVlJkYEiJt3NLa9RHn2pYtKq%2BHpO67HIQjfjKAHIxcMynZzTudktHaV 包,從 GitHub 的 gitignore https://link.segmentfault.com/?enc=Szh56TKqT6gYmrJidM7ZXg%3D%3D.BK7Vf5F73GaplJKeN48OsobM6U4EPriatZOr3dBhsSVZIuIUiktyqfS1jhLLtQ7o 模板中拉取 Node.js 的.gitignore 文件。


為了生成我們的 EditorConfig https://link.segmentfault.com/?enc=dGD5%2BEyCTqLfqDSif7%2FHgQ%3D%3D.xgNWBjR6m%2FIUFlG1UmM3CYX2R%2BLXFN531lZhlvCRRWs%3D、Prettier https://link.segmentfault.com/?enc=n7clHFqLMZZala0zu1JjdQ%3D%3D.jivAg4cL8HkSAhuurMUHrlfhGGILOpveTQR0rjCRXyg%3D 和 ESLint https://link.segmentfault.com/?enc=J4jXEAmmBQ83%2FWSrOtTsAQ%3D%3D.b%2FKC0kT%2FZWZQ9KBItXDMQHWJBzc5aW9hUZsxWHBsMY4%3D 配置文件,我們將使用一個叫做 Mrm 的命令行工具。


全局安裝我們需要的 mrm 依賴項:


npm install --global mrm mrm-task-editorconfig mrm-task-prettier mrm-task-eslint


然後添加 mrm 命令行生成配置文件:


await $`npx mrm editorconfig`;
await $`npx mrm prettier`;
await $`npx mrm eslint`;


Mrm 負責生成配置文件,以及安裝所需的 npm 包。它還提供了大量的配置選項,允許我們調整生成的配置文件以符合我們的個人偏好。


生成 README


我們可以使用我們的 readPackageJson 輔助函數,從項目的 package.json 文件中讀取項目名稱。然後我們可以生成一個基本的 Markdown 格式的 README,並將其寫入 README.md 文件中:


const { name: projectName } = await readPackageJson(targetDirectory);
const readmeContents = `# ${projectName}
...
`;
await fs.writeFile(`${targetDirectory}/README.md`, readmeContents);


在上面的函數中,我們正在使用 fs-extra 暴露的 fs.writeFile 的 promise 變量。


提交項目骨架


最後,是時候提交我們用 git 創建的項目骨架了:


await $`git add .`;
await $`git commit -m "Add project skeleton"`;


然後我們將顯示一條消息,確認我們的新項目已經成功啟動:


console.log(
  chalk.green(
    `\n✔️ The project ${projectName} has been successfully bootstrapped!\n`
  )
);
console.log(chalk.green(`Add a git remote and push your changes.`));


啟動新項目


mkdir new-project
./bootstrap-tool.mjs --directory new-project


並觀看我們所做的一切。


總結


在這篇文章中,我們已經學會了如何在 Node.js 中藉助 Google 的 zx 庫來創建強大的 shell 腳本。我們使用了它提供的實用功能和庫來創建一個靈活的命令行工具。


到目前為止,我們所構建的工具只是一個開始。這裡有一些功能點子,你可能想嘗試自己添加:


自動創建目標目錄。如果目標目錄還不存在,則提示用戶並詢問他們是否想要為他們創建該目錄。


開源衛生。問問用戶他們是否在創建一個將是開源的項目。如果是的話,運行命令來生成許可證和貢獻者文件。


自動創建 GitHub 上的倉庫。添加使用 GitHub CLI 的命令,在 GitHub 上創建一個遠程倉庫。一旦用 Git 提交了初始骨架,新項目就可以被推送到這個倉庫。


本文中的所有代碼都可以在 GitHub 上找到。


本文譯自:https://link.segmentfault.com/?enc=5Z%2ByLQNgua%2FY5gnguxXllg%3D%3D.SeNINYETng%2BH6uZupDjhsYNRqM5GWB5jXVDlvMdMqsO9u3CmWfwe8DwT48iAvK%2Fsm8pflQ8jbxHc1sB281%2B6pA%3D%3D

作者:Simon Plenderleith


以上就是本文的所有內容。如果對你有所幫助,歡迎點讚、收藏、轉發~



關鍵字: