Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何使用zx编写shell脚本

如何使用zx编写shell脚本

作者头像
chuckQu
发布于 2022-11-28 08:24:19
发布于 2022-11-28 08:24:19
4.1K00
代码可运行
举报
文章被收录于专栏:前端F2E前端F2E
运行总次数:0
代码可运行

前言

在这篇文章中,我们将学习谷歌的zx库提供了什么,以及我们如何使用它来用Node.js编写shell脚本。然后,我们将学习如何通过构建一个命令行工具来使用zx的功能,帮助我们为新的Node.js项目引导配置。

编写Shell脚本的问题

创建一个由Bash或者zsh执行的shell脚本,是自动化重复任务的好方法。Node.js似乎是编写shell脚本的理想选择,因为它为我们提供了许多核心模块,并允许我们导入任何我们选择的库。它还允许我们访问JavaScript提供的语言特性和内置函数。

如果你尝试编写运行在Node.js中的shell脚本,你会发现这没有你想象中的那么顺利。你需要为子进程编写特殊的处理程序,注意转义命令行参数,然后最终与stdout(标准输出)和stderr(标准错误)打交道。这不是特别直观,而且会使shell脚本变得相当笨拙。

Bash shell脚本语言是编写shell脚本的普遍选择。不需要编写代码来处理子进程,而且它有内置的语言特性来处理stdoutstderr。但是用Bash编写shell脚本也不是那么容易。语法可能相当混乱,使得它实现逻辑,或者处理诸如提示用户输入的事情非常困难。

谷歌的zx库[1]有助于让使用Node.js编写的shell脚本变得高效和舒适。

前置条件

往下阅读之前,有几个前置条件需要遵循:

  • 理想情况下,你应该熟悉JavaScript和Node.js的基础知识。
  • 你需要适应在终端中运行命令。
  • 你需要安装Node.js >= v14.13.1

本文中的所有代码都可以从GitHub[2]上获得。

zx如何运作

Google的zx提供了创建子进程的函数,以及处理这些进程的stdoutstderr的函数。我们将使用的主要函数是$函数。下面是它的一个实际例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { $ } from "zx";

await $`ls`;

下面是执行上述代码的输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ ls
bootstrap-tool
hello-world
node_modules
package.json
README.md
typescript

上面的例子中的JavaScript语法可能看起来有点古怪。它使用了一种叫做带标签的模板字符串[3]的语言特性。它在功能上与编写await $("ls")相同。

谷歌的zx提供了其他几个实用功能,使编写shell脚本更容易。比如:

  • cd()。允许我们更改当前工作目录。
  • question()。这是Node.js readline[4]模块的包装器。它使提示用户输入变得简单明了。

除了zx提供的实用功能外,它还为我们提供了几个流行的库,比如:

  • chalk[5]。这个库允许我们为脚本的输出添加颜色。
  • minimist[6]。一个解析命令行参数的库。然后它们在argv对象下被暴露出来。
  • fetch[7]。Fetch API的Node.js实现。我们可以用它来进行HTTP请求。
  • fs-extra[8]。一个暴露Node.js核心fs模块的库,以及一些额外的方法,使其更容易与文件系统一起工作。

现在我们知道了zx给了我们什么,让我们用它创建第一个shell脚本。

zx如何使用

首先,我们先创建一个新项目:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mkdir zx-shell-scripts
cd zx-shell-scripts

npm init --yes

然后安装zx库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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[9]行,它告诉操作系统(OS)的内核要用node程序运行该脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#! /usr/bin/env node

然后,我们添加一些代码,使用zx来运行命令。

在下面的代码中,我们运行命令执行ls程序。ls程序将列出当前工作目录(脚本所在的目录)中的文件。我们将从命令的进程中捕获标准输出,将其存储在一个变量中,然后打印到终端:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 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来让脚本可执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chmod u+x hello-world.mjs

运行项目:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./hello-world.mjs

可以看到如下输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ 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命令前加入以下一行代码来改变这种行为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$.verbose = false;

大多数命令行程序,如ls,会在其输出的结尾处输出一个新行字符,以使输出在终端中更易读。这对可读性有好处,但由于我们要将输出存储在一个变量中,我们不希望有这个额外的新行。我们可以用JavaScript String#trim()函数把它去掉:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- const output = (await $`ls`).stdout;
+ const output = (await $`ls`).stdout.trim();

再次运行脚本,结果看起来好很多:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
hello-world.mjs
node_modules
package.json
package-lock.json

引入TypeScript

如果我们想在TypeScript中编写使用zx的shell脚本,有几个微小的区别我们需要加以说明。

