跳到主要内容
Deno 2.4 发布,带来 deno bundle、字节/文本导入、OTel 稳定版等新特性
了解更多
Deno 1.33

Deno 1.33:Deno 2 即将到来

正如最近在 Node Congress 2023 上“强制优化”演示中提到的那样,我们正在努力争取在未来几个月内发布 Deno 2 的一个重要版本。尽管我们对 Deno 2 的愿景雄心勃勃,但自项目启动以来,我们的目标从未改变。

轻松编码:无论是删除配置、样板代码还是构建步骤,我们都致力于让您轻松投入代码并立即提高生产力。此版本使我们的 LSP 更加健壮,支持 LSP 的任何代码编辑器都能与 Deno 项目完美协作。

一流的性能:速度和效率对开发者和用户都很重要。此版本提高了 HTTP 和 WebSocket 服务器的性能,并为进一步的性能工作奠定了基础。

毫不妥协的安全性。Deno 内置了安全功能,采用选择性加入的权限模型,因此您始终知道您的代码可以访问什么。在未来几个月,我们将为 Deno 的权限系统引入新功能,使其更易于使用且更灵活。

Deno 1.33 是向这些理想迈进的又一步。此版本带来了:

随着 Deno 2 的临近,接下来的次要版本将专注于提高性能、创造一流的开发者体验、增强安全性以及更强大的 Node/npm 兼容性。


内置 KV 数据库

Deno KV 是 Deno 中无缝集成的数据库。无需安装任何依赖项,您可以立即开始构建应用程序。此外,当您部署到 Deno Deploy 时,您的数据将由一个一致的、地理复制的全球数据库提供支持。请记住,KV 目前是一个不稳定的 API,因此您需要使用 --unstable 标志才能使用它。

立即开始使用 KV,无需任何设置

const kv = await Deno.openKv();

const key = ["users", crypto.randomUUID()];
const value = { name: "Alice" };
await kv.set(key, value);

const result = await kv.get(key);
result.value; // { name: "Alice" }

当然,数据在磁盘上是持久且可维护的,即使在程序重新启动后也能确保可靠的存储和访问。

有关详细文档,请查阅手册

更扁平化的 deno.json 配置

deno.json 模式已扁平化,使其更易于阅读和写入。

嵌套选项,例如 "lint.files.exclude""fmt.options.lineWidth",现在可在其各自部分的顶层使用。

以前这样写:

{
  "lint": {
    "files": {
      "exclude": ["gen.ts"]
    }
  },
  "fmt": {
    "options": {
      "lineWidth": 80
    }
  }
}

现在您可以这样写,效果相同:

{
  "lint": {
    "exclude": ["gen.ts"]
  },
  "fmt": {
    "lineWidth": 80
  }
}

所有更改

之前 之后
bench.files.include bench.include
bench.files.exclude bench.exclude
fmt.files.include fmt.include
fmt.files.exclude fmt.exclude
fmt.options.useTabs fmt.useTabs
fmt.options.lineWidth fmt.lineWidth
fmt.options.indentWidth fmt.indentWidth
fmt.options.singleQuote fmt.singleQuote
fmt.options.proseWrap fmt.proseWrap
fmt.options.semiColons fmt.semiColons
lint.files.include lint.include
lint.files.exclude lint.exclude
test.files.include test.include
test.files.exclude test.exclude

此更改向后兼容,但我们倾向于在未来弃用旧模式。

感谢 @scarf005 实现了此更改。

动态导入的权限检查更少

此版本在使用动态导入时带来了巨大的用户体验改进。

如果您在 import() 调用中使用字符串字面量(例如 import("https://deno.land/std/version.ts")),Deno 将不再需要权限来执行此导入。我们长期以来一直能够下载和分析这类导入,经过讨论,我们决定最好不要要求权限来执行此代码——它已经是您程序“模块图”的一部分,并显示在 deno info main.ts 的输出中。

