原文:Deno官方博客
作者:Bartek Iwańczuk 等 2024年5月30日
Deno 1.44 引入了对私有 npm 注册表的支持,使用户可以通过配置 .npmrc
文件来在 Deno 中使用内部包。此外,Deno 1.44 现在支持 gRPC 连接,允许与 Google Cloud Platform 等服务进行高性能通信。本次发布还改进了 Node.js 的兼容性,并重新启用了 V8 指针压缩以获得显著的性能提升。与往常一样,此版本还包含许多其他功能和改进,使你的开发体验更加顺畅。
要升级到 Deno 1.44,请在终端中运行以下命令:
bash
deno upgrade
如果尚未安装 Deno,请运行以下任一命令进行安装或了解如何安装。
bash
# Using Homebrew (macOS):
brew install deno
# Using Shell (macOS and Linux):
curl -fsSL https://deno.land/install.sh | sh
# Using PowerShell (Windows):
iwr https://deno.land/install.ps1 -useb | iex
支持私有 npm 注册表
许多大型组织托管自己的私有 npm 注册表来管理内部包。Deno 1.44 现在支持使用 .npmrc
文件来配置 Deno 从私有注册表中获取包。在 package.json
文件中使用私有包或直接使用 npm:
标识符导入包时,可以使用此功能。
.npmrc
:
bash
@mycompany:registry=http://mycompany.com:8111/
//mycompany.com:8111/:_auth=secretToken
deno.json
:
json
{
"imports": {
"@mycompany/package": "npm:@mycompany/package@1.0.0"
}
}
main.ts
:
typescript
// main.ts
import { hello } from "@mycompany/package";
console.log(hello());
运行:
shell
$ deno run main.ts
Hello world!
你还可以在 package.json
文件中使用私有 npm 包:
json
{
"dependencies": {
"@mycompany/package": "1.0.0"
}
}
main.ts
:
typescript
import { hello } from "@mycompany/package";
console.log(hello());
运行:
shell
$ deno run main.ts
Hello world!
现在支持 gRPC 连接
Deno 现在可以使用来自 npm 的 @grpc/grpc-js
客户端库连接到 gRPC 服务。这使得你可以从 Deno 连接到 gRPC 服务,例如 Google Cloud Platform。以下是使用 Google Cloud SDK 通过 Google Cloud Vision API 分类图像的示例:
typescript
import { ImageAnnotatorClient } from "npm:@google-cloud/vision";
const client = new ImageAnnotatorClient();
const [result] = await client.labelDetection("./cat_dog.webp");
const labels = result.labelAnnotations;
console.log("Labels:");
for (const label of labels) {
console.log(" - ", label.description);
}
gRPC 是一个高性能、开源、通用的 RPC 框架,可实现服务之间的高效通信。通过支持 gRPC,你可以构建利用 gRPC 低延迟通信能力的实时交互应用程序。
Node.js 兼容性改进
此次发布标志着 Deno 在兼容 Node.js 和 npm 包方面取得了重要进展。
作为一个重大里程碑,我们已经能够使用 Deno 运行 Next.js 应用程序。虽然仍有一些粗糙的边缘,例如需要使用 DENO_FUTURE=1
,但我们有信心能快速解决这些问题。我们将很快发布一篇博客文章,详细介绍如何使用 Deno 运行 Next.js 应用程序。
现在,这里有一个示例,演示如何使用Deno运行一个Next.js应用程序,使用新的Next.js服务器操作来流式传输文件,详见这里。
此外,其它 Node.js 兼容性改进包括:
- 添加
Buffer.isUtf8()
和Buffer.isAscii()
,这是ts-node
所依赖的。 - 修复 npm 依赖项被打包并传递
process.uptime
时的错误。这个错误是因为我们的实现依赖于this
的正确性。我们已重写process.uptime
以不再依赖任何this
引用。 - 修复
SIG*
监听器未在process.listeners
中被跟踪的问题。这修复了signal-exit
包未能正确退出的错误。该包在许多流行的 CLI 工具中使用,如vitest
。 - 修复
tinypool
无法终止worker_threads
的问题。这是由于我们在Worker.terminate()
中返回了不同的返回代码。tinypool
包在vitest
中被广泛使用。 - 为
tinypool
设置AsyncResource.emitDestroy()
,以允许其干净地关闭工作线程。 - 修复将
MessagePort
传递给 Nodeworker_threads
时缺少的方法。这解决了与vitest
中工作线程通信相关的多个错误。 - 允许在不使用
new
关键字的情况下实例化Process
类。这解决了流行测试运行器jest
的一个问题。 - 为 Next.js 的
build
命令工作,设置perf_hooks.PerformaceObserver
的模拟。 - 在尝试关闭资源之前检查资源是否存在。这使 gRPC 的 deadline 示例能够工作。
- 为具有 bin 入口点的包设置
node_modules/.bin
条目。这是关于 npm 支持的长期请求功能。 - 使解析不正确的
package.json
文件更加健壮。一些 npm 包带有不符合预期数据类型的package.json
文件。 - 修复在调用
fs.rmSync
时对目录而非文件抛出的错误异常。 - 为
ava
模拟findSourceMap
。 - 修复默认状态代码属性未初始化为
200
的ServerResponse
。这使11ty
开发服务器能够工作。 - 修复
node:process
中缺少的geteuid
。 - 修复在 gRPC 中流未标记为取消的问题。这使流示例能够工作。
- 修复发出
response
事件时发出的错误标志。这修复了 gRPC 中的错误传播问题。 - 允许通过
delete
关键字删除process.env
值。这种模式有时在集成测试中使用。 - 为每个
worker_thread
使用单独的模块缓存。解决了这个问题后,SvelteKit
现在能够工作。 - 修复 CommonJS 的罕见再导出错误,这是在使用
@solana/spl-governance
npm 包时发现的。 - 修复
napi_get_element
和napi_set_element
,这使 npm DuckDB 适配器能够在 Deno 中工作。 - 使 HOME 目录检测更可靠,以便在 OpenNext 中运行服务器。
此外,Deno 任务在处理 package.json 文件时变得更加智能。 如果发现一个任务调用了npm run <another_task>
,Deno 将使用 deno 任务代替运行 npm 二进制文件,请参阅 #23036了解更多详细信息。
性能改进
Deno 1.44 引入了多项性能改进,使 Deno 更快且更节省内存。我们预计许多项目的内存使用量将减少 5-30%,具体取决于工作负载。
- 通过 V8 指针压缩减少内存使用 :重新启用 V8 指针压缩使 V8 能更有效地存储指针,大幅减少内存使用。这项改进对存在大量对象分配的实际场景特别有益,显著降低了内存消耗。
- 更快的模块加载 :通过并行执行任务来优化模块加载,包括分析和发出 CommonJS 导出和再导出、在
deno cache
操作期间将 TypeScript 编译为 JavaScript、在模块解析期间跳过不必要的目录查找,以及尽快下载元数据文件。这些改进显著加快了模块处理和缓存效率,减少了整体启动时间,使得大量使用动态导入的项目启动速度快了约 2-3 倍 (#23856, #23894, #23892, #23851, #23836)。 - AWS Lambda 中更快的启动时间 :在 DENO_DIR 中使用 Write-Ahead Logging (WAL) 日志记录提高了代码缓存和 Deno 实例的启动时间,特别是在 AWS Lambda 等无服务器环境中。这项改进有助于减少冷启动的延迟,使无服务器应用程序更具响应性 (#23955)。
- 改进的语言服务器性能 :在 LSP 中缓存打开文档的语义标记,提高了语言服务器性能,使开发过程更流畅高效,减少了重新分析打开文件所需的时间 (#23799)。
标准库向稳定化迈进
Deno 标准库 提供了一套由核心团队审核的高质量包,保证能与 Deno 一起使用。
目前,标准库将独家发布到 JSR 下的 @stdscope。现有版本的标准库将继续保留在 deno.land/std。此举以及 Deno 新的工作区功能,都是 Deno 2 即将带来的变化的一部分。更多详细信息,请查看 标准库的稳定化路线图。
Deno.exitCode
API
本次发布增加了一个新的、稳定的 Deno.exitCode
API。你可以使用这个 API 来获取和设置程序的退出码:
typescript
console.log("Initial code", Deno.exitCode);
try {
console.log("Try to retrieve data...");
await fetch("https://doesnt.exist");
} catch (e) {
console.log("Failed to retrieve data");
// Set the exit code, to a special value to signal a failure.
Deno.exitCode = 42;
// Perform some additional cleanup...
}
console.log("Exit code after the task", Deno.exitCode);
shell
$ deno run --allow-net exit_code.ts
Initial code 0
Try to retrieve data...
Failed to retrieve data!
Exit code after the task 42
$ echo $?
42
你可以使用这个 API 来指定特定的退出码,但不会像 Deno.exit(code?)
API 那样立即退出。这个 API 允许在程序结束前进行额外的清理。
这个 API 与 Node.js 的 process.exitCode
API 非常相似,但 Deno.exitCode
具有更强的验证功能,要求设置有效的十进制退出码。两个 API 可以配合使用,并按预期反映值:
typescript
import process from "node:process";
console.log("Deno 1 - exit code -", Deno.exitCode);
console.log("Node.js 1 - exit code -", process.exitCode);
Deno.exitCode = 42;
console.log("Deno 2 - exit code -", Deno.exitCode);
console.log("Node.js 2 - exit code -", process.exitCode);
process.exitCode = 70;
console.log("Deno 3 - exit code -", Deno.exitCode);
console.log("Node.js 3 - exit code -", process.exitCode);
shell
$ deno run exit_code.ts
Deno 1 - exit code - 0
Node.js 1 - exit code - 0
Deno 2 - exit code - 42
Node.js 2- exit code - 42
Deno 3 - exit code - 70
Node.js 3 - exit code - 70
$ echo $?
70
感谢 Luke Edwards 提议并初步实现了这个 API。
Request#bytes()
和 Response#bytes()
Fetch API 规范 最近更新,在 Request
和 Response
类中增加了新的 .bytes()
方法。这一小改动显著改善了处理字节时的便利性,你不再需要获取底层 ArrayBuffer
并将其转换为 Uint8Array
。
typescript
// Before:
const response = await fetch("https://example.com");
const buffer = new Uint8Array(await response.arrayBuffer());
// After
const response = await fetch("https://example.com");
const buffer = await response.bytes();
Lint 规则更新
本次发布带来了现有规则的重大更新和一条新的 lint 规则。
no-undefined-vars
no-undefined-vars
现在适用于 JSX 和 TSX 文件:
tsx
import React from "react"; // This import is now flagged as unused!
const Foo = () => {
return "Hello world!";
};
这一改进对 Fresh 的用户特别有用。
此规则仍默认启用,如同以前的版本。
no-boolean-literal-for-arguments
通常会定义可以接受 boolean
参数的函数。然而,传递 boolean
字面量作为参数可能导致缺乏关于参数在函数中的角色的上下文:
typescript
function redraw(allViews: boolean, inline: boolean) {
// redraw logic...
}
redraw(true, true);
此规则强制所有布尔参数需要使用"自文档化"的常量:
typescript
function redraw(allViews: boolean, inline: boolean) {
// redraw logic...
}
const ALL_VIEWS = true;
const INLINE = false;
redraw(ALL_VIEWS, INLINE);
感谢 Jorge Martin Juarez 实现了这一规则。
此规则默认禁用。你可以在 deno.json(c)
配置文件中启用它,如下所示:
json
{
"lint": {
"rules": {
"include": ["no-boolean-literal-for-arguments"]
}
}
}
测试运行时清理覆盖目录
Deno 的内置测试运行器新增了一个 --clean
标志,该标志将在运行测试套件前清空覆盖目录。这看似是个小改动,但解决了长期删除文件的覆盖数据仍然存在的问题。
shell
deno test --coverage --clean
请注意,此标志在并行或串行运行多个 deno test
命令并查看聚合的覆盖报告时会引发冲突。如果你在并行运行测试,则不应使用 --clean
标志。如果串行运行,应该只在第一个 deno test
调用中传递 --clean
标志。
为运行缓慢的测试打印反馈
我们注意到,长时间运行的测试可能会让人困惑,因为当没有输出时,无法判断测试运行器是否仍在工作:
shell
$ deno test slow_test.ts
Check file:///tmp/test_slow.ts
running 1 test from test_slow.ts
test ...
'test' has been running for over 1m0s
'test' has been running for over 2m0s
ok (2m10s)
ok | 1 passed | 0 failed (2m10s)
你可以使用 DENO_SLOW_TEST_TIMEOUT
环境变量来配置这些消息的间隔时间,该变量接受消息打印前经过的秒数。我们正在考虑为缓慢的测试添加硬超时,这将强制中止测试。我们希望听到你对此功能的反馈。
Deno.FsFile
稳定化
你不再需要使用 --unstable-fs
标志,这在包括 Next.js 在内的各种环境中经常引起问题。以下方法已经稳定:
这些稳定化消除了对不稳定标志的需求,使文件系统操作更加顺畅和可靠。通过纳入这些更改,API 现在支持在稳定的 Deno 运行时中直接进行基本的文件同步和锁定功能。这一改进对于确保数据完整性和有效处理并发文件操作特别有用。
FFI API 的变化
Deno 的 FFI API 允许你从 JavaScript 代码调用本地库。在 Deno 1.44 中,我们对这项功能进行了改进。
我们更新了从本地代码处理 u64
和 i64
类型的方式。之前,这些符号表示为 number | bigint
。从 v1.44 开始,它们始终是 bigint
类型。这一变化使 API 与 JavaScript 处理大整数的方式保持一致,确保更好的性能和类型一致性。虽然这是一个破坏性变化,但 API 仍不稳定,我们借此机会解决类型问题,随着 Deno.dlopen()
API 的稳定化推进 (#23981, #23983)。
这些更新是我们为 Deno 2 稳定 FFI API 所做的持续努力的一部分,确保它提供一个稳健一致的从 Deno 调用本地库的体验。
在 deno serve
中选择随机端口
在过去的一个月里,deno serve
命令被添加到 Deno 中。它允许你以声明式的方式编写服务器。我们注意到,在开发过程中经常希望服务器启动而不太在意它在哪个端口上运行。为此我们增加了对传递 --port 0
的支持,它返回由操作系统选择的随机空闲端口。
shell
$ deno serve --port 0 server.ts
deno serve: Listening on http://localhost:58333/
WebSocket
超时
Deno 对 WebSocket
API 具有保持连接活跃的 ping/pong
机制。不幸的是,默认的 120 秒超时对于许多流行的反向代理服务器(如 Nginx)来说太长了。这些服务器的默认超时通常为 60 秒。这导致与 Deno WebSocket 服务器的连接过早关闭。
ping/pong
消息的默认"空闲"超时已降低到 30 秒。此更改应使大多数 WebSocket 服务器更可靠,而无需手动干预。
感谢 Alex Gleason 实现了这一改动。
语言服务器改进
本月我们花了大量时间清理语言服务器,从而带来了多项性能改进和错误修复,具体包括:
- 为打开的文档添加语义标记缓存 (#23799)
- 重用"松散导入"解析器 (#23764)
- 将导入修复应用于缺失声明代码操作 (#23924)
- 修复命名示例中的 JSDoc 显示问题 (#23927)
- 为方法显示引用 CodeLens (#23804)
使用 DENO_FUTURE=1
试用 Deno 2 功能
我们继续发布将在 Deno 2 中生效的更改,你可以通过运行带有 DENO_FUTURE=1
环境变量的 Deno 来试用这些更改。
本次发布带来了以下更改:
deno install
现在处理将依赖项添加到deno.json(c)
和package.json
文件中,使 Node.js 项目迁移更容易。- 所有文件系统 API 均已稳定(不需要
--unstable-fs
标志) - WebGPU API 已稳定(不需要
--unstable-webgpu
标志) - FFI API 已稳定(不需要
--unstable-ffi
标志) deno install
正确设置node_modules/.bin/
条目用于带有二进制入口点的npm
包
致谢
没有社区的帮助,我们不可能构建 Deno!无论是在我们的社区 Discord 服务器 上回答问题,还是 报告错误,我们都非常感谢你的支持。特别感谢以下人员对 Deno 1.44 的贡献:Alex Gleason, Antoine du Hamel, Bedis Nbiba, charlotte ✨, chirsz, Evan, Felipe Baltor, futsuuu, Hajime-san, Hasan-Alrimawi, Kenta Moriuchi, Kyle Kelley, Luke Edwards, Mathias Lafeldt, Mattias Buelens, Mike Mulchrone, Milly, Simon Lecoq, Volker Schlecht。
想加入 Deno 贡献者的行列吗?查看我们的贡献文档,我们将在下次名单中看到你的名字。
相信与否,上述变更仍未涵盖 1.44 版本中所有的改进。你可以在 GitHub 上查看 Deno 1.44 中合并的完整拉取请求列表 点击这里。
感谢你关注我们的 1.44 版本发布,希望你喜欢使用 Deno 构建项目!