使用nodejs创建Helloworld CLI命令
#javascript #初学者 #node #cli

我最近从柏林Weardeveloders组织的世界大会会议上回来。这是我第二次参加,我看到了一些非常鼓舞人心的演讲。其中一个特别引起了我的注意。这是菲尔·纳什(Phil Nash)(Sonar)的演讲,标题为从JavaScript到Typescript 的4个步骤。除了在打字稿上的课程外,他还使用nodejs创建CLI命令。

现在,这是没有看不见的,我们都使用了用JS编写的各种CLI命令(想想NPM,垃圾CLI等),但是从来没有想过自己写我的。过去,当我需要一个CLI脚本时,我在ZSH中写了它。但是,其中一个变得太复杂了,我想着自己:“下次我将用另一种语言写这篇文章。”在菲尔的谈话中,我有那个时刻。当然,我可以使用JS!

简要

这是我第一次学习在nodejs中创建CLI命令的来龙去脉的小练习。这是我给自己的简介。

创建一个CLI命令,该命令接受许多参数和显示:

  1. “你好世界!”没有参数。

  2. “你好[名字]!”如果提供了一个参数。

  3. “你好[name1]和[name2]!”对于两个参数。

  4. “你好[name1],[name2],�[namex]!”对于三个及以上的参数。

先决条件

  • Node获得一些最近的版本,即18岁以上,它也可能在古代版本上使用,但是如果您必须使用旧版本的节点,那么您可能会知道自己在做什么。<<<<<<<<< /p>

  • PNPM node软件包管理器

解决方案

tldr;

对于那些以结果为导向的人,您可以find the repo on my Github account

创建一个节点软件包

首先,我创建了一个新的节点软件包。如今,我选择的软件包经理是koude0'它的快速,性能更高,并且由于其处理节点模块的方式,磁盘上的空间更少。

# Create and enter a new folder
take hello-world-cli
# Initialise a new Node package
pnpm init

这将使用基本默认元数据创建一个 package.json 文件。我们需要该文件来安装我们的依赖项。

基本文件结构

./
├── LICENSE
├── README.md
├── bin
│   └── hello
├── node_modules
├── package.json
├── pnpm-lock.yaml
└── src
    ├── cli.js
    └── greetings.js

CLI命令hello

首先,我们创建文件 hello touch /bin/hello。这将是用户将启动的实际命令。确保使其可执行chmod a+x ./bin/hello

#!/usr/bin/env node

const { run } = require('../src/cli');
run(process.argv).catch((err) => console.error(err));

您可以看到,我指定了使用节点作为解释器执行此文件的shebang。这使我们能够使用js从/src/cli.js导入run()函数,并将其称为异步将参数数组(koude6)从命令行传递为其参数。第一个元素process.argv[0]是只读的,通常保留给处理器的绝对路径(在我的情况下:/Users/myuser/.nvm/versions/node/v20.5.1/bin/node。第二个数组process.argv[1]是我们正在运行的命令的路径:/Users/myuser/Sites/_tuts/hello-word-cli/hello

如果有错误,我会抓住它并将其显示在控制台中。

run()处理命令

首先,让我们安装yargs软件包,以使我们的生活更轻松地处理所有可能的参数:pnpm install yargs。我将仅触摸此软件包可以为您做的事情的表面,但是,即使对于更复杂的CLI命令,这也是一个很好的模板。

这是/scr/cli.js中的代码。

const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const { showGreeting } = require('./greetings');
async function run(args) {
    const { _: names } = yargs(hideBin(args)).argv;
    showGreeting(names);
}
module.exports = { run };

i导入yargs()函数及其辅助功能hideBin()hideBin(args)args.slice(2)的速记。这样,您即使在Electron等不标准的环境中也可以使您的命令工作。

我定义了以数组为参数的异步函数run(args)。使用yargs()hideBin()函数处理此参数。

i从argv返回的argv_属性,并将此变量重命名为names,以便于我的代码的便利性,然后将names传递给我的showGreeting(names)函数。

就是这样!就CLI命令的处理而言,我们完成了。其余的只是像往常一样朴素的JS。

showGreeting(names)-显示正确的问候

文件/src/greetings.js用作与显示问候有关的功能库。

const joinTwoNames = (twoNames) => {
    return `${twoNames.join(' and ')}`;
};

const getLongGreetings = (longListOfNames) => {
    return longListOfNames.reduce(
        (acc, name, currentIndex) =>
            currentIndex < longListOfNames.length - 1
                ? `${acc}${name}, `
                : `${acc.slice(0, acc.length - 2)} and ${name}`,
        ''
    );
};

const getGreetings = (names) => {
    const greetingsList = [
        'Hello world!',
        `Hi there ${names[0}!`,
        `Hi there ${joinTwoNames(names)}!`,
        `Hi there ${getLongGreetings(names)}!`,
    ];
    const greetingsIndex = names.length >= 3 ? 3 : names.length;
    return `${greetingsList[greetingsIndex]}`;
};

const showGreeting = (names) => {
    const greeting = getGreetings(names);
    console.log(greeting);
};

module.exports = {
    getGreetings,
    showGreeting,
};

我以方便的方便导出了showGreeting()功能以及getGreetings(),即使我目前不使用getGreetings()

getGreetings(names)函数中保存的字符串模板列表,用于决定使用哪种问候,具体取决于传递多少名称作为参数。

  1. 没有名字?很好,只是Hello world!

  2. 一个名字?简单,Hi there, ${names[0]}将打印names数组的第一个(也是唯一)项目。

  3. 对于两个名称,我有一个辅助函数joinTwoNames(twoNames),该函数在阵列中添加了两个名称,并在它们之间添加and,然后在greetingList[2]字符串模板中使用。

  4. 最终将使用getLongGreetings(longListOfNames)函数来依靠高阶方法array.prototype.reduce()将所有单个名称与逗号相连为其分离器,除了最后两个将由由逗号链接的函数连词and

就是这样,伙计们!

希望您发现这有用,如果您有任何疑问或评论,请告诉我。我打算以一种简单易懂的方式演示在节点中创建简单CLI命令的基础知识。


Emma Plunkett的封面图像©2016