此更改将使在某些情况下有条件地执行代码变得更容易——例如,如果您有一个包含许多子命令的 CLI 工具,您可能希望仅在调用子命令时有条件地加载其相应的处理程序。这大大缩短了您工具的启动时间。另一个例子是仅在需要时加载 polyfill,或者仅在存在环境变量时在服务器应用程序中执行调试代码。

请记住,对于无法静态分析的动态导入(即,未将字符串字面量用于说明符),仍将检查权限。

import("" + "https://deno.land/std/version.ts");

import(`https://deno.land/std@${STD_VERSION}/version.ts`);

const someVariable = "./my_mod.ts";
import(someVariable);

感谢 Nayeem Rahman 实现了此更改。

npm 和 Node 兼容性改进

自上次发布以来,node:cryptonode:httpnode:vm 模块已得到极大改进。我们为大多数 node:crypto API 提供了 polyfill,这解除了许多流行 npm 包(包括云提供商 SDK)的阻塞。对 node:httpnode:vm 的更改对 Vite 用户特别有帮助,Vite 现在与 Deno 一起使用时应该更加稳定和高性能。

此版本中实现的所有 API 的完整列表:

  • crypto.checkPrime
  • crypto.checkPrimeSync
  • crypto.createSecretKey
  • crypto.createVerify
  • crypto.ECDH
  • crypto.generateKey
  • crypto.generateKeyPair
  • crypto.generateKeyPairSync
  • crypto.generateKeySync
  • crypto.generatePrime
  • crypto.generatePrimeSync
  • crypto.getCurves
  • crypto.hkdf
  • crypto.hkdfSync
  • crypto.sign
  • crypto.Sign
  • crypto.verify
  • crypto.Verify
  • crypto.X509Certificate
  • http.ClientRequest.setTimeout
  • http.IncomingMessage.socket
  • module.Module._preloadModules
  • vm.runInThisContext

在 npm 支持方面,我们大大改进了 npm 包的缓存处理。从这个版本开始,Deno 在缓存中遇到缺失版本(或版本不匹配)的包时,将尽力从注册表检索信息。这应该会大大减少建议使用 --reload 标志来检索最新注册表信息的提示消息。

性能改进

在此版本中,我们彻底改进了 HTTP 服务器以及 WebSocket 客户端和服务器的实现。在过去几个月里,我们收到了关于 Deno.serveWebSocket API 性能和可靠性不如预期的反馈。

我们认真对待这些反馈,并正在不懈努力改进它们。尽管 RPS 基准测试中的变化可能尚未在您的应用程序中显现,但我们已采取根本性措施来提高这些 API 的整体性能,我们将在未来几个月内进行展示。

CLI 改进

deno bench - --no-run 标志

此版本为 deno bench 子命令添加了一个新的 --no-run 标志,用于缓存所有解析的基准测试文件而不运行它们。这使 deno benchdeno test 对齐。

> deno bench --no-run
Download https://deno.land/std@0.185.0/path/mod.ts
Download ...etc...
Check file:///home/user/project/main_bench.ts

感谢 Geert-Jan Zwiers 贡献了此功能。

deno task - unset 命令

跨平台的 unset 命令已添加到 deno task 中的 shell,允许删除环境变量和 shell 变量。这与 POSIX unset 命令的功能相同,并且现在执行 MY_VAR= 可以正确地将变量设置为空。

{
  "tasks": {
    // `deno task example` outputs "1" then "false"
    "example": "export VAR=1 && echo $VAR && deno task next",
    "next": "unset VAR && deno eval 'console.log(Deno.env.has(\"VAR\"))'"
  }
}

LSP 文档预加载

在 Deno 的早期版本中,您可能会发现某些功能除非您之前打开过文件,否则无法正常工作。例如,在某些代码上执行“查找引用”可能不会显示它在测试文件中被使用,除非该测试文件之前已被打开。现在,通过在初始化语言服务器时预加载文件,此问题已得到缓解,这将带来更好的体验。

请注意,作为此预加载的一部分,语言服务器将最多遍历 1000 个文件系统条目,并在达到此限制时输出一条日志消息。如果这成为问题并且工作区包含大量与 Deno 无关的文件,您可能希望利用 "deno.enablePaths" 选项来部分启用工作区

