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

Deno 1.37:Jupyter Notebooks 中的现代 JavaScript

Deno 的使命是大幅简化软件开发。在 Deno 1.37 中,我们很高兴能将此扩展到交互式 Jupyter Notebook。从 1.37 开始,您可以使用新的 deno jupyter 命令来创建可用于 Notebook 的 Deno 内核。此外,Deno 1.37 还附带了更强大的 Visual Studio Code 和 LSP 支持、更好的测试性能、改进的 Node 兼容性以及许多错误修复。

如果您已经安装了 Deno,请在终端中通过以下命令升级到 1.37 版本

deno upgrade

如果您尚未安装 Deno,可以使用以下命令之一安装,或通过许多其他方式安装。

MacOS / Linux 安装

curl -fsSL https://deno.land/x/install/install.sh | sh

Windows 安装

irm https://deno.land/install.ps1 | iex

以下是 Deno 1.37 新功能的概述。

Deno 1.37 概览

  • 📒 Jupyter Notebook Deno 现在与 Jupyter Notebook 无缝集成,弥合了脚本编写和分析之间的差距。
  • 🖥️ VSCode 扩展和语言服务器 VSCode 扩展持续改进,包括更好地检测 `deno.json`、引入 `deno.disablePaths` 配置、更好地支持文件重命名、npm 说明符补全、一个名为 `deno.suggest.completeFunctionCalls` 的新配置以及更多修复。
  • 🧪 测试改进 更简单、更快、更好!我们改进了测试套件,使其更直观地编写测试,并确保更快的反馈循环。
  • Node.js 兼容性改进 内置 Node API 的持续改进意味着 Deno 现在支持 `npm:mssql`、`npm:mineflayer` 和 `npm:web-push` 等模块。大多数 NPM 模块在 Deno 中都可以开箱即用。
  • 🏝️ 体验优化 支持新的导入属性语法,使用 `Deno.serve()` 优雅关闭,以及大量的性能改进。

Jupyter Notebook 集成

Deno v1.37 内置支持 Jupyter Notebook 内核,这带来了现代 JavaScript 和 TypeScript,并开启了全新的数据科学和机器学习可能性。

如果您尚未安装,请先安装 Jupyter——此命令假定您的系统上已安装 Python 和 pip

pip install jupyterlab

如果您安装了 Python 3,您可能需要改用 pip3 命令。其他安装选项此处有介绍

要在 Jupyter 中开始使用 Deno,请运行

deno jupyter --unstable

然后按照提示完成安装。有关 deno jupyter --unstable 的更多文档可在此处找到

您现在可以使用 Jupyter Lab 或您喜欢的支持这些 Notebook 的 IDE 来创建交互式 REPL 会话。

Using the Deno kernel in a Jupyter notebook

在 Jupyter Notebook 中使用 Deno 内核

Using the Deno kernel in a CLI

在 CLI 中使用 Deno 内核

您可以直接从 Notebook 访问所有 Deno 的 API 和 npm 模块。

您不仅可以在 Jupyter Notebook 中使用现代 JavaScript,还可以从 npm 导入 D3 来可视化您的数据。

D3 example with Deno and Jupyter

截图由 Elijah Meeks 提供

此外,您还可以通过返回一个包含 Symbol.for("Jupyter.display") 函数的对象,从您的单元格提供富文本输出。

Using `Symbol.for("Jupyter.display")` in a notebook

您甚至可以使用 Deno KV Connect 连接到您托管的 Deno KV,并将实时数据直接拉入 Notebook。

Using Deno KV in a Jupyter notebook

最后,如果您正在使用 Noteable.io,您可以今天就在您的托管 Jupyter Notebook 中使用 Deno。Noteable.io 的首席架构师兼 Jupyter 项目核心维护者 Kyle Kelley 描述了此集成所解锁的可能性:

Deno 新的 Jupyter 内核为能编写 JavaScript 的用户的数据科学工作流带来了巨大的潜力。Deno 现代 JavaScript 运行时和内置 TypeScript 支持的原生访问所带来的可能性让我感到兴奋。JavaScript 开发者可以创建 Notebook 来分析数据、构建模型并创建交互式报告。

