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

Deno 1.8 发布说明

今天我们发布了 Deno 1.8.0 版本。此版本包含大量新功能和稳定性改进。

如果您已安装 Deno,可以通过运行 deno upgrade 升级到 1.8 版本。如果您是首次安装 Deno,可以使用以下列出的方法之一。

# Using Shell (macOS and Linux):
curl -fsSL https://deno.land/x/install/install.sh | sh

# Using PowerShell (Windows):
iwr https://deno.land/x/install/install.ps1 -useb | iex

# Using Homebrew (macOS):
brew install deno

# Using Scoop (Windows):
scoop install deno

# Using Chocolatey (Windows):
choco install deno

新功能和变更

WebGPU API 的实验性支持

WebGPU API 为开发者提供了一种低级、高性能、跨架构的方式,通过 JavaScript 编程 GPU 硬件。它是 Web 上 WebGL 的有效继任者。该规范尚未最终确定,但目前 Firefox、Chromium 和 Safari 正在添加支持;现在 Deno 也已支持。

这个 API 让您可以在 Deno 内部直接访问 GPU 渲染和通用 GPU 计算。一旦完成、稳定并解除标记,这将提供一种便携的方式来从 Web、服务器和开发机器访问 GPU 资源。

GPU 允许程序员将某些数值算法高度并行化。这不仅对图形和游戏渲染有用。在机器学习中有效利用 GPU 使得更复杂的神经网络得以实现,这被称为深度学习。计算机视觉、翻译、图像生成、强化学习等领域的快速发展都源于对 GPU 硬件的有效利用。

如今,大多数神经网络都是用 Python 定义的,计算则卸载到 GPU 上。我们认为,如果存在适当的基础设施,JavaScript 可以在表达数学思想方面充当理想语言,而非 Python。在 Deno 中提供开箱即用的 WebGPU 支持是朝着这个方向迈出的一步。我们的目标是在 Deno 上运行支持 GPU 加速的 Tensorflow.js。我们预计这将在未来几周或几个月内实现。

这是一个基本示例,演示了如何访问已连接的 GPU 设备,并读取其名称和支持的功能。

// Run with `deno run --unstable https://deno.org.cn/blog/v1.8/webgpu_discover.ts`

// Try to get an adapter from the user agent.
const adapter = await navigator.gpu.requestAdapter();
if (adapter) {
  // Print out some basic details about the adapter.
  console.log(`Found adapter: ${adapter.name}`);
  const features = [...adapter.features.values()];
  console.log(`Supported features: ${features.join(", ")}`);
} else {
  console.error("No adapter found");
}

这是一个小示例,演示了 GPU 如何使用渲染着色器在绿色背景上渲染一个简单的红色三角形。

$ deno run --unstable --allow-write=output.png https://raw.githubusercontent.com/crowlKats/webgpu-examples/f3b979f57fd471b11a28c5b0c91d0447221ba77b/hello-triangle/mod.ts

A simple red triangle on a green background

请注意使用 WebAssembly 写入 PNG。更多示例请访问此仓库:https://github.com/crowlKats/webgpu-examples

最终的 PR 多达 1.55 万行代码,并耗时整整 5 个月才合并。非常感谢 crowlKats 领导了 WebGPU 在 Deno 中的集成工作。我们还要感谢为 Deno 中 WebGPU 实现提供支持的 wgpu 和 gfx-rs 项目的所有贡献者。特别感谢 WebGPU 规范的编辑、wgpu 和 gfx-rs 的首席开发者 kvark 在实现 WebGPU API 期间提供的出色指导。

ICU 支持

ICU 支持一直是 Deno 仓库中第二受欢迎的功能。我们很高兴地宣布 Deno v1.8 版本已完全支持 ICU。

所有依赖 ICU 的 JavaScript API 现在都应与浏览器 API 匹配。

在 REPL 中尝试