注意:TypeScript编译器提供了大量的配置选项,允许我们调整它如何编译我们的TypeScript代码。考虑到这一点,下面的TypeScript配置和代码是为了在大多数TypeScript版本下工作。

首先,安装需要运行TypeScript代码的依赖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install --save-dev typescript ts-node

ts-node包提供了一个TypeScript执行引擎,让我们能够转译和运行TypeScript代码。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "compilerOptions": {
    "target": "es2017",
    "module": "commonjs"
  }
}

创建新的脚本,并命名为hello-world-typescript.ts。首先,添加Shebang行,告诉OS内核使用ts-node程序来运行我们的脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#! ./node_modules/.bin/ts-node

为了在我们的TypeScript代码中使用await关键字,我们需要把它包装在一个立即调用函数表达式(IIFE)中,正如zx文档所建议的那样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// hello-world-typescript.ts

import { $ } from "zx";

void (async function () {
  await $`ls`;
})();

然后需要让脚本可执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chmod u+x hello-world-typescript.ts

运行脚本:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
./hello-world-typescript.ts

可以看到下面的输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ 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模块:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#! /usr/bin/env node

// bootstrap-tool.mjs

import { $, argv, cd, chalk, fs, question } from "zx";

import path from "path";

与我们之前创建的脚本一样,我们要使我们的新脚本可执行:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
chmod u+x bootstrap-tool.mjs

我们还将定义一个辅助函数,用红色文本输出一个错误信息,并以错误退出代码1退出Node.js进程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function exitWithError(errorMessage) {
  console.error(chalk.red(errorMessage));
  process.exit(1);
}

当我们需要处理一个错误时,我们将通过我们的shell脚本在各个地方使用这个辅助函数。

检查依赖

我们要创建的工具需要使用三个不同程序来运行命令:gitnodenpx。我们可以使用which[10]库来帮助我们检查这些程序是否已经安装并可以使用。

首先,我们需要安装which

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install --save-dev which

然后引入它:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import which from "which";

然后创建一个使用它的checkRequiredProgramsExist函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的调用,以检查我们的工具所依赖的程序是否可用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await checkRequiredProgramsExist(["git", "node", "npx"]);

添加目标目录选项

由于我们正在构建的工具将帮助我们启动新的Node.js项目,因此我们希望在项目的目录中运行我们添加的任何命令。我们现在要给脚本添加一个 --directory命令行参数。

zx内置了minimist[11]包,它能够解析传递给脚本的任何命令行参数。这些被解析的命令行参数被zx包作为argv提供:

让我们为名为directory的命令行参数添加一个检查:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let targetDirectory = argv.directory;
if (!targetDirectory) {
  exitWithError("Error: You must specify the --directory argument");
}

如果directory参数被传递给了我们的脚本,我们要检查它是否是已经存在的目录的路径。我们将使用fs-extra提供的fs.pathExists方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
targetDirectory = path.resolve(targetDirectory);

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

如果目标路径存在,我们将使用zx提供的cd函数来切换当前的工作目录:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cd(targetDirectory);

如果我们现在在没有--directory参数的情况下运行脚本,我们应该会收到一个错误:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ ./bootstrap-tool.mjs

Error: You must specify the --directory argument

检查全局Git设置

稍后,我们将在项目目录下初始化一个新的 Git 仓库,但首先我们要检查 Git 是否有它需要的配置。我们要确保提交会被GitHub等代码托管服务正确归类。

为了做到这一点,这里创建一个getGlobalGitSettingValue函数。它将运行 git config命令来检索Git配置设置的值:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数以检索其值。如果设置没有值,将显示警告信息:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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.nameuser.email的Git设置是否已经被设置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await checkGlobalGitSettings(["user.name", "user.email"]);

初始化Git仓库

我们可以通过添加以下命令在项目目录下初始化一个新的 Git 仓库:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await $`git init`;

生成package.json

每个Node.js项目都需要package.json文件。这是我们为项目定义元数据的地方,指定项目所依赖的包,以及添加实用的脚本。

在我们为项目生成package.json文件之前,我们要创建几个辅助函数。第一个是readPackageJson函数,它将从项目目录中读取package.json文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
async function readPackageJson(directory) {
  const packageJsonFilepath = `${directory}/package.json`;

  return await fs.readJSON(packageJsonFilepath);
}

然后我们将创建一个writePackageJson函数,我们可以用它来向项目的package.json文件写入更改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
async function writePackageJson(directory, contents) {
  const packageJsonFilepath = `${directory}/package.json`;

  await fs.writeJSON(packageJsonFilepath, contents, { spaces: 2 });
}

