要点
本篇是 Deno 的条目式速查,按用途分五组:CLI 命令、模块标识符、运行时 API、Web 标准 API、deno.json 配置键;文末有全量速查表,可只搜表定位条目。版本基线为 Deno 2.5.x(2025-09-10 发布的 LTS 线),仅在此版本存在的特性单独标注;权限标志的完整语义不在本篇重复,见Deno 权限模型详解。对照 Node 工具链使用时,模块与包概念的差异可先看站内Node.js 模块与 ESM。
CLI 命令组
单文件可执行内置全部工具链,这是 Deno 与”npm 装 Prettier/ESLint/Vitest”最直观的差异。速查如下:
| 命令 | 一句话用途 | 有什么坑 |
|---|---|---|
| deno run [flags] file.ts | 跑一个脚本或 URL/npm 包 | 没授的权限默认拒绝;跑 npm 包用 deno run npm:vite 这类写法 |
| deno add npm:pkg / jsr:@scope/pkg | 装依赖并登记 | 项目有 package.json 就写进它,没有才写 deno.json 的 imports |
| deno install | 按配置装全部依赖 | 与”全局安装”共用命令名:带参数加 -g 才是装全局可执行(npm i -g 等价) |
| deno uninstall | 移除依赖 | 全局卸载要 -g,和 add/install 对称 |
| deno task 名字 | 跑 deno.json 里的任务 | 任务字符串里同样要写权限标志,或用 2.5 的 permission sets 加 -P |
| deno fmt | 格式化 | 规则与 Prettier 不完全一致,存量仓库首次跑 diff 会很大 |
| deno lint | 静态检查 | 默认推荐规则集;2.5 起新仓库默认含 no-unversioned-import |
| deno test | 跑测试 | 测试进程的权限独立于 run,见下方条目 |
| deno bench | 跑基准 | Deno.bench 注册的用例才被识别,别和 test 混写一个文件 |
| deno compile | 打出单文件可执行 | 产物内嵌运行时,体积不会小;权限在编译期随产物固化 |
| deno bundle | 打出单文件 JS bundle | 2.4(2025-07)才回归的命令;HTML 入口与 Deno.bundle() API 仍是实验特性 |
| deno publish | 发布到 jsr.io | 公开 API 必须有显式类型标注(no-slow-types 规则),否则发不出去 |
| deno info / deno doc | 看模块依赖图 / 看 API 文档 | info 也能查远程模块的缓存位置 |
| deno upgrade [lts] | 自升级 | 要钉在长期支持线用 deno upgrade lts |
| deno repl | 交互式解释器 | REPL 默认无权限,测文件操作要加对应标志 |
日常用得最多、也最容易踩语义的五个,单独展开:
deno run:入口,也是权限的入口
deno run --allow-net=127.0.0.1:8000 server.ts # 跑本地文件
deno run -A npm:vite dev # 直接跑 npm 包,不必先装
deno run jsr:@std/path@1/examples/hello.ts # 直接跑 jsr 模块(示例示意,以 jsr.io 页面给的命令为准)
一句话语义:一切执行的起点;权限标志加在 run 后面,而不是写在代码里。
⚠️ 常见坑:用 deno run npm:包名 跑的是”包的默认可执行入口”,不是包里任意脚本;要指定 bin 得用 npm:包名/子路径 写法,路径以该包 package.json 的 bin 字段为准。
deno add 与 deno install:一个命令名,两件事
deno add npm:express # 装并登记(有 package.json 写它,没有写 deno.json imports)
deno install # 按现有配置装全部依赖,等价 npm install
deno install -g npm:xlsx # 全局装可执行,等价 npm install -g
一句话语义:add 是”加一条依赖”,install 是”按清单装齐”或”装全局工具”。
⚠️ 常见坑:从 Node 迁移过来的肌肉记忆会把 deno install 包名 当 npm install 用——它实际是全局安装,会装到全局 bin;项目内加依赖一律用 deno add。
deno task:任务运行器
{
"tasks": {
"dev": "deno run -P=default server.ts",
"test": "deno test -P"
}
}
一句话语义:替代 npm scripts,任务定义在 deno.json 的 tasks 键,跨平台执行不依赖 shell 差异。
⚠️ 常见坑:任务里调用 deno 时权限不会自动继承——deno task start 里如果写的是裸 deno run server.ts,跑起来就是无权限进程;把权限写进任务字符串,或 2.5 起用 permission sets 加 -P 引用。
deno test:内置测试器
import { assertEquals } from "@std/assert";
Deno.test("过滤含关键词的标题", () => {
const hits = filterByKeywords(["deno 2.5 发布", "无关新闻"], ["deno"]);
assertEquals(hits, ["deno 2.5 发布"]);
});
// 2.5 新增生命周期钩子:夹具一次搭建、每例重置、统一清理
Deno.test.beforeEach(() => Deno.mkdir("./tmp-fixtures", { recursive: true }));
Deno.test.afterEach(async () => await Deno.remove("./tmp-fixtures", { recursive: true }));
一句话语义:Deno.test 注册用例,断言从 @std/assert 导入;文件命名约定 *_test.ts 或 *.test.ts。
⚠️ 常见坑:测试进程的权限与 run 完全独立——用例里读文件,deno test 也要授权;2.5 起可以把权限嵌在配置的 test 键下或直接 -P 引用集合,否则报错的是测试进程而不是被测代码。
deno compile:单文件分发
deno compile --allow-read=./data -o pull pull.ts # 权限随产物固化
./pull # 目标机不需要装 Deno
一句话语义:把脚本连同运行时打成一个可执行文件,适合分发 CLI 小工具。
⚠️ 常见坑:权限是编译期烧进去的——产物行为由 compile 时的标志决定,运行时不再弹提示;漏授的权限到目标机上才会暴露,编译前先在本地按同样标志完整跑一遍。
模块标识符组
Deno 2 起,一个项目里四种前缀可以共存,这是”住进 Node 生态”的语法层表现:
| 前缀 | 一句话用途 | 有什么坑 |
|---|---|---|
| npm:pkg | 引 npm 生态的包 | 建议带版本;2.5 默认 lint 规则 no-unversioned-import 会提醒 |
| node:fs 等 | 引 Node 内置模块 | 前缀必写,裸 import “fs” 不行;多数常用模块已兼容,边角以官方兼容列表为准 |
| jsr:@scope/pkg | 引 JSR 注册表的 TS 原生包 | 发布物要求显式类型;引错了版本 jsr.io 页面会给出正确命令 |
| 裸名 bare | imports 映射的短名 | 必须在 deno.json 的 imports 键登记,否则解析失败 |
import { serve } from "https://deno.land/std@0.224.0/http/server.ts"; // URL 直引(老写法,仍可用)
import express from "npm:express@5"; // npm 生态
import { DatabaseSync } from "node:sqlite"; // Node 内置(2.2 起可用)
import { join } from "@std/path"; // 走 imports 映射的裸名
⚠️ 常见坑:动态 import 一个非字面量路径(await import(specifier))走运行时权限检查,需要 –allow-import 且目标在信任名单内——静态 import 不需要。把”拼接出模块路径”当配置化手段用,权限上会多出一个口子。
运行时 API 组
Deno.env:环境变量
const token = Deno.env.get("WEBHOOK_URL"); // 未授权时抛 NotCapable
Deno.env.set("RUN_ID", "42"); // 写同样要权限
一句话语义:替代 process.env 的受控入口,get/set/has/toObject 四件套。
⚠️ 常见坑:作用域按变量名单个放行(–allow-env=WEBHOOK_URL),整类放行写成 –allow-env 即可但等于全交;变量名写错不报错,get 只是返回 undefined——先 Deno.env.has 探测。
Deno.args 与 import.meta:入口信息
const target = Deno.args[0] ?? "./data"; // 命令行参数,替代 process.argv 的语义化子集
console.log(import.meta.dirname); // 当前模块所在目录,替代 __dirname
console.log(import.meta.main); // 本模块是否是入口,替代 require.main 判断
⚠️ 常见坑:Deno.args 不含 node 风格的可执行与脚本路径两个前缀,按 process.argv 的下标习惯取值会拿到 undefined。
Deno.readTextFile / writeTextFile:文件读写
const raw = await Deno.readTextFile("./data/items.json");
await Deno.writeTextFile("./data/last.json", raw); // 默认覆盖写
await Deno.writeTextFile("./data/log.txt", "一次运行\n", { append: true }); // 追加写
一句话语义:最常用的两个文本 IO;全部异步,没有同步版本。
⚠️ 常见坑:默认是”存在即截断重写”,想追加必须显式 append;权限按路径作用域匹配(–allow-read=./data 放行其子树),写到别处照样 NotCapable。
Deno.serve:HTTP 服务
Deno.serve({ port: 8000 }, (req) => {
const url = new URL(req.url);
if (url.pathname === "/health") return new Response("ok");
return new Response("not found", { status: 404 });
}); // 运行需要 --allow-net
一句话语义:一行起一个 HTTP 服务,替代 http.createServer;返回的 server 可用于优雅关闭。
⚠️ 常见坑:port 省略时默认 8000 不是 80——”改了环境变量没生效”多半是配置没传进来;作用域授权时监听地址也要落在 –allow-net 允许的主机里。
Deno.Command:子进程
const cmd = new Deno.Command("git", { args: ["status", "--short"] });
const { code, stdout } = await cmd.output(); // output() 收集完整输出
console.log(code, new TextDecoder().decode(stdout));
一句话语义:替代 Deno.run(已废弃)与 child_process 的主路径;流式消费用 spawn()。
⚠️ 常见坑:–allow-run 必须白名单到具体可执行(–allow-run=git);子进程拥有操作系统全量权限,是沙箱的洞——能用库解决的事不要 shell 出去。
Deno.cron:定时任务
Deno.cron("每 5 分钟", "*/5 * * * *", () => {
console.log("UTC 时间每 5 分钟执行一次");
});
一句话语义:标准 5 字段 cron 表达式(UTC)注册周期任务,顶层调用。
⚠️ 常见坑:截至 2.5 仍是实验 API,本地跑要 –unstable-cron 或 deno.json 的 unstable 数组加 “cron”;进程活着才会触发(长驻进程模型),脚本跑完就退的场景用系统 crontab 或 Deno Deploy 的托管 cron;时间一律 UTC,按北京时间排凌晨任务要自己换算。
Deno.KV:键值存储
const kv = await Deno.openKv("./data/app.db");
await kv.set(["visits", "2025-10-20"], 7);
const v = (await kv.get(["visits", "2025-10-20"])).value;
一句话语义:内置键值库,本地落到指定文件,Deno Deploy 上是托管服务,同一套 API。
⚠️ 常见坑:截至 2.5 本地使用需 –unstable-kv,API 仍可能变化,核心业务慎用;需要 SQL 约束(唯一键、事务回滚)的场景,node:sqlite 或 PG 客户端更合适。
Deno.permissions:权限协商
query/request/revoke 三件套与 NotCapable 错误的完整用法见权限模型详解,此处不重复。
Deno.watchFs:文件监听
for await (const ev of Deno.watchFs("./data")) {
console.log(ev.kind, ev.paths); // kind: any / accessed / create / modify / remove
}
⚠️ 常见坑:编辑器保存一次可能触发多个事件(事件会聚合并重复投递),直接在里面做重活会抖——按 paths 去重加防抖再处理。
Web 标准 API 速查
Deno 的网络与文本层直接用 Web 标准,Node 里要靠 polyfill 的东西这里原生就有:
| API | 一句话用途 | 有什么坑 |
|---|---|---|
| fetch / Response | HTTP 客户端 | 受 –allow-net 管辖;默认无超时,配 AbortSignal.timeout |
| URL / URLSearchParams | URL 解析与构造 | 全局可用,无需 import |
| TextEncoder / TextDecoder | UTF-8 与字节互转 | encoder 全局单例风格使用,不用 new 多份 |
| AbortSignal.timeout(ms) | 给 fetch/等待加超时 | 到点抛 TimeoutError,要 catch 分类处理 |
| crypto.subtle | 哈希、签名、随机数 | 只在安全上下文(HTTPS/localhost)可用 subtle;摘要计算用 crypto.subtle.digest |
| structuredClone | 深拷贝 | 函数、DOM 类对象克隆不了 |
| setTimeout / setInterval | 定时器 | Deno 返回 number;Node 返回 Timer 对象——混跑 node 兼容代码注意(2.5 提供 DENO_COMPAT=1 换 Node 语义) |
| Web Streams | 流式读写 | 与 Node 流是两套概念,混用要转换;概念对照见站内 Node.js 流与 Worker 一文 |
deno.json 配置键速查
| 键 | 一句话用途 | 有什么坑 |
|---|---|---|
| tasks | 任务定义 | 权限不会自动继承,见 CLI 组 |
| imports | 裸名到 URL/包的映射 | 项目有 package.json 时依赖登记走那边,两处别混 |
| compilerOptions | TS 编译选项 | 只支持一个子集,不认的全部 tsconfig 字段会告警 |
| permissions(2.5+) | 命名权限集与 default 集合 | 要在 deno run/test 时用 -P 显式引用才生效 |
| test / bench / compile | 各自嵌套 permissions | 2.5 起:声明了 test 权限却不带 -P 跑 deno test 会直接报错提示 |
| unstable | 开实验特性([“cron”]、[“kv”] 等) | 实验 API 可能变,生产慎用 |
| fmt / lint | 格式化与检查配置 | include/exclude 写错路径不会报错,只是规则没生效 |
| lock | 锁定文件开关与路径 | CI 里配合 –frozen 才能保证”锁了就不可变” |
| nodeModulesDir | node_modules 策略 | 有 package.json 的项目默认建 node_modules;纯 deno.json 项目默认走全局缓存 |
全量速查表
| 条目 | 一句话用途 | 有什么坑 |
|---|---|---|
| deno run | 执行入口 + 权限入口 | 权限不写就是拒绝 |
| deno add | 加一条依赖 | 有 package.json 时登记到那边 |
| deno install / -g | 装依赖 / 装全局工具 | 带包名即全局,别当 npm install 用 |
| deno task | 任务运行 | 任务内权限要自己带 |
| deno test | 测试 | 测试权限独立配置 |
| deno bench | 基准 | 用例要用 Deno.bench 注册 |
| deno compile | 单文件可执行 | 权限编译期固化 |
| deno bundle | 单文件 bundle | 2.4 回归;HTML 入口实验性 |
| deno publish | 发 JSR | 公开 API 必须显式类型 |
| deno upgrade lts | 升级到 LTS 线 | 不带 lts 跟最新稳定线 |
| npm: / node: / jsr: | 三种模块前缀 | 带版本;node: 前缀必写 |
| Deno.env | 环境变量 | 按变量名授权 |
| Deno.args / import.meta | 参数与模块信息 | 别按 process.argv 下标取 |
| Deno.readTextFile 等 | 文本 IO | 默认覆盖,追加要 append |
| Deno.serve | HTTP 服务 | 默认端口 8000 |
| Deno.Command | 子进程 | –allow-run 白名单;沙箱的洞 |
| Deno.cron | 周期任务 | 2.5 仍实验;UTC;长驻才触发 |
| Deno.KV | 键值存储 | 2.5 仍实验(–unstable-kv) |
| Deno.permissions | 权限协商 | 见权限模型详解篇 |
| Deno.watchFs | 文件监听 | 事件重复,要防抖 |
| fetch + AbortSignal.timeout | 带超时的请求 | fetch 本身无超时 |
延伸阅读
权限标志的完整语义与威胁模型见Deno 权限模型详解;这些 API 在真实工程里怎么组合,见实战篇用 Deno 写一个定时抓取脚本;与 Node 工具链逐项对照的迁移视角见Deno 学习路线;运行时定位与选型见开山篇Deno 2 入门。
版本核实(以官方文档为准):本篇基线为 Deno 2.5.x(2025-09-10,LTS,内置 V8 14.0 与 TypeScript 5.9.2);deno bundle 回归自 2.4(2025-07-02,HTML 入口与 Deno.bundle() 为实验);node:sqlite 兼容自 2.2;Deno.test 生命周期钩子(beforeAll/beforeEach/afterAll/afterEach)与配置文件 permission sets、DENO_AUDIT_PERMISSIONS 为 2.5 新增;Deno.cron 与 Deno.KV 截至 2.5 仍为实验 API,需 –unstable-cron / –unstable-kv;no-unversioned-import 为 2.5 新默认 lint 规则;Deno.serve 默认端口 8000。命令行为以 docs.deno.com 当前文档为准。