$ deno
Deno 1.8.0
exit using ctrl+d or close()
> const d = new Date(Date.UTC(2020, 5, 26, 7, 0, 0));
undefined
> d.toLocaleString("de-DE", {
    weekday: "long",
    year: "numeric",
    month: "long",
    day: "numeric",
});
"Freitag, 26. Juni 2020"

改进的代码覆盖率工具:deno coverage

此版本扩展了我们的代码覆盖率基础设施,增加了许多出色的新功能。此版本的主要变化是,代码覆盖率处理现在分为代码覆盖率收集和代码覆盖率报告。

以前,代码覆盖率的收集和报告都通过在启动 deno test 时指定 --coverage 标志在一个子命令中完成。现在,deno test--coverage 标志接受一个参数——一个用于存储收集到的配置文件的目录路径。这是代码覆盖率收集。在第二步中,您现在使用存储代码覆盖率配置文件的目录路径调用 deno coverage。此子命令既可以在控制台上以漂亮的文本输出报告,也可以输出 lcov 文件(--lcov 标志),以供 genhtml、coveralls.io 或 codecov.io 等工具使用。

我们已经在 deno_std 上“内部测试”此功能几天了。我们为每次提交都上传代码覆盖率报告到 codecov.io。您可以在这里查看这些报告:https://codecov.io/gh/denoland/deno_std。添加此功能非常简单,只需对我们的 GitHub Actions 工作流进行 10 行代码更改。

- name: Run tests
-        run: deno test --unstable --allow-all
+        run: deno test --coverage=./cov --unstable --allow-all
+
+      - name: Generate lcov
+        run: deno coverage --unstable --lcov ./cov > cov.lcov
+
+      - name: Upload coverage
+        uses: codecov/codecov-action@v1
+        with:
+          name: ${{ matrix.os }}-${{ matrix.deno }}
+          files: cov.lcov

有关与 coveralls.io 集成的示例,请参阅此仓库:https://github.com/lucacasonato/deno_s3

导入映射现已稳定

导入映射已在 Chrome 89 中稳定,此后我们的实现也已更新以匹配最新规范,并现在也被认为是稳定的。这意味着在使用 --import-map 时不再需要 --unstable 标志。

$ deno run --import-map=./import_map.json ./mod.ts

此外,--import-map 标志现在不仅接受本地路径,还接受 URL,允许您从远程服务器加载导入映射。

$ deno run --import-map=https://example.com/import_map.json ./mod.ts

导入映射允许用户为依赖项使用所谓的“裸”说明符,而不是相对或绝对文件/HTTP URL。

// Deno does not support such specifiers by default,
// but by providing an import map, users can remap bare specifiers
// to some other URLs.
import * as http from "std/http";
{
  "imports": {
    "std/http": "https://deno.land/std@0.85.0/http/mod.ts"
  }
}

用户应记住导入映射不可组合:这意味着您只能为 deno run / deno test 提供单个导入映射。因此,库作者仍应使用常规的非裸说明符(相对或绝对文件/HTTP URL);否则,库的用户将需要手动将您的库(以及您的库的依赖项)的裸说明符添加到他们的导入映射中。

导入映射一个更有用的功能是能够将常规说明符重新映射到完全不同的说明符。例如,如果您的模块图中存在某个深层嵌套的损坏依赖项,您可以在上游修复它之前将其替换为修复版本;或者,如果您使用构建过程为模块文件名添加哈希值,您可以在源代码中引用不带哈希的文件,并仅在运行时使用导入映射重新映射说明符。

有关更多示例和详细解释,请参阅规范

支持使用认证令牌获取模块

并非所有代码都在公共互联网上公开可用。以前 Deno 无法从需要认证的服务器下载代码。在此版本中,我们增加了用户指定每个域的认证令牌的功能,这些令牌在首次获取模块时使用。

为此,Deno CLI 将查找名为 DENO_AUTH_TOKENS 的环境变量,以确定在请求远程模块时应考虑使用哪些认证令牌。环境变量的值格式为若干个令牌,由分号 (;) 分隔,其中每个令牌的格式为 {token}@{hostname[:port]}