我们在上面的函数中使用的fs.readJSONfs.writeJSON方法是由fs-extra库提供的。

在定义了package.json辅助函数后,我们可以开始考虑package.json文件的内容。

Node.js支持两种模块类型:

  • CommonJS Modules[12] (CJS)。使用module.exports来导出函数和对象,在另一个模块中使用require()加载它们。
  • ECMAScript Modules[13] (ESM)。使用export来导出函数和对象,在另一个模块中使用import加载它们。

Node.js生态系统正在逐步采用ES模块,这在客户端JavaScript中是很常见的。当事情处于过渡阶段时,我们需要决定我们的Node.js项目默认使用CJS模块还是ESM模块。让我们创建一个promptForModuleSystem函数,询问这个新项目应该使用哪种模块类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数。它将检查所输入的值是否有效。如果不是,它将再次询问:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await $`npm init --yes`;

然后我们将使用readPackageJson辅助函数来读取新创建的package.json文件。我们将询问项目应该使用哪个模块系统,并将其设置为packageJson对象中的type属性值,然后将其写回到项目的package.json文件中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const packageJson = await readPackageJson(targetDirectory);
const selectedModuleSystem = await getNodeModuleSystem();

packageJson.type = selectedModuleSystem;

await writePackageJson(targetDirectory, packageJson);

提示:当你用--yes标志运行npm init时,要想在package.json中获得合理的默认值,请确保你设置了npminit-*配置设置[14]。

安装所需项目依赖

为了使运行我们的启动工具后能够轻松地开始项目开发,我们将创建一个 promptForPackages函数,询问要安装哪些npm包:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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命令来检查它们是否存在:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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函数,使用我们刚刚创建的两个函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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命令来安装它们:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const packagesToInstall = await getPackagesToInstall();
const havePackagesToInstall = packagesToInstall.length > 0;
if (havePackagesToInstall) {
  await $`npm install ${packagesToInstall}`;
}

为工具生成配置

创建项目配置是我们用项目启动工具自动完成的最佳事项。首先,让我们添加一个命令来生成一个.gitignore文件,这样我们就不会意外地提交我们不希望在Git仓库中出现的文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await $`npx gitignore node`;

上面的命令使用gitignore[15]包,从GitHub的gitignore模板[16]中拉取Node.js的.gitignore文件。

为了生成我们的EditorConfig[17]、Prettier[18]和ESLint[19]配置文件,我们将使用一个叫做Mrm[20]的命令行工具。

全局安装我们需要的mrm依赖项:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install --global mrm mrm-task-editorconfig mrm-task-prettier mrm-task-eslint

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await $`npx mrm editorconfig`;
await $`npx mrm prettier`;
await $`npx mrm eslint`;

Mrm负责生成配置文件,以及安装所需的npm包。它还提供了大量的配置选项,允许我们调整生成的配置文件以符合我们的个人偏好。

生成README

我们可以使用我们的readPackageJson辅助函数,从项目的package.json文件中读取项目名称。然后我们可以生成一个基本的Markdown格式的README,并将其写入README.md文件中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const { name: projectName } = await readPackageJson(targetDirectory);
const readmeContents = `# ${projectName}

...
`;

await fs.writeFile(`${targetDirectory}/README.md`, readmeContents);

在上面的函数中,我们正在使用fs-extra暴露的fs.writeFile的promise变量。

提交项目骨架

最后,是时候提交我们用git创建的项目骨架了:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
await $`git add .`;
await $`git commit -m "Add project skeleton"`;

