Deno 2.0 候选版本来啦!

874 阅读12分钟

原文:Deno官方博客

作者:Bartek Iwańczuk、Andy Jiang 2024年9月19日


我们已经计划 Deno 的新主要版本多年了。多次看似即将发布,但我们意识到需要更多的工作来实现我们想要的功能。而现在,这一刻终于到来了。上个月,我们发布了最后一个 1.x 版本 1.46,今天我们发布了 Deno 2.0 的候选版本,包含了我们预计在最终版本中的所有内容。这是自 1.0 以来最大的一次更新,其中包括引入了 Node 的 process 全局对象等重大变更。我们还做出了一些哲学上的转变,比如更倾向于使用 deno install 代替现在已废弃的 deno cache。请继续阅读完整的更改列表,并分享你的反馈!

要试用该候选版本,请在终端中运行以下命令:

deno upgrade
deno upgrade rc

ℹ️ 如果你使用的是 Homebrew 等替代的分发方式,可能无法使用 deno upgrade

请按照 deno.com 上的安装说明进行操作,然后运行上述命令。

Deno 2.0 候选版本中的新功能

  • 全局变量 windowprocess 的变更
  • 依赖管理
  • 权限系统的变更
  • API 变更
  • 命令行界面的变更
  • 导入断言被弃用,导入属性取而代之
  • Node.js 和 npm 兼容性
  • 通过 deno test --doc 进行文档测试
  • TypeScript 变更

全局变量的变更

Deno 2 带来了两个全局变量的重要变更——window 被移除,并引入了 Node 的 process


我们在 Deno v1.0 中引入了 window 全局对象,目的是让 Deno 尽可能与浏览器兼容。不幸的是,window 全局变量成了用户问题的源头。

许多库通过检测 window 全局变量来判断是否在浏览器中运行,而不是检查 DOM 的存在。这导致了在 Deno 中的许多库出现了一类问题,因为 window 是全局可用的。

Deno 在 v1.40 中开始不鼓励使用 window 全局变量,建议改用 globalThisself

// Deno v1.x
window.addEventListener("load", () => {
  console.log("loaded");
});

// Deno v2.x
globalThis.addEventListener("load", () => {
  console.log("loaded");
});

相比之下,process 全局对象是广泛请求的功能。

虽然早已可以通过从 node:process 模块导入来使用 process,但许多流行框架依赖它的全局作用域,尤其是在配置文件中经常用到。

虽然添加 import process from 'node:process'; 看似简单,但它经常会给那些希望在 Deno 中无缝使用流行框架的用户带来摩擦。

因此,通过引入 process 全局对象,你可以期待更多为 Node.js 编写的代码无需任何修改即可在 Deno 中运行。然而,我们仍然鼓励用户优先使用显式导入。因此,新增了一个 no-process-global lint 规则,该规则将在编辑器中提供提示和快速修复,以改用导入语句。

依赖管理

Deno 2 带来了多项新功能以改进依赖管理。

deno add 子命令现在支持具有子路径的标识符:

# Before in Deno v1.46
deno add jsr:@std/testing/snapshot
error: Failed to parse package required: @std/testing/snapshot

Caused by:
    0: Invalid package requirement '@std/testing/snapshot'. Invalid version requirement. Invalid specifier version requirement. Unexpected character '/'
    ...

# Deno v2.0
deno add jsr:@std/testing/snapshot
Add jsr:@std/testing@1.0.2

# Deno v1.46
deno add npm:preact/hooks
error: Failed to parse package required: npm:preact/hooks

Caused by:
    0: Invalid package requirement 'preact/hooks'. Packages in the format <scope>/<name> must start with an '@' symbol.
    1: Packages in the format <scope>/<name> must start with an '@' symbol.

# Deno v2.0
deno add npm:preact/hooks
Add npm:preact@10.24.0

ℹ️ 现在在添加依赖时必须使用 jsr:npm: 前缀,以避免两个注册表中同名包的潜在歧义。

如果你省略了前缀,Deno 将打印出正确的调用建议,检查哪个注册表包含该包。

此外,如果你的项目中包含 package.json 文件,Deno 将优先把 npm: 依赖添加到 package.json 中,而不是 deno.json

cat package.json
{
  "dependencies": {}
}

deno add npm:express
Add npm:express@5.0.0

cat package.json
{
  "dependencies": { "express": "^5.0.0" }
}

你还可以使用 --dev 标志将“开发依赖”添加到 package.json 中:

deno add --dev npm:express
Add npm:express@5.0.0

