我最近从柏林Weardeveloders组织的世界大会会议上回来。这是我第二次参加,我看到了一些非常鼓舞人心的演讲。其中一个特别引起了我的注意。这是菲尔·纳什(Phil Nash)(Sonar)的演讲,标题为从JavaScript到Typescript 的4个步骤。除了在打字稿上的课程外,他还使用nodejs创建CLI命令。
现在,这是没有看不见的,我们都使用了用JS编写的各种CLI命令(想想NPM,垃圾CLI等),但是从来没有想过自己写我的。过去,当我需要一个CLI脚本时,我在ZSH中写了它。但是,其中一个变得太复杂了,我想着自己:“下次我将用另一种语言写这篇文章。”在菲尔的谈话中,我有那个时刻。当然,我可以使用JS!
简要
这是我第一次学习在nodejs中创建CLI命令的来龙去脉的小练习。这是我给自己的简介。
创建一个CLI命令,该命令接受许多参数和显示:
“你好世界!”没有参数。
“你好[名字]!”如果提供了一个参数。
“你好[name1]和[name2]!”对于两个参数。
“你好[name1],[name2],�[namex]!”对于三个及以上的参数。
先决条件
解决方案
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)
函数中保存的字符串模板列表,用于决定使用哪种问候,具体取决于传递多少名称作为参数。
-
没有名字?很好,只是
Hello world!
。 -
一个名字?简单,
Hi there, ${names[0]}
将打印names
数组的第一个(也是唯一)项目。 -
对于两个名称,我有一个辅助函数
joinTwoNames(twoNames)
,该函数在阵列中添加了两个名称,并在它们之间添加and
,然后在greetingList[2]
字符串模板中使用。 -
最终将使用
getLongGreetings(longListOfNames)
函数来依靠高阶方法array.prototype.reduce()
将所有单个名称与逗号相连为其分离器,除了最后两个将由由逗号链接的函数连词and
。
就是这样,伙计们!
希望您发现这有用,如果您有任何疑问或评论,请告诉我。我打算以一种简单易懂的方式演示在节点中创建简单CLI命令的基础知识。
Emma Plunkett的封面图像©2016