然后我们将显示一条消息,确认我们的新项目已经成功启动:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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.`));

启动新项目

现在我们可以使用我们创建的工具来启动一个新的项目:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mkdir new-project

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

并观看我们所做的一切。

总结

在这篇文章中,我们已经学会了如何在Node.js中借助Google的zx库来创建强大的shell脚本。我们使用了它提供的实用功能和库来创建一个灵活的命令行工具。

到目前为止,我们所构建的工具只是一个开始。这里有一些功能点子,你可能想尝试自己添加:

  • 自动创建目标目录。如果目标目录还不存在,则提示用户并询问他们是否想要为他们创建该目录。
  • 开源卫生。问问用户他们是否在创建一个将是开源的项目。如果是的话,运行命令来生成许可证[21]和贡献者[22]文件。
  • 自动创建GitHub上的仓库。添加使用GitHub CLI[23]的命令,在GitHub上创建一个远程仓库。一旦用Git提交了初始骨架,新项目就可以被推送到这个仓库。

本文中的所有代码都可以在GitHub[24]上找到。

  • 本文译自:https://www.sitepoint.com/google-zx-write-node-shell-scripts/
  • 作者:Simon Plenderleith

以上就是本文的所有内容。如果对你有所帮助,欢迎点赞、收藏、转发~

参考资料

[1]

zx库: https://www.npmjs.com/package/zx

[2]

GitHub: https://github.com/simonplend/node-shell-scripting-with-zx

[3]

带标签的模板字符串: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

[4]

readline: https://nodejs.org/api/readline.html

[5]

chalk: https://www.npmjs.com/package/chalk

[6]

minimist: https://www.npmjs.com/package/minimist

[7]

fetch: https://www.npmjs.com/package/node-fetch

[8]

fs-extra: https://www.npmjs.com/package/fs-extra

[9]

Shebang: https://zh.m.wikipedia.org/zh-hans/Shebang

[10]

which: https://www.npmjs.com/package/which

[11]

minimist: https://www.npmjs.com/package/minimist

[12]

CommonJS Modules: https://nodejs.org/api/modules.html

[13]

ECMAScript Modules: https://nodejs.org/api/esm.html

[14]

配置设置: https://docs.npmjs.com/cli/v8/using-npm/config

[15]

gitignore: https://www.npmjs.com/package/gitignore

[16]

gitignore模板: https://github.com/github/gitignore

[17]

EditorConfig: https://editorconfig.org/

[18]

Prettier: https://prettier.io/

[19]

ESLint: https://eslint.org/

[20]

Mrm: https://mrm.js.org/

[21]

许可证: https://choosealicense.com/

[22]

贡献者: https://www.contributor-covenant.org/

[23]

GitHub CLI: https://cli.github.com/

[24]

GitHub: https://github.com/simonplend/node-shell-scripting-with-zx

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-11-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端F2E 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
nodejs写bash脚本终极方案!
最近在学习bash脚本语法,但是如果对bash语法不是熟手的话,感觉非常容易出错,比如说:显示未定义的变量shell中变量没有定义,仍然是可以使用的,但是它的结果可能不是你所预期的。举个例子:
IT大咖说
2021/07/19
3.9K0
nodejs 写 bash 脚本终极方案!
最近在学习bash脚本语法,但是如果对bash语法不是熟手的话,感觉非常容易出错,比如说:显示未定义的变量shell中变量没有定义,仍然是可以使用的,但是它的结果可能不是你所预期的。举个例子:
ConardLi
2021/09/08
2.6K0
nodejs 写 bash 脚本终极方案!
工具库 zx - 使用 JavaScript 更便捷地编写 shell 脚本
在编写一些复杂脚本做处理的时候,比起传统 shell 脚本,由于对 JS 更加熟悉,我更倾向于使用 JS 来编写。但一旦涉及到文件相关操作,几条 shell 指令肯定是更加方便的,但 Node 本身的 child_process 又差了那么点意思,手感并不是很好。
Shiroka
2022/04/28
9230
工具库 zx - 使用 JavaScript 更便捷地编写 shell 脚本
使用 JavaScript 编写 Shell 脚本
作为程序员,在平时的开发中肯定少不了一些命令行操作了。当然,简单的命令大家都是可以拿捏的,但是涉及到一些逻辑的时候还是比较头疼的。
ConardLi
2023/01/09
1.2K0
yyds,这可能是你第一个自定义的脚手架
哈喽大咖好,我是Johnny,这次给大家重新缕一缕如何用typescript配合周边插件做一个易用的脚手架管理工具。
南山种子外卖跑手
2022/09/09
8530
yyds,这可能是你第一个自定义的脚手架
靓仔快来!!用typescript带你搭建一个自己的脚手架
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
南山种子外卖跑手
2022/06/12
1.7K0
靓仔快来!!用typescript带你搭建一个自己的脚手架
(满满干货)从零实现命令行脚手架工具——自动初始化项目工程以及发布到NPM
这篇文章将带你从零实现一款命令行脚手架工具用于初始化项目以及如何发布到NPM。首先,我们所熟知的VueCLI就是采用命令行工具快速生成项目工程目录的,这样,我们每次开发项目前只需要在命令行中输入命令,然后就可以快速生成项目工程,非常方便。那么,这么方便的命令行工具是怎么实现的呢?下面我们就开始进入实战环节。
Vam的金豆之路
2021/12/01
6050
从0开始搭建优雅的前端脚手架工具
在日常开发中,我们经常会使用到各种脚手架工具(cli): vue-create-app,ng 包括 npm。它们极大简化了开发人员对于项目结构和文件创建的工作,让我们可以把精力专心在业务实现上。 对于某些项目而言 cli还可以封装一些脚本,用来处理项目中的一些特殊场景。
用户8738532
2022/12/05
6360
VueUse scripts,他们都模仿过的脚本
今天我们就“单纯”地从 VueUse scripts 入手,从中探索我们后续也许会用上的第三方包库。
码农小余
2022/06/16
1.2K0
VueUse scripts,他们都模仿过的脚本
开发前端 CLI 脚手架思路解析
在实际的开发过程中,我们经常用别人开发的脚手架,以节约搭建项目的时间。但是,当 npm 没有自己中意的脚手架时,我们不得不自己动手,此时学会开发前端 CLI 脚手架的技能就显得非常重要。搭建一个符合大众化的脚手架能使自己在项目经验上加个分哦!
winty
2021/12/17
7920
开发前端 CLI 脚手架思路解析
Node.js 初入门?持续记录
教程:https://www.runoob.com/nodejs/nodejs-tutorial.html
房东的狗丶
2023/02/17
1.2K0
从零开始构建 vue3
2019年10月5日凌晨,Vue 的作者尤雨溪公布了 Vue3 的源代码。当然,它暂时还不是完整的 Vue3,而是 pre-alpha 版,只完成了一些核心功能。github 命名为 vue-next ,寓意下一代 vue 。在笔者发文前,已经有很多大佬陆续发布了一些解读 Vue3 源码的文章。但是,本文并不打算再增加一篇解读源码的文章,而是以项目参与者的视角,通过动手实践,一步步理解和搭建自己的 Vue3 项目。因此,为了达到最佳效果,建议读者,一边阅读本文,一边打开终端跟着一步步动手实践。你将掌握所有构建 Vue3 所必须的知识。
我是一条小青蛇
2019/10/23
1.6K0
从零开始构建 vue3
从零撸一个CLI命令行脚手架工具
我想大部分同学肯定都是这样回答的:现在社区都有开箱即用的脚手架,像vue-cli、create-react-app这种,我们直接用脚手架来创建项目就可以了啊。
前端森林
2021/02/03
1.1K0
从零撸一个CLI命令行脚手架工具
尤大是如何发布vuejs的,学完可以应用到项目
1.源码地址:https://github1s.com/vuejs/vue-next/blob/HEAD/scripts/release.js
童欧巴
2021/08/20
5880
尤大是如何发布vuejs的,学完可以应用到项目
如何开发一个极简的前端脚手架
功能上,要满足登录,权限管理,菜单配置,用户管理,字典管理,角色管理等后台管理系统的常规功能,
虎妞先生
2023/10/16
3880
如何开发一个极简的前端脚手架
能用js实现的最终用js实现,Shell脚本也不例外
今天来讨论一个牛逼的项目 ——zx ,1个月增长15000 star, 成为了2021年度明星项目排行榜第一。
秋风的笔记
2022/01/18
3.4K0
能用js实现的最终用js实现,Shell脚本也不例外
前端CLI脚手架思路解析并从0到1搭建
在实际的开发过程中,我们经常用别人开发的脚手架,以节约搭建项目的时间。但是,当npm没有自己中意的脚手架时,我们不得不自己动手,此时学会开发前端CLI脚手架的技能就显得非常重要。搭建一个符合大众化的脚手架能使自己在项目经验上加个分哦!
IT大咖说
2020/10/19
1.5K0
前端CLI脚手架思路解析并从0到1搭建
带你了解并实践monorepo和pnpm,绝对干货!熬夜总结!
简单来说就是,将多个项目或包文件放到一个git仓库来管理。 目前比较广泛应用的是yarn+lerna的方式实现monorepo的管理。 一个简单的monorepo的目录结构类似这样:
winty
2023/08/23
7.4K0
带你了解并实践monorepo和pnpm,绝对干货!熬夜总结!
node命令行工具之实现项目工程自动初始化的标准流程
可以看出,传统的初始化步骤,花费的时间并不少。而且,人工操作的情况下,总有改漏的情况出现。这个缺点有时很致命。 甚至有马大哈,没有更新项目仓库地址,导致提交代码到旧仓库,这就很尴尬了。。。 基于这些情况,编写命令行工具(CLI)的目的就很明确:
我是leon
2019/08/28
7970
node命令行工具之实现项目工程自动初始化的标准流程
Axios 功能扩展之 axios-retry 源码阅读笔记
通过对 axios-retry 这一周下载量 100w+ 的三方库来学习下其功能设计,工具库项目的发包策略,并借此抛砖引玉,以提升我们的编码设计能力!
小东同学
2022/07/29
1.5K0
Axios 功能扩展之 axios-retry 源码阅读笔记
推荐阅读
相关推荐
nodejs写bash脚本终极方案!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验