跳转到内容

Deno — 安全优先的 TypeScript/JavaScript 运行时

待复核

Deno 是一个把安全、标准兼容和 TypeScript 支持放在一起的运行时。

日常类比:你在厨房做饭,Deno 像默认把刀叉收起来并贴上警示贴, 你必须明确告诉它“这个工具能用到哪”。

它的目标不是“取代 Node”,而是把很多默认行为改成更清晰可控。 在 Deno 中,权限模型是显式开启的:网络、文件、环境变量都可以被限制。

  • 默认安全边界把“脚本能做什么”讲清楚,尤其适合多项目团队。
  • 官方 TypeScript 支持让脚本和服务端代码协作更省心。
  • 兼容 Web 标准 API 可以减少在浏览器与服务端之间来回转换心智。
  • Deno 2 开始认真补齐 npm / Node 兼容,让“安全默认值”和“现实生态”能同时谈。

很多项目最早采用 Node,不是因为它坏,而是因为历史惯性。 Deno 更像一次“默认行为重塑”。

  1. 运行时内建 TypeScript
  • 你不再依赖额外构建器链去跑 .ts 文件(在标准场景下)。
  • 类型检查与运行机制更早被纳入默认流程。
  • 对初学者有好处:更少“工具链魔法”,更高可预期。
  • 类比:像买来就装好尺子的工作台,不用先搭一套测量工具才能开工。
  1. 权限模型(Permissions)
  • 所有潜在危险能力都可通过 --allow-net--allow-read 等显式授权。
  • 这对安全审计很友好,日志和部署文档也更容易写。
  • 在 CI 或生产里,权限白名单比“默认信任”更适合长期维护。
  • 类比:像门禁卡,员工默认进不了仓库;需要仓库权限时才给那一扇门。
  1. 标准模块 URL 导入
  • 你可以直接从 URL 导入模块,减少传统 package-lock 的一部分依赖压力。
  • 但这也要求你管理 URL 漂移与缓存策略。
  • 在内部系统里,企业通常会加 registry 或锁文件。
  • 类比:像从网上打印菜谱做饭,方便,但必须确认网址、版本和备份。
import { serve } from 'https://deno.land/std@0.224.0/http/server.ts'
serve((req) => {
const url = new URL(req.url)
return new Response(`你访问了 ${url.pathname}`)
}, { port: 8080 })
  • 这是理解标准 API 的最好起点:不额外引入框架。
  • 把权限限制和 CORS 放在同一入口,安全边界最清晰。
  • 第 1 行从标准库拿 serve,第 3 行把请求 URL 解析出来。
  • 真正运行时要加 --allow-net=0.0.0.0:8080 或指定域名,否则网络监听会被权限系统拦住。
const text = await Deno.readTextFile('./data.csv')
console.log(text.slice(0, 120))
  • 运行时要带 --allow-read=./data.csv 才能通过。
  • 它让数据处理脚本的权限语义在命令行里一眼可见。
  • 如果脚本后来要写结果文件,再单独加 --allow-write=./out.csv,不要直接给整个目录读写。
Terminal window
deno run --allow-net=api.internal.example.com scheduler.ts
  • 与 cron/CI 联动时,优先把入口命令写进 deno task,让同事不用记参数。
  • --allow-net=api.internal.example.com 只允许访问这个内部 API,脚本碰别的域名会直接失败。
  • 避免“明天同一 URL 导入变了版本”导致环境漂移:提交 deno.lock,并在 CI 里用锁文件校验。
  1. 把 URL 导入当永久不变:第三方链接变更会导致构建意外崩,生产项目要锁版本并缓存依赖。
  2. 忘记权限收紧:本地调试常用 -A,上线还这样跑就等于关掉 Deno 的最大优势。
  3. 把 npm 兼容当万能:有些包默认读取 process.env、写临时目录或依赖原生扩展,迁移时要逐个验证。
  4. 生产部署忽略冷启动:边缘函数或短任务要提前测试依赖加载时间,必要时 bundle 成单文件。
  5. Deno 版本混用:1.x 与 2.x 的 npm 兼容、配置默认值不同,团队要固定工具链版本。

适用

  • 1-20 人维护的内部服务、脚本化平台、边缘函数项目。
  • TypeScript 原生体验优先,且愿意接受 Deno 约束的工程。
  • 需要清晰权限边界的安全敏感服务,例如只读文件、只访问单个 API 的自动化脚本。
  • 新项目或边缘项目,依赖包数量少于几十个,迁移成本可控。

不适用

  • 现有项目和大量传统 Node 专属依赖深度绑定,尤其依赖 native addon。
  • 对生态成熟度和文档习惯性强依赖的超大组织,培训成本可能超过收益。
  • 长期不允许改变导入策略的生产环境,例如所有依赖都必须来自内网 npm registry。
  • 追求最成熟招聘市场和最大库生态的团队,nodejs 仍是低风险选择。
  • 2009 年:Ryan Dahl 发布 Node.js,让 JavaScript 第一次大规模跑进服务端。
  • 2018 年:他在演讲里总结 Node 早年遗憾,包括权限、包管理和构建默认值。
  • 2020 年:Deno 1.0 发布,主打默认安全、TypeScript 内建和 Web 标准 API。
  • 2024 年:Deno 2.0 加强 npm / Node 兼容,路线从“另起炉灶”转向“更安全的现实替代”。
  1. 默认安全不是限制开发,而是减少系统盲区的第一道门。
  2. 运行时设计应考虑“权限最小化”,不是“能做就做”。
  3. URL 导入适合实验和模块共享,但生产需配套锁定策略。
  4. 工具链越“开箱即用”,工程规范越要提前定义。
  • 官方首页:Deno Docs
  • Deno Deploy:边缘部署与运行时一致性
  • Deno 1.0 到 2.0 的迁移文档
  • Deno by Example:用短代码理解权限、HTTP、KV 和 task
  • Node compatibility 文档:判断 npm 包能否直接迁移
  • 同类对比:nodejs —— 共同背景下的不同设计选择
  • javascript —— 运行时语义源自 JS 标准演进
  • typescript —— 类型优先开发的工程约束
  • runtime —— Runtime 与应用安全边界
  • permissions —— 权限最小化思想的实践场景
  • web-standard —— Web 标准 API 在服务端的衍生
  • nodejs —— 相似生态下的 API 迁移路径
  • bun —— 另一路 runtime 性能与兼容性竞争方向
  • boa-engine —— Boa — Rust 写的 ECMAScript 解释器
  • engine262 —— engine262 — 用 JavaScript 实现的 ECMA-262 参考引擎
  • tauri —— Tauri — 用系统浏览器内核 + Rust 做轻量桌面应用
  • wasmer —— Wasmer — 把 wasm 当成轻量容器到处跑
  • 模块版本要固定,尤其是通过 URL 导入时建议与 repo 锁文件联动。
  • 权限默认值务必保持最小化,再在部署阶段逐步放开。
  • 生产排障时,先看标准输出与权限日志,很多问题不在代码而在运行参数。
  • 边缘部署要把超时、重试和降级路径写进 runbook,别把故障抛给调用方。
  • 结合版本管理和 CI 预热机制可以把 “某天 URL 不可访问” 导致的环境问题提前暴露。