文档章节

Node.js 命令行工具的编写

o
 osc_w9s1w4o0
发布于 2019/04/12 23:16
字数 2291
阅读 12
收藏 0

精选30+云产品,助力企业轻松上云!>>>

<table class="d-block"> <tbody class="d-block"> <tr class="d-block"> <td class="d-block comment-body markdown-body js-comment-body">

<p>日常开发中,编写 Node.js 命令行工具来完成一些小任务是很常见的操作。其编写也不难,和日常编写 Node.js 代码并无二致。</p> <h2><code>package.json</code> 中的 <code>bin</code> 字段</h2> <p>一个 npm 模块,如果在 <code>package.json</code> 中指定了 <code>bin</code> 字段,那说明该模块提供了可在命令行执行的命令,这些命令就是在 <code>bin</code> 字段中指定的。</p> <p><em>package.json</em></p> <div class="highlight highlight-source-json"><pre>{ <span class="pl-s"><span class="pl-pds">"</span>bin<span class="pl-pds">"</span></span>: { <span class="pl-s"><span class="pl-pds">"</span>myapp<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>./cli.js<span class="pl-pds">"</span></span> } }</pre></div> <p>程序安装后会可在命令行执行 <code>myapp</code> 命令,实际执行的就是指定的这个 <code>cli.js</code> 文件。如果是全局安装,会将这个目标 js 文件映射到 <code>prefix/bin</code> 目录下,而如果是在项目中安装,则映射到 <code>./node_modules/.bin/</code> 目录下。</p> <p>比如上面的示例,全局安装后会将 <code>cli.js</code> 映射到 <code>/usr/local/bin/myapp</code> 目录下。</p> <div class="highlight highlight-source-shell"><pre><span class="pl-c"><span class="pl-c">#</span> 查看项目中安装的所有可执行模块</span> $ ll node_modules/.bin ... webpack -<span class="pl-k">&gt;</span> ../webpack/bin/webpack.js ...</pre></div> <p>如果你的 npm 包只提供了一个可执行的命令,可直接将 <code>bin</code> 字段设置为目标文件,此时命令行中可执行的 CLI 命令名为 npm 包名(即 <code>name</code> 字段)。</p> <div class="highlight highlight-source-json"><pre>{ <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>my-program<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>version<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>1.2.5<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>bin<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>./path/to/program<span class="pl-pds">"</span></span> }</pre></div> <p>所以上面的配置和下面这个配置是等效的。</p> <div class="highlight highlight-source-json"><pre>{ <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>my-program<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>version<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>1.2.5<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>bin<span class="pl-pds">"</span></span>: { <span class="pl-s"><span class="pl-pds">"</span>my-program<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>./path/to/program<span class="pl-pds">"</span></span> } }</pre></div> <p>执行:</p> <div class="highlight highlight-source-shell"><pre>$ my-program </pre></div> <h2>CLI 命令的编写</h2> <p>为项目添加 README 文件是很常见的操作,每次都从零开始是没必要的。这时候就可以通过创建一个 README 模板,然后写一个 CLI 工具来生成到项目中。这样,将工具安装到全局或通过 <code>npx</code> 就可以方便地完成 README 文件的创建。</p> <div class="highlight highlight-source-shell"><pre>$ npx mkreadme README.md created</pre></div> <h3>初始化项目</h3> <div class="highlight highlight-source-shell"><pre>$ npm init -y</pre></div> <p>修改 <code>package.json</code> 文件为如下内容:</p> <div class="highlight highlight-source-json"><pre>{ <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>mkreadme<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>bin<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>./cli.js<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>version<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>0.1.0<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>license<span class="pl-pds">"</span></span>: <span class="pl-s"><span class="pl-pds">"</span>MIT<span class="pl-pds">"</span></span> }</pre></div> <h3>创建入口文件</h3> <div class="highlight highlight-source-shell"><pre>$ touch cli.js</pre></div> <p>入口文件即 <code>bin</code> 字段所指向的文件,它可以是任何文件名,只需要在行首指定运行环境即可。Node.js 的 CLI 命令,期望的运行环境当然是 Node.js。</p> <p><em>cli.js</em></p> <div class="highlight highlight-source-js"><pre> #<span class="pl-k">!</span><span class="pl-sr"><span class="pl-pds">/</span>usr<span class="pl-pds">/</span></span>bin<span class="pl-k">/</span>env node <span class="pl-c"><span class="pl-c">//</span> 其他代码...</span></pre></div> <p>然后添加我们的功能代码,从远端获取一个 README 模板文件到本地。</p> <p><em>cli.js</em></p> <div class="highlight highlight-source-js"><pre><span class="pl-c">#!/usr/bin/env node</span>

