Node.js 从零开发并发布 CLI 工具:以天气查询为例
本文详细介绍如何使用 Node.js 从零构建并发布一个命令行工具(CLI)。内容涵盖项目初始化、bin 入口配置、本地调试技巧,以及利用 minimist 解析命令行参数。通过集成 axios 和心知天气 API 实现真实数据查询,并添加 ora 库优化用户交互体验,最终演示如何将工具发布至 npm 供全局使用。
Node.js CLI 工具开发概述
CLI(命令行界面)本质上是用户与程序交互的接口,通过接收指令和参数来获取反馈。优秀的 CLI 工具通常提供清晰的帮助信息,例如我们常用的 vue-cli 便是典型代表。本文将演示如何使用 Node.js 从零开始开发并发布一款用于查询天气的 CLI 工具。
项目运行效果如下图所示:
项目初始化与本地调试配置
配置项目
首先初始化项目:npm init -y 接着编写入口文件 index.js:
module.exports = function(){
console.log('welcome to Anderlaw weather')
}
创建 bin 目录
在 bin 目录下创建 index 文件:
#!/usr/bin/env node
require('../')()
在 package.json 中配置 bin 字段信息
{
"name": "weather",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": {
"weather": "bin/index"
}
}
随后在根目录(与 package.json 同级)执行 npm link,该命令会将当前项目的模块信息及 bin 指令以软链接形式注册到 npm 全局环境中:
- 此时在
C:\Users\mlamp\AppData\Roaming\npm\node_modules目录下会新增一个模块链接 - 在
C:\Users\mlamp\AppData\Roaming\npm目录下会生成一个名为weather的 cmd 文件。
这样做的好处是便于本地调试。打开终端输入:weather,即可看到 welcome to Anderlaw weather 的日志输出。
命令行参数解析与逻辑处理
解析命令与参数
此处我们选用 minimist 库来解析类似 npm --save、npm install 等命令的参数。
安装依赖库 npm i -S minimist
通过 process.argv 获取完整的输入信息
使用 minimist 进行解析,例如:
weather today === args:{_:['today']}
weather -h === args:{ h:true }
weather --location 'china' === args:{location:'china'}
首先实现查询今天和明天天气的功能,执行命令 weather today[tomorrow]
const minimist = require('minimist');
module.exports = ()=>{
const args = minimist(process.argv.slice(2));//前两个是编译器相关路径信息,可以忽略
let cmd = args._[0];
switch(cmd){
case 'today':
console.log('今天天气不错呢,暖心悦目!');
break;
case 'tomorrow':
console.log('明天下大雨,注意带雨伞!');
break;
}
}
上述代码中,若直接输入 weather 则会报错,因为未获取到有效参数。此外,目前尚未添加版本信息,因此需要进一步优化代码。
const minimist = require('minimist')
const edition = require('./package.json').version
module.exports = ()=>{
const args = minimist(process.argv.slice(2));//前两个是编译器相关路径信息,可以忽略
let cmd = args._[0] || 'help';
if(args.v || args.version){
cmd = 'version';//查询版本优先!
}
switch(cmd){
case 'today':
console.log('今天天气不错呢,暖心悦目!');
break;
case 'tomorrow':
console.log('明天下大雨,注意带雨伞!');
break;
case 'version':
console.log(edition)
break;
case 'help':
console.log(`
weather [command] <options>
today .............. show weather for today
tomorrow ............show weather for tomorrow
version ............ show package version
help ............... show help menu for a command
`)
}
}
集成天气 API 与交互优化
接入天气 API
截至目前,功能运行正常,但仅使用了手动输入的模拟数据(mock data),并未真正实现天气查询。要实现真实查询,必须借助第三方 API,这里选用心知天气提供的免费数据服务接口。
需先注册以获取 API Key 和 ID。发送请求时使用 axios 库(HTTP 客户端请求库)。
安装依赖:npm i -S axios 封装 http 模块
///ajax.js
const axios = require('axios')
module.exports = async (location) => {
const results = await axios({
method: 'get',
url: 'https://api.seniverse.com/v3/weather/daily.json',
params:{
key:'wq4aze9osbaiuneq',
language:'zh-Hans',
unit:'c',
location
}
})
return results.data
}
该模块接收地理位置信息,并返回今天、明天及后台的天气数据。
例如查询上海今天的天气:weather today --location shanghai
修改入口文件,添加 async标志 异步标志
const minimist = require('minimist')
const ajax = require('./ajax.js')
const edition = require('./package.json').version
module.exports = async ()=>{
const args = minimist(process.argv.slice(2));//前两个是编译器相关路径信息,可以忽略
let cmd = args._[0] || 'help';
if(args.v || args.version){
cmd = 'version';//查询版本优先!
}
let location = args.location || '北京';
let data = await ajax(location);
data = data.results[0];
let posotion= data.location;
let daily = data.daily;
switch(cmd){
case 'today':
//console.log('今天天气不错呢,暖心悦目!');
console.log(`${posotion.timezone_offset}时区,${posotion.name}天气,${posotion.country}`)
console.log(`今天${daily[0].date}:白天${daily[0].text_day}夜晚${daily[0].text_night}`)
break;
case 'tomorrow':
//console.log('明天下大雨,注意带雨伞!');
console.log(`${posotion.timezone_offset}时区,${posotion.name}天气,${posotion.country}`)
console.log(`今天${daily[1].date}:白天${daily[1].text_day}夜晚${daily[1].text_night}`)
break;
case 'version':
console.log(edition)
break;
case 'help':
console.log(`
weather [command] <options>
today .............. show weather for today
tomorrow ............show weather for tomorrow
version ............ show package version
help ............... show help menu for a command
`)
}
}
输入命令 weather today --location shanghai,此时可以看到查询结果:
完善细节,添加加载提示和默认指令处理
当前功能基本完成,后续需补充一些细节。首先是进度提示,以提升用户感知度,这里使用 ora 库。
其次,当用户输入未匹配的指令时,需提供引导信息,即默认的日志提示。
安装依赖 npm i -S ora
编写 loading 模块:
const ora = require('ora')
module.exports = ora()
// method start and stop will be use
修改入口文件
const minimist = require('minimist')
const ajax = require('./ajax.js')
const loading = require('./loading')
const edition = require('./package.json').version
module.exports = async ()=>{
const args = minimist(process.argv.slice(2));//前两个是编译器相关路径信息,可以忽略
let cmd = args._[0] || 'help';
if(args.v || args.version){
cmd = 'version';//查询版本优先!
}
let location = args.location || '北京';
loading.start();
let data = await ajax(location);
data = data.results[0];
let posotion= data.location;
let daily = data.daily;
switch(cmd){
case 'today':
//console.log('今天天气不错呢,暖心悦目!');
console.log(`${posotion.timezone_offset}时区,${posotion.name}天气,${posotion.country}`)
console.log(`今天${daily[0].date}:白天${daily[0].text_day}夜晚${daily[0].text_night}`)
loading.stop();
break;
case 'tomorrow':
//console.log('明天下大雨,注意带雨伞!');
console.log(`${posotion.timezone_offset}时区,${posotion.name}天气,${posotion.country}`)
console.log(`今天${daily[1].date}:白天${daily[1].text_day}夜晚${daily[1].text_night}`)
loading.stop();
break;
case 'version':
console.log(edition)
loading.stop();
break;
case 'help':
console.log(`
weather [command] <options>
today .............. show weather for today
tomorrow ............show weather for tomorrow
version ............ show package version
help ............... show help menu for a command
`)
loading.stop();
default:
console.log(`你输入的命令无效:${cmd}`)
loading.stop();
}
}
工具发布与全局使用
发布
发布至 npm 仓库后,可直接通过 npm i -g weather 全局安装我们发布的 CLI 工具,并在任意位置输入 weather 命令查询天气。
若不清楚发布流程,可参考我的另一篇文章《发布一款 npm 包》以加深理解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
怎么在本地运行JavaScript脚本:Node.js下载安装与环境配置教程
2026-11-05 09:02:33
JavaScript开发环境怎么搭建:Node.js安装与VS Code配置指南
2026-11-03 23:36:59
JavaScript零基础入门:环境搭建与第一个Hello World
2026-11-03 23:34:09
NW.js 是什么:基于 Chromium 和 Node.js 的桌面应用框架
2026-11-03 15:14:00
nvm、n 和官方安装包:哪种 Node.js 升级方式更适合你
2026-11-03 14:54:28