cat package.json
{
  "devDependencies": { "express": "^5.0.0" }
}

deno install 现在支持 --entrypoint 标志,允许你从指定模块安装所有依赖:

// main.ts
import snapshot from "jsr:@std/testing/snapshot";
import express from "npm:express";
deno install --entrypoint main.ts
Download ...

一个新的 deno remove 子命令被添加,用于快速移除某些依赖:

deno add jsr:@std/testing
Added jsr:@std/testing@1.0.2

cat deno.json
{
  "imports": { "@std/testing": "jsr:@std/testing@^1.0.2" }
}

deno remove @std/testing
Removed @std/testing

cat deno.json
{}

你还可以使用 deno remove 来管理 package.json 中列出的依赖。


Deno 2 附带了一个新的、更简洁的锁文件格式(v4),它在更新依赖时最小化差异,并确保可重现的构建。

cat deno.lock
{
  "version": "4",
  "specifiers": {
    "jsr:@std/assert@^1.0.4": "1.0.5",
    "jsr:@std/data-structures@^1.0.2": "1.0.4",
    "jsr:@std/fs@^1.0.3": "1.0.3",
    "jsr:@std/internal@^1.0.3": "1.0.3",
    "jsr:@std/path@^1.0.4": "1.0.6",
    "jsr:@std/testing@*": "1.0.2",
    "jsr:@std/testing@^1.0.2": "1.0.2"
  },
  // ...
}

Deno 会自动将你迁移到新的锁文件格式。


最后,Deno 改进了错误消息,提供了有关常见问题(例如格式错误的相对导入路径或使用“裸标识符”时缺少依赖项)的有用提示:

// main.ts
import "@std/dotenv/load";
deno run main.ts
error: Relative import path "@std/dotenv/load" not prefixed with / or ./ or ../
  hint: Try running `deno add jsr:@std/dotenv/load`
    at file:///main.ts:1:8

这些更新共同简化了 Deno 项目中的依赖管理过程,使其更加直观,并与现代开发工作流保持一致。

权限系统的变更

新的 Deno.errors.NotCapable 错误

Deno 的权限系统是其最受欢迎的功能之一。当程序尝试访问未通过 --allow-* 标志授权的 API 时,会抛出错误。在 Deno v1.x 中,这是 Deno.errors.PermissionDenied 错误。

不过,这存在一个问题。所有操作系统在权限不足时也会抛出此错误,例如当用户无法访问仅限管理员的文件时,或尝试监听受保护的端口时。因此,尽管使用了 --allow-all 标志,用户仍常常困惑地看到该错误。

在 Deno v2.0 中,缺少 Deno 权限现在会抛出 Deno.errors.NotCapable 错误,以便更容易区分操作系统级错误和 Deno 错误。

await Deno.readTextFile("./README.md");

Deno v1.46

$ deno run main.ts
error: Uncaught (in promise) PermissionDenied: Requires read access to "./README.md", run again with the --allow-read flag
await Deno.readTextFile("./README.md")
           ^
    at Object.readTextFile (ext:deno_fs/30_fs.js:878:24)
    at file:///main.ts:1:12

Deno v2.0

$ deno run main.ts
error: Uncaught (in promise) NotCapable: Requires read access to "./README.md", run again with the --allow-read flag
await Deno.readTextFile("./README.md")
           ^
    at Object.readTextFile (ext:deno_fs/30_fs.js:777:24)
    at file:///main.ts:1:12

Deno.mainModule 不再需要 --allow-read 权限

Deno.mainModule API 的权限检查已放宽,现在不再需要完整的 --allow-read 权限。此更改同样适用于 process.argv API。

此要求已被废弃,获取主模块路径的方法是创建一个 Error 实例并检查其堆栈跟踪。

--allow-hrtime 标志已移除

在 Deno v1.x 中,有一个 --allow-hrtime 标志,它影响了 performance.now() 等 API 提供高精度计时功能。在 Deno 2 中,这个标志已经被移除,这些 API 始终提供高精度计时。

此标志被废弃的原因是高精度计时可以通过标准的 JavaScript API(如 WorkerSharedArrayBuffer)实现。

--allow-run 标志的变更

--allow-run 标志进行了几个重要的变更,目的是引导开发者以更安全的方式执行子进程。

首先,如果你使用 --allow-run 标志而没有指定二进制名称或二进制文件路径的允许列表,将会显示警告:

new Deno.Command("echo", { args: ["hello"] }).spawn();
$ deno run --allow-run main.ts
Warning --allow-run without an allow list is susceptible to exploits. Prefer specifying an allow list (https://docs.deno.com/runtime/fundamentals/security/
hello

其次,当子进程使用 LD_*DYLD_* 环境变量时,系统将需要完整的 --allow-run 权限。这些环境变量通常不应被依赖。如果你确实需要使用它们,建议通过额外的安全层(例如 Docker 容器)进一步对 Deno 进行沙盒化。

new Deno.Command("echo", {
  env: {
    "LD_PRELOAD": "./libpreload.so",
  },
}).spawn();
$ deno run --allow-run=echo main.ts
error: Uncaught (in promise) NotCapable: Requires --allow-all permissions to spawn subprocess with LD_PRELOAD environment variable.
}).spawn();
   ^
    at spawnChildInner (ext:runtime/40_process.js:182:17)
    at spawnChild (ext:runtime/40_process.js:205:10)
    at Command.spawn (ext:runtime/40_process.js:479:12)
    at file:///main.ts:5:4

文件名中的逗号转义

现在可以为包含逗号的文件名授予读取和写入权限。

在 Deno v1.x 中,逗号用于区分多个文件名:

deno run --allow-read=file1.txt,file2.txt
# 授予读取 `file1.txt` 和 `file2.txt` 的权限

这使得无法为文件名中包含逗号的文件授予权限。

在 Deno 2 中,可以通过用另一个逗号转义逗号来实现:

deno run --allow-read=file,,.txt,file2.txt
# 授予读取 `file,.txt` 和 `file2.txt` 的权限

API 变更

稳定 API

Deno 2 稳定了以下几个 API:

  • WebGPU API 不再需要 --unstable-webgpu 标志
  • Deno.dlopen() 及其他 FFI API 不再需要 --unstable-ffi 标志
  • Deno.createHttpClient() 不再需要 --unstable-http 标志

此外,当你尝试使用不稳定的 API 而没有添加相应标志时,错误信息得到了改进,并提供了有用的提示:

const db = await Deno.openKv();

Deno v1.46

$ deno run db.ts
error: Uncaught (in promise) TypeError: Deno.openKv is not a function
const db = await Deno.openKv();
                      ^
    at file:///db.ts:1:23

Deno v2.0

error: Uncaught (in promise) TypeError: Deno.openKv is not a function
const db = await Deno.openKv();
                      ^
    at file:///db.ts:1:23

    info: Deno.openKv() 是一个不稳定的 API。
    hint: 请使用 `--unstable-kv` 标志运行以启用该 API。

Deno API 的重大变更

ℹ️ 更多关于如何从已弃用 API 迁移的信息,请访问 Deno 1 到 2 的迁移指南

以下 API 已被移除:

  • Deno.Buffer
  • Deno.close()
  • Deno.copy()
  • Deno.customInspect
  • Deno.fdatasync()Deno.fdatasyncSync()
  • Deno.File(此外,Deno.FsFile 不能再手动构造)
  • Deno.flock()Deno.flockSync()
  • Deno.fstat()Deno.fstatSync()
  • Deno.fsync()Deno.fsyncSync()
  • Deno.ftruncate()Deno.ftruncateSync()
  • Deno.funlock()Deno.funlockSync()
  • Deno.futime()Deno.futimeSync()
  • Deno.iter()Deno.iterSync()
  • Deno.metrics()
  • Deno.read()Deno.readSync()
  • Deno.readAll()Deno.readAllSync()
  • Deno.resources()
  • Deno.seek()Deno.seekSync()
  • Deno.shutdown()
  • Deno.write()Deno.writeSync()
  • Deno.writeAll()Deno.writeAllSync()

TLS 选项的处理也进行了更新,以下选项不再受支持:

  • Deno.ConnectTlsOptions.certChain
  • Deno.ConnectTlsOptions.certFile
  • Deno.ConnectTlsOptions.privateKey
  • Deno.ListenTlsOptions.certChain
  • Deno.ListenTlsOptions.certFile
  • Deno.ListenTlsOptions.keyFile

以下接口已被移除:

  • Deno.Closer
  • Deno.ReaderDeno.ReaderSync
  • Deno.SeekerDeno.SeekerSync
  • Deno.WriterDeno.WriterSync

此外,某些与 DNS 记录处理相关的接口名称已更改:

  • Deno.CAARecord 改为 Deno.CaaRecord
  • Deno.MXRecord 改为 Deno.MxRecord
  • Deno.NAPTRRecord 改为 Deno.NaptrRecord
  • Deno.SOARecord 改为 Deno.SoaRecord
  • Deno.SRVRecord 改为 Deno.SrvRecord

