Deno 1.44:私有 npm 注册表、改进的 Node.js 兼容性和性能提升

原文: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 传递给 Node worker_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
  • 修复默认状态代码属性未初始化为 200ServerResponse。这使 11ty 开发服务器能够工作。
  • 修复 node:process 中缺少的 geteuid
  • 修复在 gRPC 中流未标记为取消的问题。这使流示例能够工作。
  • 修复发出 response 事件时发出的错误标志。这修复了 gRPC 中的错误传播问题。
  • 允许通过 delete 关键字删除 process.env 值。这种模式有时在集成测试中使用。
  • 为每个 worker_thread 使用单独的模块缓存。解决了这个问题后,SvelteKit 现在能够工作。
  • 修复 CommonJS 的罕见再导出错误,这是在使用 @solana/spl-governance npm 包时发现的。
  • 修复 napi_get_elementnapi_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 规范 最近更新,在 RequestResponse 类中增加了新的 .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 在内的各种环境中经常引起问题。以下方法已经稳定:

  • Deno.FsFile.syncDataDeno.FsFile.sync (#23733)
  • Deno.FsFile.unlockDeno.FsFile.lock(#23754)

这些稳定化消除了对不稳定标志的需求,使文件系统操作更加顺畅和可靠。通过纳入这些更改,API 现在支持在稳定的 Deno 运行时中直接进行基本的文件同步和锁定功能。这一改进对于确保数据完整性和有效处理并发文件操作特别有用。

FFI API 的变化

Deno 的 FFI API 允许你从 JavaScript 代码调用本地库。在 Deno 1.44 中,我们对这项功能进行了改进。

我们更新了从本地代码处理 u64i64 类型的方式。之前,这些符号表示为 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 构建项目!

相关推荐
懒大王爱吃狼39 分钟前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
逐·風5 小时前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫5 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦6 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子6 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山7 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享7 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
清灵xmf9 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询
大佩梨9 小时前
VUE+Vite之环境文件配置及使用环境变量
前端
GDAL9 小时前
npm入门教程1:npm简介
前端·npm·node.js