首页
/ Deno 架构详解:从 CLI 到 V8 的五层技术栈与 Ops 扩展机制全解析

Deno 架构详解:从 CLI 到 V8 的五层技术栈与 Ops 扩展机制全解析

2026-09-06 21:28:06作者:殷蕙予

本文基于 Deno 仓库官方文档 doc/architecture.md 展开,系统讲解 Deno 由上至下的五层架构(cli → runtime → ext → libs → V8+Tokio)如何分层协作,并深入解读贯穿各层的 Ops 扩展机制、权限模型与 Worker 隔离模型。读完后,你将能够准确定位任意一个功能(从 CLI 子命令到原生能力)在代码库中的实现位置,理解"往 JS 里加一个原生 API"的完整链路,并知道做改动时应从哪个文件入手。

分层总览:每层只依赖其下的层

Deno 被构建为一个分层技术栈(stack of layers),每一层只依赖它下面的层。这一约束保证了系统的可测试性,也让底层能力可以脱离 deno 二进制被独立复用。官方给出的层次结构如下(自上而下):

+-----------------------------------------------------------+
|  cli/            the `deno` binary: subcommands, tooling   |
+-----------------------------------------------------------+
|  runtime/        deno_runtime: assembles the JS runtime    |
+-----------------------------------------------------------+
|  ext/*           extensions: native capabilities for JS    |
+-----------------------------------------------------------+
|  libs/*          deno_core + supporting crates (V8 bridge) |
+-----------------------------------------------------------+
|  V8 + Tokio      JavaScript engine and async runtime       |
+-----------------------------------------------------------+

这个分层对应到仓库目录一目了然:顶层 cli/ 是用户直接交互的二进制;runtime/ 组装 JS 运行时;ext/ 提供原生能力;libs/ 是 Rust 与 V8 之间的桥接层;最底层则是 V8 引擎与 Tokio 异步运行时。doc/codebase-map.md 提供了更细粒度的逐目录说明,doc/testing.md 则给出了各层的测试方式。

CLI 层(cli/):用户直接触碰的一切

cli/ 目录下的 deno crate 承载了用户能直接触碰的所有东西:命令行参数解析、全部子命令(runtestfmtlintcompilebundleinstallpublish 等)、包管理工具、LSP 语言服务器,以及把模块解析与运行时连接起来的模块加载器。

关键入口文件:

  • cli/main.rs — 进程入口与命令路由。该文件刻意保持极简,仅调用 deno::main(),真正的入口逻辑放在 cli/lib.rs 中。这样做的原因是官方注释中说明的:"We have a lib.rs and main.rs in order to be able to run tests without building a binary on the CI"——把逻辑放进库目标,CI 上跑测试就无需构建完整的二进制。
  • cli/args/flags.rs — 完整的 clap 标志与子命令定义。新增一个 flag 或子命令,从这里开始
  • cli/tools/ — 每个子命令一个模块:简单的如 cli/tools/fmt.rs,复杂的如 cli/tools/test/ 目录,以及 compile.rsbundle/lint/pm/(包管理)、publish/repl/serve.rs 等。
  • cli/module_loader.rs — 解析并加载模块,把 resolver 与模块图(module graph)桥接到运行时。

CLI 层是有意做重的:它引入了 TypeScript 类型检查、npm 与 JSR 解析、lockfile、bundler 等重资产。作为分层纪律的一部分,底层 crate 严禁反向依赖 CLI 层

cli/lib.rsmain() 实现还能看到 CLI 启动阶段的实际细节:进程启动后依次完成 panic hook 安装、日志初始化、文件描述符上限提升(util::unix::raise_fd_limit())、权限提示回调注册(deno_permissions::prompter::set_prompt_callbacks)、rustls 的 aws_lc_rs 默认 provider 安装,然后才进入参数处理。一个值得一提的实现细节是:当二进制通过名为 node 的符号链接被调用时,node_compat_shim::maybe_rewrite_node_arg0 会在启动最早期把 Node.js 风格的 CLI 参数翻译成 Deno 参数——这就是 Deno 能兼容 node script.js 调用方式的基础(见 cli/node_compat_shim.rs)。

运行时层(runtime/):组装"Den the runtime"

runtime/ 目录下的 deno_runtime crate 负责把 deno_core 加上一组精选扩展(extensions)组装成一个可用的 JavaScript 运行时。它是嵌入者(embedder)想要"Deno 这个运行时"但不想要"Deno 这个 CLI"时所用的那一层。

关键文件:

  • runtime/worker.rs — 构建主 worker:一个 V8 isolate、op 集合(op set)以及启动(bootstrap)序列。从源码结构看,该文件大量引用 deno_web 等扩展(如 deno_web::deno_web::lazy_init()、CSSStyleSheet 创建等),正是"把各扩展装配进运行时"的集中体现。
  • runtime/web_worker.rs — Web Worker 变体。
  • runtime/permissions/ — 权限模型,为每一个敏感 op(read、write、net、env、run、ffi、sys)设卡。权限检查在 Rust 侧的 op 边界完成,绝不在 JavaScript 中完成——这是 Deno 安全模型的核心设计。

扩展层(ext/):平台能力的真正所在地

ext/ 下的每个目录都是一个自包含的扩展:一个 Rust crate,定义了 ops(可从 JS 调用的原生函数),外加在其之上暴露更高层 API 的 JavaScript。平台能力实际就"住"在这里。按用途分组:

  • Web 平台ext/webext/fetchext/urlext/cryptoext/consoleext/webidlext/websocketext/webgpuext/canvas(以及 ext/imageext/broadcast_channelext/webstorage 等)。
  • 系统访问ext/fsext/netext/ioext/osext/processext/signalsext/tls
  • Deno 特有 APIext/kvext/cronext/cacheext/ffiext/napiext/bundle
  • Node 兼容ext/node(大部分 node:* 内建模块,含 Rust ops 与 JavaScript polyfills)、ext/node_cryptoext/node_sqlite

一个扩展的典型形态

每个扩展遵循三步结构:

  1. Rust 侧用 #[op2] 宏标注的函数执行特权操作,需要时携带权限检查;
  2. 一组带数字前缀的 JavaScript 模块(00_*.js01_*.js……,前缀决定加载顺序),构建公开 API 并通过 Deno.core.ops 调用 op;
  3. runtime/worker.rs(以及 CLI 的 snapshot 构建)中注册该扩展,使其成为组装后运行时的一部分。

以文件系统扩展为例,这条链路在源码中可以完整印证:

  • Rust 侧:ext/fs/ops.rs 中密集使用 #[op2]#[op2(fast, stack_trace)] 等宏定义 op;
  • JS 侧:ext/fs/30_fs.js 通过 const { ... } = core.ops; 解构拿到全部 op 的 JS 绑定,再在其上构建 Deno.readTextFile 等公开 API;
  • 注册侧:扩展在 libs/core 中通过 deno_core::extension! 宏(见 libs/core/benches/ops/async.rs 等处的用法)声明为扩展单元,最终由 runtime/worker.rs 装配。

数字前缀(00_01_20_30_……)不仅是命名惯例,更是模块加载顺序的控制机制:例如 ext/fetch/ 下的 20_headers.js21_formdata.js22_body.js23_request.js23_response.js26_fetch.js,反映了 Headers、FormData、Body 到 Request/Response 的依赖顺序。

官方给出的开发准则很明确:新增原生功能时,在对应的 ext/<name>/ crate 中添加 op,不要去 runtime 或 CLI 层里找地方塞

核心层(libs/):Rust 与 V8 之间的桥

libs/ 目录容纳 deno_core 及从原独立 deno_core 仓库并入的配套 crate。这一层是 Rust 与 V8 的桥梁,拥有 op 基础设施、模块加载器 trait、快照(snapshotting)机制、JsRuntime 事件循环,以及 serde_v8 序列化层。核心成员:

  • libs/coredeno_core 本体:JsRuntime、op 注册、模块映射(module map)、inspector 集成。其内部结构包括 op 注册与指标(libs/core/ops.rslibs/core/ops_metrics.rs)、事件循环(libs/core/event_loop.rs)、快照格式(libs/core/snapshot_format.rs)、模块系统(libs/core/modules/)等。
  • libs/ops#[op2] 过程宏(proc-macro),负责生成 Rust/V8 之间的胶水代码。
  • libs/serde_v8 — Rust 类型与 V8 值之间近似零拷贝的序列化。
  • libs/resolverlibs/node_resolverlibs/npmlibs/npm_installerlibs/package_jsonlibs/lockfilelibs/configlibs/npmrc — CLI 组合使用的解析与包管理积木块(此外还有 libs/npm_cachelibs/cache_dirlibs/cli_parserlibs/esziplibs/http_h1 等配套 crate)。

这些 crate 刻意保持无 CLI 关切,以便可以独立单元测试、被其他工具复用。

横切概念:五个贯穿全栈的核心抽象

无论在哪一层工作,都要理解以下五个贯穿整个技术栈的概念:

  • Ops 是 JavaScript 触及原生代码的唯一通道。op 就是暴露给 JS 的 Rust 函数:同步 op 立即返回,异步 op 返回一个 future,在事件循环上解析。
  • Extensions 把 op 与其 JavaScript 打包在一起,是组装一个运行时的基本单元。
  • Workers 是隔离的 JavaScript 执行上下文(主 worker 与 Web Worker),各自拥有独立的 V8 isolate。
  • Resources 是受管理的句柄(打开的文件、socket、reader),由 deno_core 追踪,以整数 id 跨 Rust/JS 边界传递。
  • Permissions 在 op 边界处由 Rust 强制。未被授予的能力会让 op 在做任何实际工作之前就报错。

改动指引:想做什么,从哪里入手

官方维护了一张"任务 → 起始位置"对照表,是日常开发最直接的导航:

你想做…… 从这里开始
新增或修改 CLI flag/子命令 cli/args/flags.rscli/tools/
给 JS 新增原生能力 ext/<name>/(op + JS)
修改运行时的组装方式 runtime/worker.rs
触碰 Rust/V8 桥或 op 宏 libs/corelibs/ops
修改模块/npm/JSR 解析 libs/resolverlibs/npm、CLI

结语

Deno 的架构纪律可以浓缩为一句话:上层重、下层净,依赖只向下。CLI 层承担全部用户交互与重型工具链,runtime 层负责组装,ext 层按"一个 crate + 数字前缀 JS"的统一形态扩展平台能力,libs 层以 deno_core#[op2] 宏和 serde_v8 提供与 V8 打交道的稳定底座。想进一步深入,建议按 doc/codebase-map.md 推荐的顺序阅读 cli/main.rscli/args/flags.rsruntime/worker.rsruntime/permissions/cli/module_loader.rs,并参考 doc/testing.md 了解如何对每一层运行测试。

登录后查看全文
热门项目推荐
相关项目推荐