Deno 1.39:WebGPU 回归
Deno 1.39 标志着 Deno 生态系统的一次重大更新,其中备受期待的 WebGPU 回归,增强了图形、游戏和机器学习功能。我们还引入了新的 deno coverage 报告器,以改进代码库分析,并在 Node.js 兼容性方面取得了长足进步,简化了 Node.js 开发人员的过渡。最后,此版本包括标准库更新、性能优化和最新的 TypeScript 5.3 支持。
如果您已经安装了 Deno,可以在终端中使用以下命令升级到 1.39 版本:
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.39 的新功能概述
- WebGPU 回归
- 新的
deno coverage
报告器 deno compile
更新- 增强型语言服务器
- Node.js 兼容性改进
Deno
API 变更- Web API 变更
- 标准库更新
- TypeScript 5.3
- 装饰器即将进行的更改
WebGPU 回归
WebGPU API 为开发者提供了一种低级别、高性能、跨架构的方式,通过 JavaScript 编程 GPU 硬件。它是 Web 上 WebGL 的有效继任者。该规范已最终确定,Chrome 也已发布该 API。Firefox 和 Safari 正在开发支持。
Deno 早在 2021 年初就首次引入了 WebGPU,但由于性能问题在今年早些时候被移除。在此版本中,我们很高兴能重新引入它,并且所有性能问题都已解决。
与 CPU 相比,GPU 能够以极高的并行度计算某些数值运算。这对于各种应用程序都很有用,而不仅仅是渲染和游戏。例如,机器学习算法通常可以表示为一系列矩阵运算,这些运算可以在 GPU 上极其高效地计算。
我们的 WebGPU 实现基于与 Firefox 即将推出的 WebGPU 实现相同的底层系统,因此我们相信它为开发者提供了一个坚实的基础。
通过 WebGPU 获取 GPU 信息的简单示例
// 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.
const adapterInfo = await adapter.requestAdapterInfo();
console.log(`Found adapter: ${adapterInfo.device}`); // On some systems this will be blank
const features = [...adapter.features.values()];
console.log(`Supported features: ${features.join(", ")}`);
} else {
console.error("No adapter found");
}
更多示例可在我们的 webgpu-examples 仓库中查看。
尽管规范是稳定的,但 WebGPU 在 Deno 中仍被视为不稳定功能。要在 Deno 中访问它,请使用 `--unstable-webgpu` 标志。我们计划在有机会从社区获得更多反馈并有更多时间根据规范测试套件验证实现后,尽快将其稳定。
为了提供更多 WebGPU 功能,我们还添加了 std/webgpu
(更多信息见下文)。
感谢 wgpu 团队为实现此目标提供的帮助。
deno coverage
报告器
新的 在此版本中,`deno coverage` 获得了两个新的报告器:`summary` 和 `html`。现在您还可以省略 `deno test` 中 `--coverage` 标志的目录值,因为我们现在默认使用 `./coverage/` 目录。
summary
报告器是新的默认报告器。它以简洁的表格输出覆盖率摘要,为您提供特定文件和整体摘要的覆盖率信息。
$ deno coverage
----------------------------------
File | Branch % | Line % |
----------------------------------
bar.ts | 0.0 | 57.1 |
baz/quux.ts | 0.0 | 28.6 |
baz/qux.ts | 100.0 | 100.0 |
foo.ts | 50.0 | 76.9 |
----------------------------------
All files | 40.0 | 61.0 |
----------------------------------
以前默认的报告器,它将所有文件中未覆盖的行打印到终端,现在仍可通过使用 `--detailed` 标志获得。
您还可以指定 `--html` 标志以获取 HTML 格式的详细覆盖率报告。
$ deno test --coverage
$ deno coverage --html
HTML coverage report has been generated at file:///path/to/project/coverage/html/index.html
覆盖率报告示例如下
deno coverage --html
的输出完全是静态的,可以托管在任何静态文件服务器上,例如 GitHub Pages。
我们仍然支持 `--lcov` 标志,它以 LCOV 格式输出覆盖率报告,这对于与 Codecov 或 Coveralls 等其他工具集成非常有用。
我们有进一步的计划来改进 deno coverage
并使其更有用。如果您有任何反馈,请在此问题上发表评论。
deno compile
更新
Deno 1.39 在 deno compile
功能方面引入了重大进展
更好的 node_modules
支持:通过 `--unstable-byonm` 标志,`deno compile` 现在支持“自带 node_modules”,从而增强了 Node.js 兼容性。此功能允许您直接在 Deno 项目中使用 npm 包,弥合了 Deno 与庞大 npm 生态系统之间的差距。在我们之前的博客文章中了解有关此功能的更多信息。
可执行文件的灵活命名:Deno 已取消对可执行文件命名的限制。您现在可以使用前导数字命名已编译的程序,例如 3d_modeler
,在命名约定方面提供了更大的灵活性。
更多动态导入支持:deno compile
现在支持更多动态导入模式。这很有趣,因为 Deno 需要在 `deno compile` 生成的二进制文件中静态包含所有可能在运行时导入的模块。因此,动态导入可能会出现问题。现在,Deno 可以处理更多动态导入模式,例如:
await import(`./dir/${expr}`);
在此示例中,Deno 将把 ./dir/
及其子目录中的所有模块包含到编译后的二进制文件中。这允许您在运行时导入这些文件中的任何一个。此更新通过确保所有动态引用的模块在运行时可用,从而简化了依赖管理。
增强型语言服务器
在我们不断致力于改进 Deno 语言服务器 (LSP) 的过程中,此版本引入了显著的性能增强。
响应式输入体验:我们优化了快速输入时处理快速请求突发的能力,确保在您的 IDE 中获得更流畅、更响应的编辑体验。
关闭超时:为了解决 LSP 实例“僵尸”进程滞留的问题,我们实现了关闭超时机制。此功能会在您关闭编辑器并在设定的超时后强制终止 LSP 进程,从而促进资源的高效利用。
更新通知:语言服务器现在会主动通知您最新的 Deno 更新。此功能旨在简化 Deno 安装的更新过程,确保您始终可以使用最新的功能和修复。
增强诊断:我们在 VSCode 中引入了一个新的 deno.logFile
设置。当与 deno.internalDebug
一起使用时,此功能允许捕获详细的诊断数据,有助于性能分析和故障排除。
我们致力于不断增强 Deno LSP。如果您在使用 LSP 或 VSCode Deno 中遇到任何性能问题,您的反馈将非常宝贵。请在此处告诉我们您的体验。
Node.js 兼容性改进
宽松导入
将现有 TypeScript 代码库迁移到 Deno 可能是一项艰巨的任务。最大的障碍之一是 Deno 要求您在导入语句中明确指定文件扩展名。
想象一个 TypeScript 项目,其中有一个文件 foo.ts
导入了 bar.ts
// foo.ts
import { Example } from "./bar";
console.log(Example);
// bar.ts
export const Example = "Example";
在 Deno 的早期版本中,这会报错并显示一条无用的消息
# Deno v1.38.5
$ deno run foo.ts
error: Module not found "file:///dev/bar"
at file:///dev/foo.ts:1:25
现在在 Deno 1.39 中,此错误消息得到了改进,并提供了一个备用方案
# Deno v1.39.0
$ deno run foo.ts
error: Module not found "file:///dev/bar". Maybe add a '.ts' extension or run with --unstable-sloppy-imports
at file:///dev/foo.ts:1:25
使用 `--unstable-sloppy-imports` 标志运行将无需任何更改即可执行代码
# Deno v1.39.0
$ deno run --unstable-sloppy-imports foo.ts
Warning Sloppy imports are not recommended and have a negative impact on performance.
Warning Sloppy module resolution (hint: add .ts extension)
at file:///dev/foo.ts:1:25
Example
除了解析没有文件扩展名的导入之外,此功能还允许解析“目录”导入,以及使用 `.js` 扩展名导入 `.ts` 文件
// routes/index.ts
export default {
"/": () => "Hello World",
"/example": () => "Example",
};
// bar.ts
export const bar = "bar";
// foo.ts
import routes from "./routes";
import { bar } from "./bar.js";
console.log(routes);
console.log(bar);
$ deno run --unstable-sloppy-imports foo.ts
Warning Sloppy imports are not recommended and have a negative impact on performance.
Warning Sloppy module resolution (hint: specify path to index.ts file in directory instead)
at file:///Users/ib/dev/deno/foo.ts:1:20
Warning Sloppy module resolution (hint: update .js extension to .ts)
at file:///Users/ib/dev/deno/foo.ts:2:21
{ "/": [Function: /], "/example": [Function: /example] }
bar
如上所示,使用此标志将打印警告,指导您将代码迁移到推荐的导入语法。您还将在编辑器中获得诊断信息,以及“快速修复”,这将使应用必要的更改变得更容易。
我们希望此功能将使尝试和迁移现有项目到 Deno 变得更加容易。
deno task
中运行 node_modules/.bin/
可执行文件
支持在 deno task
可以运行 deno.json
中定义的任务,以及 package.json
中定义的 scripts
。此版本增加了在 deno task
中运行 node_modules/.bin/
目录中可执行文件的支持。
如果您的 package.json
看起来像这样:
{
"scripts": {
"dev": "vite dev"
}
}
您可以使用 deno task
运行 vite dev
$ deno task dev
Deno 将在 node_modules/.bin/
目录中查找 vite
可执行文件并使用 Deno 运行它——即使 node_modules/.bin/vite
使用 shebang 定义 Node.js 作为解释器。
node_modules
中的 CommonJS 入口点
Deno 现在将正确处理 node_modules
中的 CommonJS 入口点,尊重相关包的 package.json
中的 type
设置。这应该会大大提高与尚未迁移到 ESM 的包的兼容性。
Object.prototype.__proto__
支持 出于安全原因,Deno 曾有意识地决定不支持 Object.prototype.__proto__
。然而,npm 上仍有许多包依赖此属性才能正常工作。
在此版本中,我们引入了一个新的 `--unstable-unsafe-proto` 标志,允许您启用此属性。不建议使用此标志,但如果您确实需要使用依赖它的包,现在可以使用此备用方案了。
Node.js API 更新
以下 Node.js API 现已可用
crypto.createPrivateKey
http.ClientRequest.setTimeout
http.globalAgent
perf_hooks.performance
process.geteuid
process.report
util.parseArgs
vm.runInNewContext
此外,我们还修复了已支持的 Node.js API 中的几个错误:
child_process.spawnSync
对status
的处理不正确child_process.spawnSync
正确规范化stdio
child_process
可以在 Unix 系统上处理 IPC 管道(Windows 支持即将推出)crypto.sign
现在支持 PEM 私钥- 当文件不存在时,
fs.existsSync
现在更快 process.exitCode
应该改变进程的退出码- 允许
http.OutgoingMessage.setHeader
的null
值 - 修复当
sourceStart
>source.length
时的Buffer.copy
- 修复
os.freemem
- 修复
stream.Writable
- 处理多次关闭
process.stdin
Deno
API 更改
此版本包含对 Deno
API 的多项更改
Deno.serve()
对 Unix 套接字的支持现已稳定
Deno.serve(
{ transport: "unix", address: "/tmp/my.sock" },
(req) => new Response("Hello!"),
);
Deno.HttpServer.shutdown()
现已稳定
const server = Deno.serve((req) => new Response("Hello!"));
// Shutdown the server gracefully when the process is interrupted.
Deno.addSignalListener("SIGINT", () => {
server.shutdown();
});
await server.finished;
Deno.HttpClient
现在可以使用 using
关键字声明
继“显式资源管理”在上一个版本中引入到 Deno
API 之后,此版本为 Deno.HttpClient
带来了对 using
关键字的支持。
{
using client = Deno.createHttpClient({});
const response = await fetch("http://localhost:4545/assets/fixture.json", {
client,
});
const json = await response.json();
}
// `client` is closed here
KV 监视
新的、不稳定的 Deno.Kv.watch()
API 用于监视给定数据库中给定键的变化。此 API 返回一个 ReadableStream
,每当任何被监视的键更改其版本戳时,它都会发出一个新值。发出的值是一个 Deno.KvEntryMaybe
对象数组,其长度和顺序与 keys
数组相同。在此处阅读有关 KV 监视功能的更多信息。
const db = await Deno.openKv();
const stream = db.watch([["foo"], ["bar"]]);
for await (const entries of stream) {
entries[0].key; // ["foo"]
entries[0].value; // "bar"
entries[0].versionstamp; // "00000000000000010000"
entries[1].key; // ["bar"]
entries[1].value; // null
entries[1].versionstamp; // null
}
Cron
最近引入的 Deno.cron
函数在此版本中迎来了激动人心的更新。它现在支持直观的 JSON 格式来定义计划,使 cron 任务更易于理解和实现。有关更深入的信息,请查阅我们关于 cron 功能的详细博客文章。
传统 Unix Cron 格式
以前,设置每 20 分钟运行一次的任务需要使用 Unix cron 格式
Deno.cron("myCron", "*/20 * * * *", () => {
console.log("Running every 20 minutes");
});
新 JSON 格式
现在,您可以使用更具可读性的 JSON 格式实现相同的功能
Deno.cron("myCron", {
minutes: { every: 20 },
}, () => {
console.log("Running every 20 minutes");
});
已弃用的 IO 接口
我们已经推动 Deno
API 使用 Web Streams API 几个月了,为了最终确定这一更改,v1.39 版本带来了对 Deno 中各种 IO 接口的弃用。
以下接口现已弃用,并计划在 Deno 2 中移除:
Deno.Reader
Deno.ReaderSync
Deno.Writer
Deno.WriterSync
Deno.Closer
现在,当您使用这些接口时,您的编辑器中将收到警告,并建议您改用 Web Streams API。
Web API 更改
AbortSignal.any()
此 API 允许监听多个 AbortSignals
,并且如果任何指定的信号被中止,它将中止。
如果您有一个提供 AbortSignal
的 API(例如,Request
),并且您想额外依赖另一个 AbortSignal
,这会很有用。
ImageData
ImageData
Web API 是一个类,可用于以标准化格式表示图像。
快速创建一个 1x2 像素红色图像的示例
const rawImage = new Uint8ClampedArray([255, 0, 0, 1, 255, 0, 0, 1]);
new ImageData(rawImage, 1, 2);
感谢 @jamsinclair
贡献此功能。
ReadableStream.read
的 min
选项
ReadableStreamBYOBReader.read
的 min
选项允许指定要读取的最小字节数。这对于各种需要读取 n 字节的编码格式非常有用,可以通过将 min
选项设置为与缓冲区字节长度相同来实现。
例如
const response = await fetch("https://example.com");
const reader = response.body!.getReader({ mode: "byob" });
const buffer = new Uint8Array(10);
// value will contain at least 5 bytes written to it
const { value } = await reader.read(buffer, { min: 5 });
URLPattern
性能
改进 URLPattern
API 获得了性能改进,使其在匹配多个模式时速度提高了 6 到 8 倍,这是针对在 HTTP 路由器中使用 URLPattern
的常见场景进行的优化。
标准库更新
std/webgpu
除了在 CLI 中发布 WebGPU 之外,我们还在本次发布中添加了 std/webgpu
。
此模块添加了一些额外的功能,包括用于使用现有数据创建 GPUTexture
的 createTextureWithData
、用于获取纹理格式信息的 describeTextureFormat
,以及用于使用纹理进行“捕获”的 createCapture
等。
其中一些功能已移植自 wgpu
功能或基于其开发,未来还将计划更多功能。
std/expect
在此版本中,已添加 std/expect
。该模块导出两个函数:expect
和 fn
。它们旨在与 Jest 兼容。
import { expect } from "https://deno.land/std@0.209.0/expect/mod.ts";
expect(Math.max(5, 8)).not.toEqual(5);
expect(Math.max(5, 8)).toEqual(8);
expect(Math.pow(3, 5)).toBeGreaterThan(100);
expect(Math.pow(3, 5)).toBeLessThan(300);
目前,expect
支持以下匹配器和修饰符 API:not
、resolves
、rejects
、toBe
、toEqual
、toStrictEqual
、toMatch
、toMatchObject
、toBeDefined
、toBeUndefined
、toBeNull
、toBeNaN
、toBeTruthy
、toBeFalsy
、toContain
、toContainEqual
、toHaveLength
、toBeGreaterThan
、toBeGreaterThanOrEqual
、toBeLessThan
、toBeLessThanOrEqual
、toBeCloseTo
、toBeInstanceOf
、toThrow
、toHaveProperty
、toHaveLength
。
该模块还提供了与 mock 相关的实用工具和断言
import { expect, fn } from "https://deno.land/std@0.209.0/expect/mod.ts";
const mockFn = fn();
mockFn();
mockFn();
mockFn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn).not.toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledTimes(3);
已实现以下与 mock 相关的匹配器:toHaveBeenCalled
、toHaveBeenCalledTimes
、toHaveBeenCalledWith
、toHaveBeenLastCalledWith
、toHaveBeenNthCalledWith
、toHaveReturned
、toHaveReturnedTimes
、toHaveReturnedWith
、toHaveLastReturnedWith
、toHaveNthReturnedWith
。
该模块与 Jest 的 expect
API 并非完全兼容。以下 API 尚未实现:toMatchSnapShot
、toMatchInlineSnapShot
、toThrowErrorMatchingSnapShot
、toThrowErrorMatchingInlineSnapShot
、expect.anything
、expect.any
、expect.arrayContaining
、expect.not.arrayContaining
、expect.closedTo
、expect.objectContaining
、expect.not.objectContaining
、expect.stringContaining
、expect.not.stringContaining
、expect.stringMatching
、expect.not.stringMatching
、expect.assertions
、expect.hasAssertions
、expect.addEqualityTester
、expect.addSnapshotSerializer
、expect.extend
。
标准库还包含 std/testing/bdd
模块。现在您可以使用标准库以 BDD 风格编写测试用例。
import { describe, it } from "https://deno.land/std@0.209.0/testing/bdd.ts";
import { expect } from "https://deno.land/std@0.209.0/expect/mod.ts";
describe("Math", () => {
describe("max", () => {
it("returns max value from the given args", () => {
expect(Math.max(1, 2, 3)).toEqual(3);
expect(Math.max(-3, -2, -1)).toEqual(-1);
});
});
});
将此文件保存为 my_test.ts
,然后您可以使用以下命令执行它:
$ deno test my_test.ts
Check file:///path/to/my_test.ts
running 1 test from ./my_test.ts
Math ...
max ...
returns max value from the given args ... ok (1ms)
max ... ok (1ms)
Math ... ok (1ms)
ok | 1 passed (2 steps) | 0 failed (1ms)
感谢 Thomas Cruveilher 贡献此功能。
std/ini
在此版本中,已添加 std/ini
。该模块提供了用于处理 INI 文件的解析器和序列化器。
感谢 Aaron Huggins 贡献此功能。
std/data_structures
此版本中已添加 std/data_structures
。此模块导出实现数据结构算法的类。目前提供了 RedBlackTree
、BinarySearchTree
和 BinaryHeap
类。
std/text
此版本中已添加 std/text
。此模块导出用于根据特定标准比较/排序/选择文本的实用函数。
import {
closestString,
levenshteinDistance,
} from "https://deno.land/std@0.209.0/text/mod.ts";
// Calculates levenshtein distance of 2 words
console.log(levenshteinDistance("hello", "halo")); // => prints 2
console.log(levenshteinDistance("hello", "world")); // => prints 4
console.log(closestString("puhs", ["commit", "pull", "push"])); // => prints "push"
感谢 Jeff Hykin 贡献这些功能。
std/cli
此版本中已添加 std/cli
。此模块目前导出两个 API:parseArgs
和 promptSecret
。
import {
parseArgs,
promptSecret,
} from "https://deno.land/std@0.209.0/cli/mod.ts";
const parsedArgs = parseArgs(["--foo", "--bar=baz", "./quux.txt"]);
console.log(parsedArgs);
// prints: { foo: true, bar: "baz", _: ["./quux.txt"] }
// This is typically used as `parseArgs(Deno.args)`
const credential = promptSecret("Enter the credential ");
// This asks for the credential in the terminal and the user inputs are masked with '*'
注意:parseArgs
与 std/flags
中的 parse
相同,但我们意识到 std/flags
的范围过于有限,因此决定在 std/cli
下探索更多 CLI 相关功能。
感谢 Alisue 提出并实现了 promptSecret
。
std/net
此版本中已添加 std/net
。此模块导出一个 API:getAvailablePort
,它对于选择可用 TCP 端口很有用。
import { getAvailablePort } from "https://deno.land/std@0.209.0/net/mod.ts";
const port = await getAvailablePort();
感谢 Harry Solovay 贡献此功能。
TypeScript 5.3
Deno v1.39 附带最新发布的 TypeScript 5.3,详情请参阅“Announcing TypeScript 5.3”博客文章。
装饰器即将进行的更改
目前,Deno 默认启用实验性 TypeScript 装饰器。由于TC39 装饰器提案已达到 Stage 3 阶段,并且有广泛的需求,我们决定在即将发布的 Deno v1.40 版本中更改装饰器的默认设置。
在下一个版本中,实验性 TypeScript 装饰器将默认禁用,而 TC39 装饰器将默认启用。
如果您正在使用实验性 TS 装饰器,请通过将此配置添加到您的 deno.json
来为这一更改做好准备:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
感谢我们的贡献者!
没有社区的帮助,我们无法构建 Deno!无论是通过在我们的社区 Discord 服务器中回答问题,还是报告错误,我们都非常感谢您的支持。特别是,我们要感谢以下人员对 Deno 1.39 的贡献:Aravind、Birk Skyum、Bolat Azamat、Chen Su、Daniel Mizerski、Florian Schwalm、Gasman、Ian Bull、Jacob Hummer、Jakub Jirutka、Jamie、Jesse Jackson、John Spurlock、Jordan Harband、Julien Cayzac、Jérôme Benoit、Kenta Moriuchi、Laurence Rowe、Max Goodhart、Raashid Anwar、Tareque Md Hanif、btoo、citrusmunch、lionel-rowe、liruifengv、pk、scarf、ud2 和林炳权。
您想加入 Deno 贡献者的行列吗?在此处查看我们的贡献文档,下次再见!
信不信由你,上面列出的更改仍然没有告诉您 1.39 中所有改进的地方。您可以在 GitHub 上此处查看 Deno 1.39 中合并的完整拉取请求列表。
感谢您关注我们的 1.39 版本发布,希望您喜欢使用 Deno 进行构建!
🍋 Fresh 1.6 已发布。
Fresh v1.6 应用程序扩展了插件 API,实现了更快的路由匹配,并正式支持 Tailwind CSS。