以下 API 中不再提供 "资源 ID":

  • Deno.FsWatcher.prototype.rid
  • Deno.Conn.prototype.rid
  • Deno.TlsConn.prototype.rid
  • Deno.TcpConn.prototype.rid
  • Deno.UnixConn.prototype.rid
  • Deno.FsFile.prototype.rid
  • Deno.Listener.prototype.rid
  • Deno.TlsListener.prototype.rid

最后,部分 API 被“软弃用”,这些 API 仍然可以使用,但不再接收更新或 bug 修复。建议尽快迁移到对应的稳定 API:

  • Deno.serveHttp() - 使用 Deno.serve() 代替
  • Deno.run() - 使用 new Deno.Command() 代替
  • Deno.isatty(Deno.stdin.rid) - 使用 Deno.stdin.isTerminal() 代替
  • Deno.isatty(Deno.stdout.rid) - 使用 Deno.stdout.isTerminal() 代替
  • Deno.isatty(Deno.stderr.rid) - 使用 Deno.stderr.isTerminal() 代替

命令行界面(CLI)变更

Deno 2 移除了以下两个子命令:

  • deno bundle - 已在 Deno v1.31 中弃用,因为用户期望的功能与内置打包工具的实际功能存在不匹配。许多 Deno 用户期望一个通用的、高度可定制的打包工具,而 Deno 内置的打包工具仅用于将多个文件简单拼接为单个文件,便于分发,没有提供自定义行为的设置。我们计划在未来版本中实现一个新的内置打包工具,请关注更新。
  • deno vendor - 已在 Deno v1.45 中弃用,并被 Deno v1.37 引入的 deno.json 文件中的 vendor 选项 取代,这种方式更简单。

多个 CLI 标志已被弃用:

  • --lock-write - 使用 --frozen 代替
  • --unstable - 使用更细粒度的 --unstable-<feature> 标志代替
  • test --allow-none - 使用 test --permit-no-files
  • --jobs - 使用 DENO_JOBS 环境变量代替
  • test --trace-ops - 使用 test --trace-leaks
  • --ts - 使用 --ext=ts 代替

此外,可以通过 DENO_LOG 环境变量启用调试日志,而不是 RUST_LOG

最后,配置文件中的 files 选项已被弃用。

在 Deno v1.x 中支持如下语法:

{
  "test": {
    "files": {
      "include": ["**/*.ts"],
      "exclude": ["ignore.ts"]
    }
  }
}

而在 Deno 2 中,files 配置已简化,并被扁平化到父配置中:

{
  "test": {
    "include": ["**/*.ts"],
    "exclude": ["ignore.ts"]
  }
}

导入断言已废弃,导入属性取而代之

导入断言功能在 Deno v1.46 中已弃用,在 Deno 2 中不再可用。

原因是该提案已进行了重大更改,包括将关键字从 assert 更改为 with,并且该提案已被重命名为 导入属性。此外,一些浏览器(例如 Chrome)也已停止支持导入断言。

更新后的语法如下:

- import data from "./data.json" assert { type: "json" };
+ import data from "./data.json" with { type: "json" };

Node.js 和 npm 兼容性

改进的 CommonJS 支持

自 Deno 1.0 版本以来,Deno 一直优先使用 ES 模块作为主要的模块系统,只为 CommonJS 提供了有限的支持,通常通过手动创建 require

import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
require("...");

尽管我们坚信 ES 模块是 JavaScript 的未来,但在 2024 年,许多库和项目仍然依赖于 CommonJS。

过去一年中,Deno 已经可以很好地处理 CJS 库,但用户在集成 CommonJS 尤其是自己的代码时,仍可能遇到一些问题。

在 Deno 2 中,针对 CommonJS 模块进行了以下改进,帮助用户更好地使用它们,并更容易过渡到 ES 模块:

  • 支持直接运行 CommonJS 文件: 现在 Deno 可以执行带 .cjs 扩展名的 CommonJS 文件,如:
deno run index.cjs

使用此选项时,Deno 不会自动安装依赖项,因此你需要手动运行 deno install 以确保所有依赖项可用。

// index.cjs
const express = require("express");

注意: Deno的权限系统仍然有效,因此调用将会提示需要权限。

