Deno 2024年回顾
2024 年,Deno 团队在实现简化编程的愿景方面取得了重大进展。我们发布了备受期待的 Deno 2,它提供了与 Node 和 npm 的向后兼容性,将依赖管理添加到工具链中,并通过 monorepo 和工作区支持扩展了灵活性。以下是 2024 年值得关注的技术改进总结:
- 您现在可以使用 Deno 2 运行 Node 应用程序,它提供了原生的
package.json
和node_modules
支持,以及改进的 CommonJS 兼容性。这些改进还使得能够逐步采用 Deno 的一体化工具链。 - Deno 的 npm 兼容性得到了显著改善。现在您可以在 Deno 中使用诸如
@grpc/grpc-js
、playwright
、@google-cloud
、mysql2
、pglite
、ssh2
等更多包。 - 今年我们推出了 JSR,一个现代的、开源的 JavaScript 注册表,它拥有原生 TypeScript 支持(您可以将模块发布为 TypeScript 源代码),可以处理跨运行时和环境的模块加载,从 JSDoc 风格的注释自动生成文档,并且可以与任何 npm 兼容的包管理器一起使用。阅读更多。
- Deno 的内置工具链现在包含一个 npm 和 JSR 包管理器,并新增了这些子命令:
deno install
、deno add
、deno remove
和deno outdated
。Deno 可以从 npm 或 JSR 安装依赖,并且在冷缓存下比 npm 快 15%,在热缓存下快 90%。 - 我们使
Deno.serve()
提速了 8-15%,增加了声明式编写服务器的能力,并引入了deno serve
子命令,它支持使用--parallel
标志的多线程服务器。 - 代码签名和资产捆绑现在已在
deno compile
中得到支持,这使得从 JavaScript 编译自包含的跨平台可执行文件变得更加容易。我们还在 2024 年将deno compile
的输出大小大致减半。 - 经过 5 年的开发,我们稳定了
rusty_v8
,这是一个 Rust crate,它提供了 V8 C++ API 的高质量、零开销 Rust 绑定,并作为 Deno 的核心运行。如果您对创建自定义 JavaScript 运行时或将 JavaScript 嵌入 Rust 应用程序感兴趣,请务必探索其 API。 - Deno 标准库,作为一系列经过严格审计的实用模块集合,涵盖了数据操作、Web 相关逻辑、JavaScript 特定功能等,现已稳定发布 1.0 版本。它在 JSR 上可用,并可以在其他运行时和环境中(如浏览器)使用。阅读更多。
- Deno 项目在 GitHub 上获得了超过 10 万颗星!感谢大家的支持。
下面让我们深入了解这些更新。
与 Node 和 npm 的向后兼容性
在 2022 年,我们的调查回复显示了能够将 npm 包与 Deno 一起使用的重要性。经过两年多的努力,随着 Deno 2 的发布,我们很高兴地宣布 Deno 提供了与 Node 和 npm 的向后兼容性。
Deno 实现向后兼容性的一些关键更新包括理解 package.json
、移除全局变量 window
并添加 process
、使“自带 Node 模块”功能成为默认,以及对 node:
内置模块等数十项错误修复。有了 Deno 2,您不仅可以在 Deno 中运行现有的 Node 项目,还可以导入和使用 npm 包,例如 playwright
、prisma
、sqlite3
、duckdb
和 gRPC
。除此之外,Deno 2 还支持 Next.js、Astro、Remix、Qwik、Solid 等 JavaScript 框架。
尽管我们坚信 ES 模块是 JavaScript 的未来,但许多遗留项目和库仍依赖 CommonJS。2024 年,我们改进了 CommonJS 支持。Deno 可以运行和导入带有 .cjs
扩展名的 CommonJS 文件,并在处理 CommonJS 问题时提供更具描述性的错误。
最后,为了让您的 Deno 项目更具灵活性,我们增加了monorepo 和工作区支持。Deno 工作区也理解 npm 工作区,这意味着您可以创建一个混合 Deno-npm monorepo,其成员可以拥有 package.json
或 deno.json
。您甚至可以使用 deno publish
将工作区成员发布到 JSR,而无需手动确定发布顺序(请参阅Deno 标准库作为示例)。
内置、高性能的依赖管理
从 Deno 2 开始,Deno 自带一个包管理器,并新增了这些子命令:deno install
、deno add
和 deno remove
。如果您使用过 npm,这些子命令会很熟悉,但它们要快得多:deno install
在冷缓存下比 npm 快 15%,在热缓存下快 90%。
这些包管理命令可以根据提供的说明符,或根据包是否存在于 package.json
或 deno.json
中,从 npm 或 JSR 拉取/移除包。
为了扩大对需要执行安装前或安装后脚本的 npm 包的支持,我们还增加了对 npm 生命周期脚本的支持,新增了 --allow-scripts
标志
deno install --allow-scripts=npm:duckdb
最后,为了便于在大型开发团队中共享内部模块,我们增加了私有 npm 注册表支持。它们的工作方式与 Node 和 npm 中完全相同:使用 .npmrc
文件
// .npmrc
@mycompany:registry=http://mycompany.com:8111/
//mycompany.com:8111/:_auth=secretToken
JSR:一个现代化的开源 JavaScript 注册表
今年,我们推出了一个新的 JavaScript 注册表,JSR。它原生支持 TypeScript(您可以将模块发布为源代码),处理跨运行时和环境的模块加载,从 JSDoc 风格的注释自动生成文档,并且可以与类似 npm/npx 的系统一起使用。
由于 TypeScript 源代码可以直接上传到 JSR,因此它对代码有着深入的理解。这为模块的发布和使用提供了更流畅、无缝的开发体验。要了解更多幕后细节,请阅读我们关于JSR 架构的文章。
使用 deno publish
将模块发布到 JSR 非常简单,您甚至可以使用 deno init --lib
快速搭建 JSR 模块。
✅ Project initialized
Run these commands to get started
# Run the tests
deno test
# Run the tests and watch for file changes
deno task dev
# Publish to JSR (dry run)
deno publish --dry-run
尽管 Deno 团队构建了 JSR,但它旨在服务于更广泛的 JavaScript 社区。我们目前正在努力为 JSR 建立一个开放的管理机构。如果您感兴趣并想了解更多信息,请查看JSR Discord 并加入我们的双周办公时间会议,在此会议上我们会回答社区问题并分享 JSR 路线图。
更快、更小、更简单的 JavaScript 跨平台编译二进制文件
自 Deno v1.6 以来,deno compile
已使开发者能够将 JavaScript 和 TypeScript 程序转换为可在所有主流平台上运行的独立单一二进制文件——无需依赖,无需额外安装。这意味着简化部署和更快的启动。与Node 的 8 步编译过程不同,deno compile
是一个单一命令。
在过去的一年里,我们对 deno compile
进行了重大改进,例如将编译后的二进制文件大小减小了高达 50%,添加了用于软件验证的代码签名、Windows 图标支持以及资产捆绑。此外,使用 deno compile
创建的程序还可以使用V8 代码缓存以实现更快的启动时间。通过这些更新,您现在可以编译完整的应用程序,例如将 HTML/JS/CSS 游戏编译成原生桌面二进制文件。
为了展示使用 deno compile
带来的性能提升,这里有一个编译 npm
的例子:
deno compile -A npm:npm
根据我们的观察,Deno 编译的 npm
二进制文件运行速度比普通 npm
快约 1.9 倍
# hyperfine "./npm -v" "npm -v"
Benchmark 1: ./npm -v
Time (mean ± σ): 40.1 ms ± 2.0 ms [User: 37.7 ms, System: 5.3 ms]
Range (min … max): 38.9 ms … 51.8 ms 71 runs
Benchmark 2: npm -v
Time (mean ± σ): 75.2 ms ± 7.6 ms [User: 59.1 ms, System: 9.0 ms]
Range (min … max): 69.2 ms … 105.0 ms 40 runs
Summary
./npm -v ran
1.87 ± 0.21 times faster than npm -v
我们将继续迭代和改进 deno compile
,例如支持编译全栈框架等。
deno serve
搭建更快、更简单的 Web 服务器
使用 构建 Web 服务器是 Deno 的一个常见用例,去年我们在其性能和可用性方面都取得了显著改进。我们重构了Deno.serve()
API,使其速度提升了 8-15%。
在 Deno 中编写服务器也变得更容易了。我们还增加了deno serve
命令,允许您声明式地编写服务器
export default {
fetch(request) {
return new Response("Hello world");
},
};
$ deno serve server.ts
deno serve: Listening on http://localhost:8000/
$ curl http://localhost:8000/
Hello world
deno serve
还支持使用 --parallel
标志的多线程服务器,这使得在多个 CPU 核心之间自动负载均衡变得同样易于使用。
您可以使用 deno init --serve
选项在几秒钟内启动一个新的服务器。Deno 还增加了能够使用 satisfies Deno.ServeDefaultExport
对您的服务器入口文件进行类型检查的功能。
Deno 在 AWS Lambda 上表现出色
Deno 致力于构建最快、性能最优的 JavaScript 和 TypeScript 运行时,去年我们在这方面取得了重大进展。我们通过添加V8 代码缓存以及在快照期间预热引导初始化来缩短启动时间。
当 Deno 在无服务器环境中(Deno 常用于生产环境)运行时,我们还在 Deno 中取得了显著的性能改进。Deno 增加了在 DENO_DIR
中为 SQLite 数据库提供了预写日志(WAL)日志,改进了代码缓存、启动时间和冷启动。为了比较无服务器环境中的性能,我们发布了一份关于 AWS Lambda 上 JavaScript 运行时冷启动的基准测试,其中包含了我们的方法论以及一些最大化性能的技巧。
去年,Deno 的整体性能方面还有许多其他改进。尽管基准测试无法揭示全貌,但它们可以提供关于运行时在哪方面表现出色的洞察。以下是 2.0 版本发布的一些基准测试,希望能提供更好的了解。
Temporal API 和 Wasm 导入
Temporal
API 旨在解决 JavaScript 中 Date
对象的局限性和复杂性,目前正在所有主流 JavaScript 引擎中积极实现。您已经可以在 Deno 中通过--unstable-temporal
标志尝试使用它。
虽然 Deno 一直支持 WebAssembly(“Wasm”),但我们的 2.1 版本将Wasm 支持提升为一流,使得导入 Wasm 模块就像导入任何其他模块或文件一样简单
// Now in Deno 2.1
import { add } from "./add.wasm";
console.log(add(1, 2));
// $ deno main.ts
// 3
现在,在 Deno 中加载 Wasm 模块的性能更高,因为它们是“模块图”的一部分,可以进行分析和缓存以更快地使用。不仅如此,Deno 还理解导出 Wasm 模块,并可以在您的代码库中对其使用进行类型检查。
随着越来越多的 Wasm 在 Web 上用于提高浏览器应用程序的性能,我们将继续努力使 Wasm 与 Deno 的使用尽可能地简单和快速。
用 deno.json 做更多事情
编程应该简单,这就是我们构建 Deno 时采用零配置和合理默认值的原因。然而,我们承认大型项目通常需要更复杂的设置,因此我们不断改进了可选的 deno.json
配置文件,以满足这些需求,同时不牺牲易用性
- 更灵活的
tasks
:您的deno task
现在可以包含npm
命令、使用 shebang 的脚本,并且可以作为带有详细描述的对象编写和依赖项。使用依赖项时,deno task
将在可能的情况下并行运行任务,并处理依赖项中的循环以确保避免无限循环。deno task
还可以运行package.json
脚本。 - 增强的格式化选项:
deno fmt
现在支持格式化更多文件,例如 HTML、CSS、YAML、Astro、Angular、Svelte、Vue 等。 - 更简单的导入:Deno 现在预处理
imports
字段,以支持一种更简单的语法来指定带有子路径导出的依赖项。
这些改进有助于使 Deno 不仅对大型应用程序来说功能强大且灵活,而且对小型项目来说也简单易用。
Deno 标准库,已稳定
经过 4 年多、151 个版本发布和 4 千多次提交,Deno 标准库终于稳定了。这个包含 40 多个经过严格审计的实用模块的集合,涵盖了 JavaScript、Web 和通用数据操作的广泛用途。最棒的是,这个库可以在所有 JavaScript 运行时和环境(如浏览器)中使用。
为了让您了解 Deno 标准库中可用模块的类型,这里列出了标准库模块及其在 npm 中的对应部分:
Deno 标准库模块 | npm 包 |
---|---|
@std/testing | jest |
@std/expect | chai |
@std/cli | minimist |
@std/collections | lodash |
@std/fmt | chalk |
@std/net | get-port |
@std/encoding | rfc4648 |
有关可用包的完整列表,请访问 https://jsr.deno.org.cn/@std。
值得关注的开源 Rust crate
构建 Deno 意味着接触广泛的开源项目,我们为这些项目贡献力量,以扩展 Deno 的功能并优化性能。以下是一些开发者可能会发现独立于 Deno 本身也有用的 Rust crate:
rusty_v8
:该库提供了 V8 C++ API 的高质量、零开销 Rust 绑定。自五年前我们最初发布它以来,它在 crates.io 上已经有近 150 个版本发布和超过 310 万次下载。去年,我们宣布rusty_v8
已经稳定并可用于生产环境。deno_semver
:这个 Rust crate 提供了用于解析、比较、验证和操作 npm 和 JSR 包所使用的语义版本(semver)字符串的实用工具。deno_npm
:这个 crate 是一个 npm 客户端,作为 Deno 和 npm 包生态系统之间的桥梁。该库以与 Node.js 相同的方式解析 npm 模块,因此如果您正在编写 Rust 代码并希望与 npm 生态系统互操作,它会非常有用。deno-vite-plugin
:这个 Deno Vite 插件支持在 Vite 中进行 Deno 解析,这允许您在 Vite 中使用 Deno,以及从 JSR 和 HTTP 导入库。deno_cache_dir
:这个 TypeScript 模块提供了对 Deno 缓存的访问,其逻辑与 Deno CLI 相同。其他几个 Deno 工具,例如deno_graph
、deno_doc
、dnt
和deno_emit
,都依赖于这个模块,以与 Deno CLI 相同的方式访问和填充缓存。
Fresh、Deno Deploy、Subhosting
在 Deno 2 发布的同时,我们迎来了重要的里程碑,我们继续运营并迭代我们的无服务器计算平台,Deno Deploy,这是在云端运行任意 JavaScript/TypeScript 的最简单方式。
我们为 Deno Deploy 用户提供了改进的入门流程,包括新教程,展示了如何轻松开始使用 Deno 的云原生功能,以及一个简化的项目创建流程,它会自动检测框架并为构建和部署步骤提供更高的透明度。我们还让 Next.js 在 Deno Deploy 上运行起来了!
我们还为用户提供了使用 Deno Deploy 的更多灵活性。我们发布了 deployctl
,它是 Deno Deploy 的 CLI 工具,允许用户从终端创建、管理和观察您的部署。Web Cache API
支持还赋予用户对其部署性能的精细控制。此外,我们还实施了通过新的支出限额对云计费进行保障。
过去一年,我们的企业产品 Deno Subhosting 持续改进。我们增加了对通过编程管理自定义域和子域以及配置数据备份的支持。如果您想了解您的产品如何在无需数月工程投入的情况下安全运行用户不可信代码的更多信息,请联系我们。
最后,我们正在继续迭代我们的下一代、基于岛屿的全栈 Web 框架,Fresh,2.0 版本即将发布。(实际上,Fresh 2 已经发布了测试版,文档和正式发布即将到来。如果您想访问 Fresh 2,请在Discord 中告诉我们。)这个下一个主要版本是对内部 API 的实质性大修,但应该能解锁创建可组合和模块化中间件的能力。敬请期待!
Deno 2 之外
去年我们发布了 Deno 2,扩展了开发者已经喜爱的 Deno 特性——其简洁性、一体化工具链、内置 Web 标准 API 和 TypeScript 支持——使其在更广泛的项目和用例中变得更加灵活和可用
- 与 Node 和 npm 的向后兼容性
- monorepo 和工作区支持
- 改进了与 JSR 和 npm 的包管理
- 企业级功能,如 LTS 和 专用企业支持渠道
今年,我们将专注于让 Deno 在生产场景中更加可靠和高效。例如,在我们的下一个小版本中,我们计划改进可观测性、追踪和调试功能。我们还在努力实现 Deno 及其商业产品 Deno Deploy 更快的云性能,希望很快能分享更多信息。