func 负责命令模型、类型化输入和依赖注入,不限制 CLI 的存储、呈现与交互方式。下面按常见需求整理 Node.js 内置模块和生态功能包,同时标注各自适合的场景,方便在默认推荐和其他可选方案之间比较。
如何阅读对比数据
下载量来自 npm 2026-07-31 至 2026-08-06 的统计,并使用 M(百万)和 K(千)缩写。它可以反映生态采用程度,但其中包含自动化安装和传递依赖安装,不能等同于真实用户数量,也不代表质量排名。
Bundle 数据是在固定示例中使用 esbuild 打包为经过压缩和 Tree Shaking 的单文件 ESM CLI 后,相对基线增加的体积,并四舍五入到整数 KiB。体积只是选型标准之一,不应作为唯一依据。维护活跃度、Node.js 版本要求、ESM/CJS 兼容性、文档质量、API 设计、无障碍支持、测试体验,以及功能包是否符合 CLI 的交互模型都同样重要。对发布体积敏感时,还应使用项目的真实入口重新测量。
本地数据库
单个 CLI 安装需要保存结构化数据时,默认推荐 Node.js 内置的 node:sqlite。func 要求 Node.js 24.15 或更高版本,因此无需额外安装数据库功能包、原生扩展或独立服务。同步的 DatabaseSync API 适合执行时间短的命令、本地索引、缓存、历史记录,以及使用 :memory: 的测试。
import { Injectable } from 'func'
import type { OnDispose } from 'func'
import { DatabaseSync } from 'node:sqlite'
type Project = Readonly<{ path: string }>
@Injectable()
export class DatabaseService implements OnDispose {
private readonly database = new DatabaseSync('data.sqlite', {
timeout: 5_000,
})
private readonly findProjectStatement = this.database.prepare(
'SELECT path FROM projects WHERE name = ?',
)
findProject(name: string) {
return this.findProjectStatement.get(name) as Project | undefined
}
onDispose() {
this.database.close()
}
}在所属 Module 的 providers 中注册 DatabaseService,再通过构造函数注入需要它的 Command。func 只会在选中的 Command 需要时创建这个 service,并在本次调用结束后执行 onDispose()。
来自用户的值应通过 prepared statement 绑定,并保持事务简短。多个本地进程可能访问同一数据库时,可以考虑启用 WAL,但不要把 WAL 数据库放在网络文件系统上。由于每个 DatabaseSync 操作都会阻塞当前 JavaScript 线程,长时间查询、高并发写入或跨主机共享数据应改用 Worker,或者外部数据库及其驱动。
文字颜色与样式
Node.js 内置的 util.styleText 无需安装依赖即可提供基础 ANSI 样式。需要统一 API、更丰富的颜色或更广的模块兼容性时,可以选择下面的第三方库。
| 功能包 | 最近一周下载量 | 适合场景 | 代表性 Bundle 增量 |
|---|---|---|---|
picocolors | ≈218M | 需要常用颜色和强调样式的小型 ESM/CJS API;普通输出的默认第三方选择 | 2 KiB |
ansis | ≈44.5M | 同时需要 ESM/CJS、HEX/RGB、模板字符串和颜色自动降级 | 4 KiB |
chalk | ≈486M | 更看重成熟的链式 API、丰富颜色能力和广泛的生态认知 | 8 KiB |
kleur | ≈90.7M | 需要紧凑的链式 ESM/CJS API,或已有项目已经使用它 | 2 KiB |
新的 CLI 如果只需要常用颜色,可以从 picocolors 开始。既要高级颜色又要兼顾 ESM/CJS 时选择 ansis;更看重成熟 API 和现有集成时选择 chalk。
Prompt、Spinner 与任务流
| 功能包 | 最近一周下载量 | 适合场景 | 代表性 Bundle 增量 |
|---|---|---|---|
@clack/prompts | ≈18.0M | 希望 Prompt、日志和 Spinner 风格统一的项目创建器与配置向导 | 17 KiB |
@inquirer/prompts | ≈34.6M | 需要更多输入类型、模块化导入或自定义 Prompt | 28 KiB |
listr2 | ≈43.3M | 包含嵌套、并行、跳过或动态输出的多任务流程 | 79 KiB |
ora | ≈83.5M | 需要明确成功、警告和失败状态的单个或少量异步操作 | 58 KiB |
安装或配置向导可以优先使用 @clack/prompts;输入类型和扩展能力是主要要求时选择 @inquirer/prompts。ora 适合独立操作,多个任务需要同时保留并分别展示状态时,listr2 更合适。
表格、进度与重点信息
| 功能包 | 最近一周下载量 | 适合场景 | 代表性 Bundle 增量 |
|---|---|---|---|
cli-table3 | ≈32.1M | 需要 ANSI 感知的对齐、换行、跨行或跨列表格 | 34 KiB |
cli-progress | ≈10.1M | 任务具有可测量总量,需要单个或多个进度条 | 24 KiB |
boxen | ≈27.7M | 带边框的通知、摘要和少量需要突出显示的信息 | 49 KiB |
log-update | ≈43.9M | 需要原地刷新自定义多行输出的底层能力 | 34 KiB |
报告型输出通常选择 cli-table3,能够用数字表示完成度的任务更适合 cli-progress。boxen 用于强调信息,不适合作为布局系统;现成 Spinner 或进度渲染器无法满足要求时,再使用 log-update 自行控制刷新。
完整终端界面
需要键盘导航、焦点管理、持续存在的多区域布局或全屏更新时,可以考虑 TUI 框架。只需要表格、Prompt 或单个 Spinner 时没有必要引入这一层。
| 功能包 | 最近一周下载量 | 适合场景 | 代表性 Bundle 增量 |
|---|---|---|---|
ink | ≈5.7M | 希望使用组件、状态、Flexbox 风格布局和组件测试的 React 团队 | 362 KiB |
terminal-kit | ≈202K | 需要命令式键鼠、屏幕缓冲区、绘图和图片能力 | 无可靠单文件结果 |
blessed | ≈1.4M | 维护已经基于类 DOM Widget API 构建的终端应用 | 264 KiB |
新的 React 终端应用可以优先考虑 Ink。Terminal Kit 提供了更广的底层终端能力,但动态资源会增加单文件发布的处理成本。Blessed 对已有应用仍有价值,新项目采用前应重点评估维护状态和兼容性。
知名项目选用
下面的项目展示了这些库在不同交互复杂度下的实际使用情况。它们可以作为实现参考,但知名项目的选择不等于对所有场景的推荐。
| 功能包 | 采用项目 | 资料 |
|---|---|---|
@clack/prompts | Vite 的 create-vite、OpenClaw、create-t3-app 和 OpenCode | Vite 源码、OpenClaw 依赖 |
ink | Claude Code、Gemini CLI、GitHub Copilot CLI、Cloudflare Wrangler、Prisma、Shopify CLI 和 Canva CLI | Ink 官方项目展示 |
最小的调用级接入方式见交互式应用。