deno run index.cjs
┏ ⚠️  Deno requests read access to "/dev/example".
┠─ Learn more at: https://docs.deno.com/go/--allow-read
┠─ Run again with --allow-read to bypass this prompt.
┗ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all read permissions) >
  • import cjs from "./index.cjs" - Deno 现在能够导入使用.cjs 扩展名的 CommonJS 文件。Deno 不会查找 package.json文件和类型选项来确定文件是 CommonJS 还是 ESM
// greet.cjs
module.exports = {
  hello: "world",
};
import greet from "./greet.cjs";
console.log(greet);
deno run main.js
{
  "hello": "world"
}
  • require(ESM) - Deno 现在支持加载 ES 模块了。但这仅在被加载的模块不使用顶级等待(Top-Level Await)的情况下才可行。这一改变旨在提升互操作性,以便在同时使用依赖于 CommonJS 和 ES 模块的混合依赖项时,能够更流畅地工作。
// greet.js
export function greet(name) {
  return `Hello ${name}`;
}
// esm.js
import { greet } from "./foo.js";

export { greet };
// main.cjs
const esm = require("./esm");
console.log(esm);
console.log(esm.greet("Deno"));
deno run --allow-read main.cjs
[Module: null prototype] { greet: [Function: greet] }
Hello Deno

在处理CommonJS模块时,提供更佳的错误建议,引导您走向可正常运行的程序。