在 Jupyter JavaScript 内核中配置 Babel 和 TypeScript 的日子一去不复返了。由于 Deno 支持基于 URL 的 ESM 导入,Deno 内核使得共享可在任何地方运行的 Notebook 变得异常容易。依赖项是声明性的。组织可以利用现有的 Jupyter 部署,并立即获得 Deno 安全运行时沙箱的访问权限,而无需放弃 Jupyter 提供的灵活工作流。

有关使用 Deno 的 Jupyter 集成的更多详细信息,请查看我们的文档。我们正在寻求社区对此功能的反馈,因此请尝试使用并让我们知道您是否发现任何问题或缺少的功能

VSCode 扩展和语言服务器

通过检测 deno.json 启用

为了方便从事非 Deno TypeScript 项目的用户,Deno 扩展默认是禁用的。以前,您必须在编辑器的工作区设置中指定 "deno.enable": true 才能启用它。现在,只要您的项目根目录包含 deno.json 文件,您就可以将其留空。您仍然可以指定 "deno.enable": false 来覆盖此设置。

"deno.disablePaths"

为帮助解决上述情况,引入了新的 "deno.disablePaths" 设置。这是现有 "deno.enablePaths" 设置的补充。如果您有嵌套的非 Deno 子项目,它将禁用指定路径的 Deno 扩展。

// .vscode/settings.json
{
  "deno.disablePaths": ["./node_api/", "./vsc_extension/"]
}

自动更新文件重命名时的导入

这是许多语言中广泛使用的重构功能。Deno 的语言服务器现在提供此功能——重命名 JS/TS 文件后,您将收到提示,可以选择更新项目中指向该文件的导入说明符。

NPM 说明符补全

现在,当您在导入说明符中键入 npm: URL 时,将显示 NPM 包的自动补全选项。这些选项通过搜索 NPM 注册表获取。

import "npm:prea";
//     "npm:preact"; ✔️
//     "npm:preact-render-to-string";
//     "npm:preact-compat";
//     "npm:preact-jsx-chai";
//     "npm:preact-css-transition-group";
//     ...

但可能更有用的是:如果您键入了 npm:<package_name>@,您将看到该包最新发布版本的自动补全选项。查找有效版本曾是使用 NPM 说明符的繁琐部分。现在这已为您完成。

import "npm:preact@";
//     "npm:preact@11.0.0-experimental.1";
//     "npm:preact@11.0.0-experimental.0";
//     "npm:preact@10.17.1"; ✔️
//     "npm:preact@10.17.0";
//     "npm:preact@10.16.0";
//     ...

函数调用补全

设置 "deno.suggest.completeFunctionCalls": true 以在选择已知函数签名的自动补全选项时包含括号和参数占位符。这是 "typescript.suggest.completeFunctionCalls""javascript.suggest.completeFunctionCalls" 的重新实现。

// Type the following:
addEventLi
// and select the autocomplete option for `addEventListener`.

// `"deno.suggest.completeFunctionCalls": false`:
addEventListener

// `"deno.suggest.completeFunctionCalls": true`:
addEventListener(type, listener)

deno.cacheOnSave

引入了一个新的 "deno.cacheOnSave" 设置。启用后,当您保存文件时,扩展将自动缓存新的依赖项。这对于经常向项目添加新依赖项的用户来说非常方便,并且无需从命令面板运行“缓存依赖项”命令。目前此设置默认关闭,但我们计划在未来的版本中默认启用它。

测试资源管理器和代码透镜修复