例如,单个令牌看起来像这样:

DENO_AUTH_TOKENS=a1b2c3d4e5f6@deno.land

多个令牌看起来像这样:

DENO_AUTH_TOKENS=a1b2c3d4e5f6@deno.land;f1e2d3c4b5a6@example.com:8080

当 Deno 获取远程模块时,如果主机名与远程模块的主机名匹配,Deno 会将请求的 Authorization 头设置为 Bearer {token} 的值。这允许远程服务器识别该请求是绑定到特定已认证用户的授权请求,并提供对服务器上相应资源和模块的访问。

有关更详细的使用指南和配置环境以从私有 GitHub 仓库拉取代码的说明,请参阅相关手册条目

Deno.test 的退出清理器

Deno.test API 已经有两个清理器,它们有助于确保您的代码不会“泄露”操作或资源——即,所有打开的文件/网络句柄在测试用例结束前都已关闭,并且没有更多的待处理系统调用。

Deno 1.8 添加了一个新的清理器,确保被测试的代码不会调用 Deno.exit()。错误的退出语句可能会导致测试结果出现误报,并且通常是被滥用或忘记删除的。

此清理器默认对所有测试启用,但可以通过在测试定义中将 sanitizeExit 布尔值设置为 false 来禁用。

Deno.test({
  name: "false success",
  fn() {
    Deno.exit(0);
  },
  sanitizeExit: false,
});

// This test is never run
Deno.test({
  name: "failing test",
  fn() {
    throw new Error("this test fails");
  },
});

您可以自己运行此脚本:deno test https://deno.land/blog/v1.8/exit_sanitizer.ts

Deno.permissions API 现已稳定

Deno 的安全模型基于权限。目前,这些权限只能在应用程序启动时授予。这在大多数情况下都适用,但在某些情况下,在运行时请求/撤销权限会提供更好的用户体验。

在 Deno 1.8 中,现在有一个稳定的 API 可以查询请求撤销权限。这些 API 包含在 Deno.permissions 对象中。以下是其工作原理的示例:

function homedir() {
  try {
    console.log(`Your home dir is: ${Deno.env.get("HOME")}`);
  } catch (err) {
    console.log(`Failed to get the home directory: ${err}`);
  }
}

// Try to get the home directory (this should fail, as no env permission yet).
homedir();

const { granted } = await Deno.permissions.request({ name: "env" });
if (granted) {
  console.log(`You have granted the "env" permission.`);
} else {
  console.log(`You have not granted the "env" permission.`);
}

// Try to get the home directory (this should succeed if the user granted
// permissions above).
homedir();

await Deno.permissions.revoke({ name: "env" });

// Try to get the home directory (this should fail, as the permission was
// revoked).
homedir();

您可以自己运行此脚本:deno run https://deno.land/blog/v1.8/permission_api.ts

此版本稳定了四个与符号链接相关的 API。

  • Deno.link
  • Deno.linkSync
  • Deno.symlink
  • Deno.symlinkSync

在稳定之前,这些 API 经过了安全审查,并且使用它们需要适当的权限。

Deno.link 和 Deno.linkSync 需要源路径和目标路径的读写权限。

Deno.symlink 和 Deno.symlinkSync 需要目标路径的写权限。

更细粒度的 Deno.metrics

随着 Deno 变得越来越稳定,开发者们拥有简单的方法来检测他们的应用程序变得越来越重要。这从最底层,即运行时本身开始。在 Deno 中,JavaScript 中所有特权操作(那些进入 Rust 的操作)都通过 JS 和 Rust 之间的单一中心接口完成。我们将通过该接口的请求称为“操作”(ops)。例如,调用 Deno.open 会向特权端调用 op_open_async 操作,该操作将返回打开文件的资源 ID(或错误)。