// main.js
module.exports = {
  foo: "foo",
};
deno run main.js
error: Uncaught (in promise) ReferenceError: module is not defined
module.exports = {
^
    at file:///Users/ib/dev/deno/main.js:1:1

    info: Deno does not support CommonJS modules without `.cjs` extension.
    hint: Rewrite this module to ESM or change the file extension to `.cjs`.

默认使用“自带 node_modules”机制

Deno 2 进一步完善了 “自带 node_modules” 功能,这一功能 首次引入于 Deno v1.38

ℹ️ 虽然我们仍然强烈建议不要依赖于本地的node_modules目录,但许多现有项目和框架都是基于这样一个假设来运行的,即这个目录将会存在。

但有时,即便没有package.json文件,你可能仍希望拥有一个本地的node_modules目录——例如,在使用Next.jsRemixSvelte等框架时;或是当你依赖使用Node API的npm包时,如duckdbsqlite3esbuild等。为了提高兼容性,如果项目包含package.json文件,Deno将会期望node_modules目录已被手动设置。


在之前的 Deno 版本中,你可以使用 --node-modules-dir 标志或配置文件中的 nodeModulesDir 选项来告诉 Deno 是否应该创建 node_modules 目录。

Deno 2 改变了这个配置选项 - 它不再是一个布尔值,而是一个有三种选项的枚举:

默认模式

deno run main.ts

# 或者

deno run --node-modules-dir=none main.ts

或者使用配置文件

{
  "nodeModulesDir": "none"
}

这是 Deno 优先项目的默认模式 - 即没有 package.json 文件的项目。它会自动将依赖项安装到全局缓存中,并且不会创建本地的 node_modules 目录。

ℹ️ 推荐用于新项目。注意,期望有 node_modules 目录的框架将无法工作,此外,依赖于 postinstall 脚本的任何 npm 依赖项也将无法工作。

auto 模式

deno run --node-modules-dir=auto main.ts

或者使用配置文件

{
  "nodeModulesDir": "auto"
}

auto 模式会自动将依赖项安装到全局缓存,并在项目根目录创建一个本地的 node_modules 目录。

ℹ️ 推荐用于有依赖于 node_modules 目录的 npm 依赖项的项目 - 主要是使用打包器的项目或者有 postinstall 脚本的 npm 依赖项。

manual 模式

deno run --node-modules-dir=manual main.ts

或者使用配置文件

{
  "nodeModulesDir": "manual"
}

manual 模式是使用 package.json 的项目的默认模式。这种模式是 Node.js 使用的工作流程,需要使用 deno install/npm install/pnpm install 或任何其他包管理器明确安装步骤。

ℹ️ 推荐用于使用 Next.js、Remix、Svelte、Qwik 等框架的项目;或使用 Vite、Parcel、Rollup 等工具。


建议使用默认的 none 模式,并在遇到有关 node_modules 目录中缺少包的错误时,退回到 automanual 模式。

Node.js API 兼容性

Deno 2 对 Node.js 内置 API 的支持再次取得了显著进展,从而支持了更多流行的包:

  • node:crypto 接口得到了多项更新:
    • 支持 MD4 摘要函数,解决了 npm:docusaurus 的兼容问题。
    • 修复了 Cipheriv.update(string, undefined) 的问题。
    • 修复了 Decipheriv 在关闭 autoPadding 选项时的表现。
    • 支持导出 JWK 公钥和导入 EC、RSA、八位组密钥对(octet key pairs)等。
    • 支持 npm:web-push
  • async_hooks.AsyncLocalStorage 更加高效和稳定。
  • **支持 npm:detect-port 和 **npm:portfinder 库。
  • **改进对 npm:ssh2 和 **npm:elastic-apm-node 的支持。
  • node:wasi 现已内置。
  • node:events** 和 **node:util 的覆盖范围得到了扩展。
  • npm:puppeteer 更加稳定,修复了 FileHandle#writeFile API 和 socket 升级处理。
  • 改进对 node:constantsnode:fsnode:pathnode:vm** 和 **node:zlib 等模块的支持,导出缺失的常量。
  • node:trace_events 已内置,避免崩溃。
  • node:timers 现在导出 promises 符号。
  • npm:qwiknpm:hono** 和 **npm:playwright 库的稳定性得到了提高。

使用 deno test --doc 测试文档中的代码

JSDoc是一种用于编写 JavaScript 和 TypeScript 内联文档的格式。它是 deno doc JSR 自动为其模块生成文档的方式。

JSDoc 允许我们直接在注释中编写代码示例:

/**
 * ```ts
 * import { assertEquals } from "jsr:@std/assert/equals";
 *
 * assertEquals(add(1, 2), 3);
 * ```
 */
export function add(a: number, b: number) {
  return a + b;
}

但是还有一个问题……如何确保这些示例保持最新并且不会代码过时?

Deno v1.10 添加了对示例进行类型检查的功能,这在一定程度上缓解了这种情况,但并未完全解决问题。确保示例是最新的唯一方法是实际执行它们。

在 Deno 2 中,deno test --doc不仅对 JSDoc 中的示例进行类型检查,还执行它们:

此处为视频,点击链接查看

要测试您的 JSDoc 示例,只需运行deno test --doc,Deno 就会自动发现并运行相关的代码块。

ℹ️如果你只想对示例进行类型检查,你仍然可以通过运行来进行deno check --doc

但这还不是全部!除了测试 JSDoc 示例,你还可以在 Markdown 文件中执行代码块:

此处为视频,点击链接查看

这是该功能的首次迭代,我们 非常欢迎任何反馈

TypeScript 变化

Deno 2.0 搭载了 TypeScript 5.6,详细内容可以参考 TypeScript 5.6 发布公告 博客。

为了帮助开发者捕捉常见问题,以下 TypeScript 配置默认启用:

  • useUnknownInCatchVariables
  • noImplicitOverride

此外,Deno 2 内置了对 @types/node 版本 22 的支持,简化了依赖 Node.js API 的代码的类型检查。

为了确保你的 compilerOptions 设置始终是最新的,Deno 现在对配置选项进行了白名单处理。如果你使用了不受支持的选项,Deno 将会发出警告。

致谢

没有我们社区的帮助,我们不可能构建出 Deno!无论是在我们社区的 Discord 服务器中回答问题,还是报告错误,我们都非常感谢你们的支持。特别感谢以下人员对 Deno 2 候选版本做出的贡献:Andreas Deininger, Armaan Salam, Bedis Nbiba, Birk Skyum, Bob Callaway, Caleb Cox, Caleb Lloyd, Coty, Hajime-san, HasanAlrimawi, Ian Bull, Ivancing, Jake Abed, Kamil Ogórek, Kenta Moriuchi, Kyle Kelley, Mohammad Sulaiman, MrEconomical, MujahedSafaa, Pig Fang, Rano | Ranadeep, Roy Ivy III, Sean McArthur, Sʜɪᴍᴜʀᴀ Yū, Victor Turansky, Yazan AbdAl-Rahman, Zebreus, chirsz, cions, i-api, melbourne2991, seb, vwh, 和 Łukasz Czerniawski。

你想加入 Deno 贡献者的行列吗?请查看我们的贡献文档,下次你也会出现在名单上。

感谢你关注我们的 Deno 2 候选版本,我们希望你热爱使用 Deno 进行构建!

接下来是什么?

此候选版本正朝着我们的 2.0 版本努力,预计会有程序缺陷和问题。如果您遇到任何问题,请在 GitHub issues(带有 2.0 标签)中或在我们的 Discord 专门的“#deno-2-help”频道中告诉我们。我们正在积极监控这两个区域,以确保在 2.0 版本发布之前修复所有主要的程序缺陷。