Deno 设计目标的核心是灵活且强大的运行时安全性。通过 Deno 1.36,我们进一步扩展了你的安全选项,使用 --deny-* 标志。与我们现有的 --allow-* 标志一起,你现在可以为网络通信、文件系统访问等配置允许列表和拒绝列表。

除了这些安全功能之外,你还将在 1.36 中发现改进的测试和基准测试 API、更强大的 Node.js 和 npm 包支持、语言服务器改进等等。

如果你已经安装了 Deno, 你可以在终端中升级到 1.36 版本:

deno upgrade

继续阅读以了解 Deno 1.36 中的最新功能和修复!

为 Deno 程序提供更灵活的安全选项

Deno 运行时提供了默认安全性,赋予开发人员选择让其代码和依赖项进行网络请求、访问文件系统或使用其他潜在危险 API 的能力。

这些选项非常有用,但在某些情况下有点不够灵活。您要么可以让程序毫无限制地访问某个功能,要么您需要配置 --allow-* 选项启用的特定域名或目录。没有办法仅打开沙箱,只排除某些域名或文件路径。在 Deno 1.36 中,我们引入了 --deny-* 系列的运行时标志,以实现更灵活的 Deno 程序权限。

例如,如果您希望程序可以访问任何它想要的 URL,但排除几个特定的 IP 地址和域名,可以使用:

$ deno run --allow-net --deny-net=api.evil.com mod.ts

例如,如果您要让程序访问整个文件系统,但排除 /etc 目录:

$ deno run --allow-read --deny-read=/etc --allow-write --deny-write=/etc mod.ts

以前具有 --allow-* 选项的每个 CLI 标志现在也都具有对应 --deny-* 选项。拒绝标志的优先级高于允许标志,因此如果对同一域名或文件路径使用两者,访问仍将被拒绝:

$ deno run --allow-read=foo.txt --deny-read=foo.txt mod.ts
error: PermissionDenied: 需要对 "foo.txt" 具有读取权限...

我们计划进一步改进和扩展权限系统的功能。我们正在研究的一个特性是能够从配置文件中使用预定义的权限 - 关注这个问题以获得更新。

我们很想听听你对新的 --deny-* 标志的反馈,以及你对权限系统的其他需求。请在 Discord、我们的直播活动(也在 Discord 上找到)中告诉我们,或者通过 GitHub 提交问题

扩展的测试和基准测试选项

Deno 1.36 还引入了应用程序测试和基准测试方面的改进。在测试方面,您现在可以使用新的自定义格式化程序输出 deno test 运行的结果。

JUnit 报告者

拥有机器可读的测试报告对于自动化测试和保持大型代码库的可维护性至关重要。JUnit XML 格式可以被许多服务像 GitLab、CircleCI、Jenkins 或 BuildPulse 原生地使用。从 Deno 1.36 开始,您可以传递 --formatter=junit 标志给 deno test 来获取结构化的报告数据:

# 打印 JUnit 报告到终端,以便进行进一步处理...  
$ deno test --reporter=junit

# ...或者与默认的人类可读输出一起直接写入文件。
deno test --junit-path=test_report.xml

点报告者

对于喜欢简短清晰测试报告的人,我们添加了一个 dot 报告者,提供了简明扼要的输出,去掉了很多冗余信息。

deno test --reporter=dot

node:test polyfill

如果您从最近的 Node.js 版本迁移到 Deno,现在可以使用 Node 20 中的内置测试 API,以及 Deno.test 或 来自标准库的 describe/it API

在 Deno 中自己试一试简单的测试工具箱,如下所示。

import assert from "node:assert";
import test from "node:test";

test("同步通过的测试", (t) => {
  // 这个测试通过,因为它没有抛出异常。
  assert.strictEqual(1, 1);
});

test("异步通过的测试", async (t) => {
  // 这个测试通过,因为异步函数返回的 Promise 没有被拒绝。 
  assert.strictEqual(1, 1);
});

还没有覆盖所有的 API 面积,所以如果您遇到问题,我们将非常感谢错误报告

deno bench 改进

通过在 Deno.bench 中添加新功能,Deno 中的基准测试的粒度和精度都得到了改进。

在 Deno 的早期版本中,由于一种名为“JIT 偏差”的现象,对于运行的第一个基准用例,Deno.bench 函数给出了令人惊讶的结果 —— V8 引擎过度优化了基准函数,然后在后续函数上放弃了优化,导致了不代表性的结果。 这现在已经通过在用户定义的基准用例之前运行一个“热身”函数来修复。

此外,您现在可以使用 Deno.BenchContext.startDeno.BenchContext.end 来告诉基准测试工具您要测量的关键部分。这两次调用之间的部分将从测量中排除。

import { readAll } from "https://deno.land/std@0.197.0/streams/mod.ts";

Deno.bench("foo", async (b) => {
  // 打开我们将操作的文件。
  const file = await Deno.open("a_big_data_file.txt");

  // 告诉基准测试工具这是您要测量的唯一部分。
  b.start();

  // 现在让我们测量从文件中读取所有数据需要多长时间。
  await readAll(file);

  // 在此结束测量。
  b.end();

  // 现在我们可以执行一些潜在的时间消耗较大的拆卸操作,这不会污染我们的基准测试结果。
  file.close();
});

我们还更新了 deno bench 输出以包含每秒迭代次数的信息:

Show Image

Node.js 兼容性改进

运行未配置为二进制文件的 npm 包脚本

您现在可以运行未在包的 package.json 中的 bin 属性中配置的 npm 包脚本。 例如:

deno run -A npm:somepackage@0.0.1/foo/cli.mjs

process.dlopen 可用

您现在可以使用 process.dlopen API 来加载 Node.js 的本机插件。

AsyncLocalStorage 最高可提速 3.5 倍

我们优化了从 node:async_hooks 模块的 AsyncLocalStorage 的实现。我们的基准测试显示,与 Deno v1.35.3 相比,它快了最多 3.5 倍。

node:os 被完全 polyfill

Node.js os 模块getPrioritysetPriorityuserInfo 函数现在可用,这使得 node:os 模块被完全 polyfill。

请在 Deno 手册中了解使用 Node.js 内置模块的更多信息。

例如:

import { getPriority } from "node:os";
  
console.log(getPriority());

生活质量改进

下面,我们列出了一些其他特性和错误修复,这些特性和错误修复进入此版本,我们认为它们会对您的日常工作产生重大影响。

deno compile --no-terminal

现在可以对 deno compile 使用新的 --no-terminal 标志。如果在 Windows 上运行编译后的二进制文件,此标志将阻止打开终端窗口。

Deno.createHttpClient.allowHost

不稳定的 Deno.createHttpClient 现在支持 allowHost 选项,使其可以为 fetch 请求指定 Host 头。

const client = Deno.createHttpClient({
  allowHost: true,
});
const res = await fetch("http://example.com", {
  headers: {
    "host": "myhost.com",
  },
  client,
});

允许在 WebSocket API 中使用 HTTP(S) URL

您现在可以在 WebSocket Web API 中使用 http:https: URL,Deno 会自动将协议调整为分别使用 ws:wss::

const url = new URL("https://example.com");
const ws = new WebSocket(url);
console.log(ws.url);
// wss://example.com

重试失败的模块下载

Deno 现在在下载依赖项时更具弹性。由于间歇性连接问题或远程服务器上的短暂错误,连接远程主机总是可能失败的。

在这种情况下,Deno 将等待一小段时间并重试下载,这使 CI 管道更可靠,减少了重新运行命令的需要。