自 1.36.0 以来,许多测试 API 错误已得到修复。

  • 测试资源管理器在执行带步骤的测试时不再冻结。
  • 当测试步骤的名称更改时,它们在资源管理器中会正确替换。以前,每键入一个字符就会注册一个新步骤,您必须重置语言服务器才能清理它。
  • 在某些情况下,具有相同名称的嵌套测试步骤不会被唯一注册,并在资源管理器中共享相同的条目。现在 ID 分配已修复。
  • 通过测试资源管理器运行所有测试不再评估不包含任何测试的模块。
  • 测试资源管理器中不再显示没有测试的模块。
  • 通过代码透镜运行单个测试时,如果文件中的另一个测试设置了 { only: true },以前不会运行任何测试并记录失败,因为使用了 only 选项。现在它按预期运行,并正确忽略其他测试。
  • 通过代码透镜运行名为 foo 的测试不再运行文件中名称包含 foo 的其他测试(例如 foobar)。感谢 @Leokuma
  • 现在,包含在测试资源管理器中并显示“运行测试”代码透镜的文件集根据 deno.json 字段 excludetest.excludetest.include 进行过滤。

其他修复

  • 在自动导入补全条目的标签描述中显示源模块。
  • 相对和裸说明符的优先级高于远程 URL,用于自动导入补全条目。
  • 插入自动导入代码时,会遵守格式偏好设置。
  • 不以 .json 结尾的 JSON 模块说明符不再显示关于没有默认导出的错误诊断。这会影响数据 URL 和包含查询字符串或片段的说明符。
  • 快速修复操作按 tscdeno、然后是 deno-lint 的顺序排序。
  • 导入补全现在包括本地 JSON 模块。
  • 按整个路径组件匹配 "deno.enablePaths" 条目。以前,文件名为条目字符串前缀的文件会被启用(例如,foo 会同时启用 foo.tsfoobar.ts)。现在它必须是路径前缀,即条目必须是文件的确切名称或其父目录之一。
  • 调试测试时始终使用 --inspect-wait 而不是 --inspect-brk。仍存在使用不太适合的 --inspect-brk 的情况。感谢 @jeiea
  • 正确处理不支持 workspace/configuration 请求的语言服务器客户端。在某些情况下,这些请求被发送到无法处理它们的客户端。
  • 删除已失效的 "deno.testing.enable" 设置。此设置没有任何作用。

测试改进

上一个版本对 Deno 测试 API 的持续改进之后,本月我们也有一些令人兴奋的更新。

速度提升

我们提高了测试运行的性能,Deno 现在每秒可以运行多达 14,000 个测试。这是通过优化 Deno 测试运行器内置的清理器实现的,将每个测试用例的基线开销从 3ms 降低到不足 0.1ms。

我们有进一步的计划来改进测试性能,您可以期待在下一个版本中获得更快的速度。

TAP 测试报告器

deno test 现在可以以 Test Anything Protocol 格式输出测试结果。您可以通过使用 --reporter=tap 标志启用它。

$ deno test --reporter=tap ./test.ts
TAP version 14
# ./test.ts
ok 1 - test 0
ok 2 - test 1
ok 3 - test 2
ok 4 - test 3
ok 5 - test 4
ok 6 - test 5
ok 7 - test 6
ok 8 - test 7
ok 9 - test 8
ok 10 - test 9
1..10

感谢 Valentin Anger 实现了此功能。

聚焦和忽略测试的简写方法

您现在可以使用简写方法 Deno.test.onlyDeno.test.ignore 来聚焦和忽略测试,如下所示:

// Only run this test
Deno.test.only(function myTest() {
  // ...
});

// Do not run this test
Deno.test.ignore(function myTest() {
  // ...
});