<span class="pl-k">const</span> <span class="pl-c1">fs</span> <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">"</span>fs<span class="pl-pds">"</span></span>); <span class="pl-k">const</span> <span class="pl-c1">https</span> <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">"</span>https<span class="pl-pds">"</span></span>);

<span class="pl-k">const</span> <span class="pl-c1">TEMPLATE_FILE</span> <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">"</span>https://raw.githubusercontent.com/wayou/readme-template/master/README.md<span class="pl-pds">"</span></span>;

<span class="pl-k">const</span> <span class="pl-c1">file</span> <span class="pl-k">=</span> <span class="pl-smi">fs</span>.<span class="pl-en">createWriteStream</span>(<span class="pl-s"><span class="pl-pds">"</span>README.md<span class="pl-pds">"</span></span>); <span class="pl-smi">https</span>.<span class="pl-c1">get</span>(<span class="pl-c1">TEMPLATE_FILE</span>, <span class="pl-smi">resposne</span> <span class="pl-k">=></span> { <span class="pl-smi">resposne</span>.<span class="pl-en">pipe</span>(file); <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">"</span>README.md created<span class="pl-pds">"</span></span>); });</pre></div>

<p>这里,我们将模板文件放远端的一个位置然后通过网络请求下载下来,而不是直接放到 npm 模块中。这样做的好处是后面可以随时更新我们的模板文件而无须重新发布这个 npm 模块。</p> <h3>调试</h3> <p>通过在当前开发目录进行 <code>link</code> 操作可进行本地调试。</p> <div class="highlight highlight-source-shell"><pre>$ npm link</pre></div> <details> <summary> link 操作的输出信息 </summary> <div class="highlight highlight-source-shell"><pre>npm WARN mkreadme@0.1.0 No description npm WARN mkreadme@0.1.0 No repository field.

up to date <span class="pl-k">in</span> 3.435s found 0 vulnerabilities

/Users/wayou/.nvm/versions/node/v11.14.0/bin/mkreadme -<span class="pl-k">></span> /Users/wayou/.nvm/versions/node/v11.14.0/lib/node_modules/mkreadme/cli.js /Users/wayou/.nvm/versions/node/v11.14.0/lib/node_modules/mkreadme -<span class="pl-k">></span> /Users/wayou/Documents/dev/github/mkreadme</pre></div>

</details> <p>然后就可以在任何地方执行刚刚创建的 CLI 命令了。</p> <div class="highlight highlight-source-shell"><pre>$ mkreadme README.md created</pre></div> <h3>参数的获取</h3> <p>让命令支持参数可以实现更加灵活的功能。通过 <code>process.argv</code> 在代码中能够获取到来自命令行的输入。但需要注意它返回的参数列表中前两位是 Node.js 的路径和当前项目的路径,从第三个元素开始才是命令中用户输入的数据。</p> <div class="highlight highlight-source-diff"><pre><span class="pl-c"><span class="pl-c">#</span>!/usr/bin/env node</span>

const fs = require("fs"); const https = require("https");

const TEMPLATE_FILE = "https://raw.githubusercontent.com/wayou/readme-template/master/README.md";

<span class="pl-mi1"><span class="pl-mi1">+</span> const [, , ...args] = process.argv;</span>

const file = fs.createWriteStream("README.md"); <span class="pl-mi1"><span class="pl-mi1">+</span> const url = args[0] || TEMPLATE_FILE;</span> <span class="pl-mi1"><span class="pl-mi1">+</span> https.get(url, resposne => {</span> resposne.pipe(file); console.log("README.md created"); });</pre></div>

<p>通过添加参数的支持,我们可以让使用者手动指定一个模板地址以下载对应的模板文件。</p> <h3>发布</h3> <p>最后一步就是发布出去,这样所有人就能安装使用了。</p> <div class="highlight highlight-source-shell"><pre>$ npm publish --access public</pre></div> <h3>安装与使用</h3> <div class="highlight highlight-source-shell"><pre>$ npm i -g mkreadme $ mkreadme README.md created</pre></div> <p>除了像上面将命令安装到全局使用外,个人更加推荐的方式是通过 <code>npx</code>。<code>npx</code> 会自动查找本机是否有安装相应模块,如果没有的话,自动去远端查找并执行。通过 <code>npx</code> 就不用安装到本地,每次运行都可以使用远端最新的版本。</p> <div class="highlight highlight-source-shell"><pre>$ npx mkreadme README.md created</pre></div> <h3>后续的优化</h3> <p>示例中只实现了基本的功能,作为一个功能健全的实用工具,可以做以下的优化:</p> <ul> <li>生成时做重名判断,如果已经存在 README 文件则提示是否覆盖。</li> <li>文件下载和创建过程中的异常处理及提示。</li> <li>提供并打印帮助信息,对使用者更加友好。</li> <li>对输出进行格式化,高亮输出相关信息,使信息更易读。</li> </ul> <h3>完整的示例</h3> <p>上面示例中的代码可在 <a href="https://github.com/wayou/mkreadme">mkreadme</a> 这个仓库中找到。同时也发布到了 npm,可直接使用体验该工具。</p> <h2>三方工具</h2> <p>命令行工具能够打印帮助和使用信息是很重要的,如果自己输出的话,会面临格式化这些内容的麻烦。<br> 如果提供的参数很多,解析处理用户输入的参数也是件很麻烦的事。</p> <p>像参数校验,错误提示及帮助信息的输出,这些命令行工具基本的功能已经有三方库比较成熟地解决了,比如 <a href="https://github.com/tj/commander.js/">commander.js</a>。通过这个库可方便地编写更加复杂的命令行工具。</p> <p>至于将输出信息进行高亮加彩色进行展示,也有相应三方库比如 <a href="https://github.com/chalk/chalk">chalk</a>。</p> <h2>相关资源</h2> <ul> <li><a href="https://docs.npmjs.com/files/package.json#bin" rel="nofollow">npm-package.json 文档关于 <code>bin</code> 字段的描述</a></li> <li><a href="https://github.com/chalk/chalk">chalk</a></li> <li><a href="https://github.com/tj/commander.js/">commander.js</a></li> </ul> </td> </tr> </tbody> </table>

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

2020最新微信域名防封技术 微信域名防封系统是如何操作的

相信很多朋友在运营自己产品的网站或者是推广链接的时候,经常会发现运行的好好的网站链接突然就被封了,有一部分因为可能是网站的内容触犯了微信的规则,但是还有很大的一部分被同行恶意投诉...

戚馨逸
15分钟前
0
0
mysql 为什么 SQL 语句不要过多的 join?

第一部分 Linux上查看内存的使用情况该用什么命令 free -mh 可以看到内存或者缓存情况 total 总内存 used 已用内存 free 空闲内存 buff/cache 已使用的缓存 avaiable 可用内存 怎么清理已使...

edison_kwok
16分钟前
17
0
芒果TV的金融野心从未停止

来源|WEMONEY研究室 作者|林小林 芒果TV是真的会讲故事,《乘风破浪的姐姐》不仅是生活的故事更是资本的故事,30位姐姐让一款节目累计播放量飙升10亿,同时让背后的上市公司芒果超媒市值站...

镭射财经
28分钟前
4
0
找到的程序集的清单定义与程序集引用不匹配

问题: I am trying to run some unit tests in a C# Windows Forms application (Visual Studio 2005), and I get the following error: 我试图在C#Windows窗体应用程序(Visual Studio 2......

法国红酒甜
29分钟前
16
0
渗透测试的概念和实战

目录 1. 前言 2. 常见web安全漏洞 3. 思路 3.1渗透测试思路 3.2黑客攻击思路 4. 暴力破解 4.1谷歌黑语法 4.1.1 黑语法inurl:搜索url包含指定字符串 4.1.2 黑语法intitle:搜索网页中的标题名...

六道木
44分钟前
21
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部