本文档解释了 Deno 如何处理命令行界面 (CLI) 的命令,详细介绍了从初始命令解析到执行特定子命令(如 run、test 或 fmt)的执行流程。
有关命令处理完成后模块加载的信息,请参阅 模块加载和解析。
Deno 的命令处理始于用户通过命令和参数调用 CLI。该过程包括通过 flags_from_vec 解析命令行参数,解析配置,通过 run_subcommand 分派到相应的子命令处理程序,并处理任何产生的错误。
来源: cli/main.rs453-513 cli/main.rs515-555 cli/main.rs111-368
当 Deno 启动时,它会收集命令行参数,并将它们传递给标志解析系统。这些参数被转换为一个结构化的 Flags 对象,其中包含已识别的子命令及其特定选项。
标志解析系统同时处理全局标志(如 --log-level 或 --unstable-*)和子命令特定标志(如 deno run 的 --watch)。Flags 结构包含一个 DenoSubcommand 枚举变体,该变体决定将调用哪个命令处理程序。
来源: cli/main.rs515-555 cli/args/flags.rs647-691 cli/args/flags.rs468-502
Deno 支持许多子命令,每个子命令都由 DenoSubcommand 枚举中的一个变体表示。解析参数后,Deno 识别要运行的子命令,并通过 run_subcommand 将执行分派到相应的处理程序。
每个子命令都通过 spawn_subcommand 函数在自己的异步任务中执行,该函数将命令处理程序包装在 deno_core::unsync::spawn 中,并使用 .boxed_local() 来防止在调试模式下的 Windows 上发生堆栈溢出。
来源: cli/main.rs102-109 cli/main.rs111-368 cli/args/flags.rs468-502
对于大多数需要执行 JavaScript/TypeScript 代码的子命令(如 run、test 或 eval),Deno 会创建一个 worker 环境。这包括使用 CliFactory 创建服务,然后使用 CliMainWorkerFactory 创建一个 CliMainWorker。
CliMainWorker 包装了一个 LibMainWorker,而 LibMainWorker 又包装了运行时 MainWorker。这种分层方法允许在利用共享库和运行时组件的同时,实现 CLI 特定的功能。
来源: cli/factory.rs314-353 cli/worker.rs314-324 cli/worker.rs68-285
deno run让我们来看一下当用户运行 deno run script.ts 这样的命令时会发生什么。
Run 子命令创建了一个 Flags 对象。run_subcommand 函数将执行分派到 Run 子命令的相应处理程序。CliFactory 来创建服务和 Worker。deno run 的详细执行流程来源: cli/main.rs225-294 cli/worker.rs84-160 cli/factory.rs500-567
Deno 为命令执行提供了一个强大的错误处理机制。如果命令失败,错误会在退出并返回适当的退出代码之前进行格式化并显示给用户。
对于 JavaScript 错误,Deno 提供详细的堆栈跟踪,以帮助开发人员识别和修复其代码中的问题。
来源: cli/main.rs404-422 runtime/fmt_errors.rs
Deno CLI 的入口点是 cli/main.rs 中的 main 函数。它负责设置环境、处理 panic hook、处理参数并启动相应的子命令。
main() → resolve_flags_and_init() → run_subcommand() → [specific subcommand handler]
run_subcommand 函数是一个中心分派点,它根据识别出的子命令将执行路由到相应的处理程序。
来源: cli/main.rs432-465 cli/main.rs109-350
Deno 支持各种子命令,每个子命令都有其特定的行为和标志。 cli/args/flags.rs 中的 DenoSubcommand 枚举定义了所有支持的子命令。
| 子命令 | 描述 | 处理程序模块 |
|---|---|---|
run | 执行 JavaScript/TypeScript 程序 | tools::run |
test | 运行测试 | tools::test |
fmt | 格式化源文件 | tools::fmt |
lint | Lint 源文件 | tools::lint |
compile | 将脚本编译成独立的自包含可执行文件 | tools::compile |
repl | 打开交互式 Read-Eval-Print-Loop | tools::repl |
install | 将脚本安装为可执行文件 | tools::installer |
uninstall | 卸载先前安装的脚本 | tools::installer |
cache | 缓存依赖项 | tools::installer |
info | 显示有关缓存的信息或与源文件相关的信息 | tools::info |
eval | 评估代码片段 | tools::run |
task | 运行配置文件中定义的任务 | tools::task |
add | 向 deno.json 添加依赖项 | tools::pm |
remove | 从 deno.json 中移除依赖项 | tools::pm |
outdated | 检查过期的依赖项 | tools::pm |
publish | 将包发布到 JSR | tools::publish |
来源: cli/args/flags.rs453-486 cli/main.rs109-350
在命令执行过程中,Deno 向 JavaScript 环境分派各种生命周期事件,以通知其执行状态。
load - 加载主模块后分派。beforeunload - 在程序退出前分派,允许取消。unload - 程序即将退出时分派。process.beforeexit - Node.js 兼容事件,在程序退出前触发。process.exit - Node.js 兼容事件,在程序退出时触发。来源: cli/worker.rs84-160 runtime/worker.rs976-1062
Deno 的命令处理系统是一个结构良好的管道,它处理用户输入,分派到相应的处理程序,创建隔离的执行环境,并管理脚本执行的生命周期。通过了解这个系统,开发人员可以更好地利用 Deno 的功能并为其代码库做出贡献。