两年多前,即 2018 年 10 月 11 日,我们添加了一种方法,让您可以查看 Rust 和 JavaScript 之间所有操作的指标:Deno.metrics。此 API 目前公开了已启动和已完成的同步及异步操作的数量,以及通过操作接口传输的数据量。到目前为止,这仅限于所有不同操作的组合数据。无法查明哪些操作被调用了多少次,只能查看所有操作的总体情况。

当使用 --unstable 运行时,此版本在 Deno.metrics 中添加了一个名为 ops 的新字段。此字段包含每个操作的详细信息,例如 API 被调用的频率以及通过它传输的数据量。这使得运行时可以进行更细粒度的检测。

这是一个工作示例:

$ deno --unstable
Deno 1.8.0
exit using ctrl+d or close()
> Deno.metrics().ops["op_open_async"]
undefined
> await Deno.open("./README.md")
File {}
> Deno.metrics().ops["op_open_async"]
{
  opsDispatched: 1,
  opsDispatchedSync: 0,
  opsDispatchedAsync: 1,
  opsDispatchedAsyncUnref: 0,
  opsCompleted: 1,
  opsCompletedSync: 0,
  opsCompletedAsync: 1,
  opsCompletedAsyncUnref: 0,
  bytesSentControl: 54,
  bytesSentData: 0,
  bytesReceived: 22
}

在即将发布的版本中,此新信息将由 Deno.test 中的异步操作清理器使用,以便在异步操作未在测试完成前完成时提供更可操作的错误。我们已经看到此功能被用于检测应用程序并将数据传输到监控软件。

screenshot of a website with a table displaying the output of Deno.metrics

deno fmt 支持 JSON

deno fmt 现在可以格式化 .json.jsonc 文件。与 JS/TS 类似,格式化程序还会格式化 Markdown 文件中包含的 JSON 和 JSONC 代码块。

Deno.emit 支持 IIFE 打包

内置打包器现在可以以立即调用函数表达式(IIFE)格式输出打包文件。

默认情况下,输出格式仍为 esm,但用户可以通过将 EmitOptions.bundle 选项设置为 iife 来更改此设置。

const { files } = await Deno.emit("/a.ts", {
  bundle: "iife",
  sources: {
    "/a.ts": `import { b } from "./b.ts";
        console.log(b);`,
    "/b.ts": `export const b = "b";`,
  },
});

console.log(files["deno:///bundle.js"]);

结果:

(function() {
    const b = "b";
    console.log(b);
    return {
    };
})();

您可以自己运行此脚本:deno run --unstable https://deno.land/blog/v1.8/emit_iife.ts

这对于为不支持 ESM 的旧版浏览器创建打包文件特别有用。

deno lsp 现已稳定

在过去的几个月里,我们一直在为 VS Code 的旧编辑器集成(即 Deno 扩展)开发替代品。旧扩展仅适用于 VS Code,并且解析的类型并不总是与 Deno CLI 中的类型匹配。

在 Deno 1.6 中,我们发布了实验性的 deno lsp ——一个 Deno 的内置语言服务器。LSP 允许我们仅用一个代码库就能为所有支持 LSP 的编辑器提供集成。内置语言服务器与 Deno CLI 的其余部分采用相同的架构构建,因此它以与 CLI 其余部分相同的方式提供 TypeScript 诊断。

两周前,在 Deno 1.7.5 中,我们稳定了 deno lsp 并将我们的官方 VS Code 扩展切换为使用它。到目前为止,我们收到了一些很好的反馈,并将努力解决所有已报告的问题。如果您在使用该扩展时遇到问题,请在我们的问题跟踪器上报告。我们无法修复我们不知道的问题。

除了官方的 VS Code 集成之外,还创建了更多基于 deno lsp 的社区集成。

TypeScript 4.2

Deno 1.8 附带最新稳定版本的 TypeScript。

有关 TypeScript 4.2 中新功能的更多信息,请参阅TypeScript 4.2 发布公告