这是一个小的改动,但比必须指定像 Deno.test({ only : true }, function myTest() ... 这样的选项包更容易、更快地迭代。

体验优化

除了上面描述的更改之外,我们还有大量其他小更改,使 Deno 中的测试体验更好。

过滤后的套件不显示

如果您使用 --filter <name> 标志只运行一部分测试,测试运行器现在只会在输出中显示过滤后的测试。这使得更容易专注于您关心的测试。

Deno v1.37 之前

`deno test --filter` before Deno v1.37

Deno v1.37 中

`deno test --filter` in Deno v1.37

ASCII 转义字符不再破坏测试名称

现在,诸如 \n\t 等字符在测试名称中已正确转义,因此如果您确实需要在测试名称中包含它们,报告器输出将不会被破坏。

--trace-ops 显示更多详细信息

如果您的测试中存在 ops 泄漏,--trace-ops 标志可以帮助您找到泄漏的来源。在此版本中,此标志变得更智能,可以在更多情况下显示有用的信息。

按名称过滤优先于 only 选项

如果您的测试套件设置了 only 选项为 true,但您想运行通过名称过滤的其他测试(使用 --filter <name> 标志),则该测试将正常运行。

JUnit 报告包含更多信息

文件、行和列属性已正确添加到生成的报告中。

从覆盖率报告中排除内部代码

通过从生成的报告中排除内部 Deno 代码,覆盖率现在更快且噪声更小。

如果您有其他想法如何改进 Deno 的测试运行器,请在 Deno 的 Bug 跟踪器中提出问题,让我们知道。

Node.js 兼容性改进

此版本中包含许多重要的 Node.js API 修复:

  • child_process 不再在环境变量为 undefinednull 时抛出错误。
  • crypto 模块实现了 AES GCM 密码。
  • http 现在正确处理 Content-Length 标头,发出 "error" 事件,正确销毁请求并清理分配的资源。
  • http2 添加了对 ClientHttp2Sessionconnect API 的支持。
  • process.title 不再抛出错误。
  • 现在支持 repl._builtinLibs
  • tls 现在实现了 TLSSocket._start 方法。
  • worker_threads.Worker 现在正确处理 process.argv
  • zlib 支持 dictionary 选项。
  • require 现在使用规范化路径来加载内容。
  • 已测试并正常工作的其他 npm 模块:mssqlmineflayerinfiscalweb-push

如果您想了解更多关于 Deno 中 Node.js 兼容性的信息,请查看我们的 Node.js 兼容性列表

体验优化

将供应商作为缓存覆盖 (不稳定)

现在可以通过简单地将以下内容添加到您的 deno.json 中来供应商依赖项:

{
  "vendor": true
}

下次您运行或缓存(例如 deno cache mod.ts)时,Deno 将在 ./vendor 文件夹中填充程序使用的远程 https/http 依赖项。

另外,也可以通过 --vendor 标志进行供应商化。

请注意,Deno 对 ./vendor 文件夹的处理方式有所不同,因为它并非总能将 URL 直接映射到文件系统。

您可能会发现此功能比 deno vendor 子命令更容易使用,因为它管理开销极小且适用于更多场景。因此,从 CLI 中移除 deno vendor 子命令并将其作为独立工具分发可能更有意义(有关更多详细信息,请参阅 issue #20584)。

导入属性

此版本添加了对 导入属性提案 的支持。该提案早期被称为“导入断言”,Deno 自 1.17 版本以来就支持它。

导入属性允许您使用 import 声明导入 JSON 文件

import jsonData from "./data.json" with { type: "json" };

它也适用于动态导入

const jsonData = await import("./data.json", { with: { type: "json" } });

使用 assert 的旧语法仍然受支持,但已弃用。我们将在接下来的几个版本中逐步淘汰它;在接下来的版本中,如果您在自己的代码中使用弃用的 assert 语法,Deno 将打印警告。

Deno.Server.prototype.shutdown()

此版本带来了新的、不稳定的 API:Deno.Server.prototype.shutdown(): Promise<void>

// Start a server...
const server = Deno.serve((_req) => new Response("hello world!"));

// ...and close it gracefully after 3 seconds.
setTimeout(async () => {
  await server.shutdown();
}, 3000);

在此版本之前,只能通过使用在服务器构建期间传递的 AbortSignal 来“突然”关闭服务器。然而,以这种方式关闭服务器并非总是可取的,在大多数情况下,您希望等待所有进行中的请求完成,然后再关闭服务器。

这个新 API 是不稳定的,因为我们希望在稳定它之前收集社区的反馈;此外,我们希望添加一个 timeout 参数,该参数将控制服务器等待挂起请求完成的时间,然后再强制关闭它们。

性能改进

此版本我们优化了许多 Web API 以及 HTTP 相关 API(Deno API 和内置 Node.js API 中)。以下是完整列表:

  • EventaddEventListener 经过了深度优化,使其速度大大提高;Event.timeStamp 现在始终设置为 0

  • Headers 针对迭代和查找场景进行了优化,此外标头名称的验证也得到了优化

  • node:http 获得了标头处理的优化——IncomingMessageForServer.headers 现在使用缓存来避免每次访问都计算标头

  • node:buffer 已从头重写,以在输出字符串时提供更快的结果

  • node:net 收到了套接字读取的优化,这使得 npm:ws 包的性能大大提高

所有这些优化在 HTTP 基准测试中提供了高达 10% 的 RPS 提升。

感谢 Marcos Casagrande 实现了许多这些优化。

锁文件 v3

锁文件格式已更新至版本 3。Deno 1.37 将在首次运行时自动将您现有的锁文件迁移到新格式,但在旧版本 Deno 中加载 v3 将会出错。

新格式包含重定向信息,Deno 使用这些信息将 http(s) 重定向锁定到它们在插入锁文件时解析到的目标。

std/url

在此版本中,std/url 模块已添加到 Deno 标准库中。std/url 支持对 URL 进行各种类似路径的操作,这些操作不受 Web 标准 URL 方法或属性 的支持。

目前 std/url 包含以下 5 种方法:

  • basename
  • dirname
  • extname
  • join
  • normalize
import {
  basename,
  dirname,
  extname,
  join,
  normalize,
} from "https://deno.land/std@0.202.0/std/url/mod.ts";

const url = new URL("https://example.com/home/page.html?foo=bar");

basename(url); // => "page.html"
dirname(url); // => new URL("https://example.com/home")
extname(url); // => ".html"
join("https://example.com", "foo", "bar.html"); // => new URL("https://example.com/foo/bar.html")
normalize("https://example.com///about///page.html"); // => new URL("https://example.com/about/page.html")

感谢 Aritra Karak 实现了此模块。

std/ulid

此版本中,std/ulid 已添加到 Deno 标准库中。std/ulid 支持生成 ULID 并从给定的 ULID 解码时间戳。

import { decodeTime, ulid } from "https://deno.land/std@0.202.0/ulid/mod.ts";

const id = ulid(); // => "01HARJZ15RFMBVZ1GQ8J4VB6C4"
const timestamp = decode(id); // => 1695189796023

ULID 是 UUID 的替代方案,由于 ULID 的前导部分是从时间戳生成的,因此这些 ID 按生成时间顺序进行词法排序。当您将其用于 Deno KV 项的部分键时,此属性非常方便。

感谢 Asher Gomez 提出了此功能,感谢 Lino Le Van 实现了它。

V8 11.8 和 TypeScript 5.2.2

最后,Deno v1.37 附带了 V8 11.8 和 TypeScript 5.2.2

还想了解更多?

信不信由你,上面列出的更改仍然没有告诉您 1.37 中所有改进之处。您可以在 GitHub 上查看 Deno 1.37 中合并的完整拉取请求列表

感谢我们的社区贡献者!

没有社区的帮助,我们无法构建 Deno!无论是回答我们社区 Discord 服务器中的问题还是报告错误,我们都非常感谢您的支持。特别是,我们要感谢以下人员对 Deno 1.37 的贡献:Adam Powers、Alexander Michaud、Curran McConnell、Evan、Fabian、Filip Skokan、Jakub Jirutka、Jonathan Rezende、Juan Gonzalez、Kira、Kyle Kelley、Laurence Rowe、Leigh McCulloch、Marcos Casagrande、Shreyas、Valentin Anger、VlkrS、await-ovo、lionel-rowe、osddeitf、sigmaSd、zuisong、林炳权、第二扩展。

您想加入 Deno 社区贡献者的行列吗?请在此处查看我们的贡献文档,下次再见。

感谢您关注我们的 1.37 版本,希望您喜欢使用 Deno 进行构建!

🍋 您知道吗?Fresh 变得更加新鲜了。

Deno Fresh v1.4 于几周前发布,其特点是可选的 AOT 编译步骤可加快页面加载速度、异步布局、路由组等。了解更多关于 Deno 现代 Web 框架的最新版本。