Deno API 更改

我们正在弃用 Deno.run API。随着 v1.31 中 Deno.Command API 的稳定,它是我们推荐的生成子进程的方式。Deno.run 存在一些难以解决的怪癖,我们将大部分精力集中在设计一个更易于使用的更好 API 上。Deno.run 将在 v2.0 中移除,因此我们强烈建议您将代码迁移到 Deno.Command

不稳定的 Deno.serve API 引入了一项重大更改,移除了其中一个 API 重载,为该 API 的稳定做准备。Deno.serve(handler: Deno.ServeHandler, options: Deno.ServeOptions) 重载已被移除,不再在 v1.33 中可用。

请更新您的代码以使用其中一个可用的重载。

Deno.serve((_req) => new Response("Hello, world"));

Deno.serve({ port: 3000 }, (_req) => new Response("Hello, world"));

Deno.serve({
  onListen({ port, hostname }) {
    console.log(`Server started at http://${hostname}:${port}`);
    // ... more info specific to your server ..
  },
  handler: (_req) => new Response("Hello, world"),
});

我们计划在下个月稳定 Deno.serve,它将成为比 Deno.serveHttp 更推荐使用的 API。

标准库更改

std/encoding 模块的重大更改

正如上一篇发布文章中宣布的那样,以下 6 个编码模块已移至顶层:

  • std/encoding/csv 已移至 std/csv
  • std/encoding/yaml 已移至 std/yaml
  • std/encoding/toml 已移至 std/toml
  • std/encoding/json 已移至 std/json
  • std/encoding/jsonc 已移至 std/jsonc
  • std/encoding/front_matter 已移至 std/front_matter

在此版本中,这些已弃用的模块已完全移除。如果您尚未迁移到新路径,请更新您的导入说明符。

注意:如果您不直接依赖这些已移除的路径,但您的传递依赖项通过非版本化模块 URL 错误地依赖这些路径,您可能无法通过更新自己的源代码来修复此问题。在这种情况下,请使用以下模式的导入映射:

{
  "imports": {
    "https://deno.land/std/encoding/yaml.ts": "https://deno.land/std@0.179.0/encoding/yaml.ts"
  }
}

这将强制将整个依赖图中的非版本化标准库 URL(在本例中为 https://deno.land/std/encoding/yaml.ts)重新映射到版本化 URL(https://deno.land/std@0.179.0/encoding/yaml.ts),从而修复您的依赖项中的问题。

fs.exists 已取消弃用

std/fs 模块中的 existsexistsSync 曾一度在 v0.111.0 中被弃用,但在此版本中已取消弃用。

这些 API 因其易错性而被弃用。它们很容易导致竞态条件错误,称为 TOCTOU。然而,在它们被弃用后,关于其正确/合理用法进行了长时间的讨论。在重新考虑了它们的便利性和易错性之间的平衡后,决定恢复它们。

std/csv 模块更新

在此版本中,添加了 CsvStringifyStream API。此 API 将源流式输入转换为 CSV 行流。

import { CsvStringifyStream } from "https://deno.land/std@0.185.0/csv/mod.ts";
import { readableStreamFromIterable } from "https://deno.land/std@0.185.0/streams/mod.ts";

const file = await Deno.open("data.csv", { create: true, write: true });
const readable = readableStreamFromIterable([
  { id: 1, name: "one" },
  { id: 2, name: "two" },
  { id: 3, name: "three" },
]);

await readable
  .pipeThrough(new CsvStringifyStream({ columns: ["id", "name"] }))
  .pipeThrough(new TextEncoderStream())
  .pipeTo(file.writable);

继上述添加之后,CsvStream 已重命名为 CsvParseStream 以明确其用途。

感谢 Yuki Tanaka 的贡献。

V8 11.4

此版本升级到最新的 V8 版本 (11.4,之前是 11.2)。

此次升级带来了一些令人兴奋的新 JavaScript 功能: