Deno 1.39:WebGPU 的回归
Deno 1.39 是 Deno 生态系统的一次重大更新,它包含了备受期待的 WebGPU 的回归,增强了图形、游戏和机器学习功能。我们还引入了新的 deno 覆盖率报告程序,以改善代码库分析,并在 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 正在努力支持该 API。
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
使用定义 Node.js 作为解释器的 shebang。
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
应该更改进程的退出代码- 允许
null
值用于http.OutgoingMessage.setHeader
- 修复
Buffer.copy
当sourceStart
>source.length
时 - 修复
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("https://127.0.0.1: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 倍,这是一个针对使用 URLPattern
的常见场景进行的优化,即在 HTTP 路由器中使用 URLPattern
。
标准库更新
std/webgpu
除了在 CLI 中发布 WebGPU 外,我们还在此版本中添加了 std/webgpu
。
此模块添加了一些额外的功能,包括 createTextureWithData
用于创建带有现有数据的 GPUTexture
,describeTextureFormat
用于获取有关纹理格式的信息,以及 createCapture
用于使用纹理进行“捕获”,等等。
其中一些功能已移植/基于 wgpu
功能,并且正在计划进一步的功能。
std/expect
在此版本中,添加了 std/expect
。该模块导出两个函数:expect
和 fn
。这些函数旨在与 Jest 兼容。
import { expect } from "https://deno.land/[email protected]/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
。
该模块还提供与模拟相关的实用程序和断言
import { expect, fn } from "https://deno.land/[email protected]/expect/mod.ts";
const mockFn = fn();
mockFn();
mockFn();
mockFn();
expect(mockFn).toHaveBeenCalled();
expect(mockFn).not.toHaveBeenCalledTimes(1);
expect(mockFn).toHaveBeenCalledTimes(3);
已实现以下与模拟相关的匹配器: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/[email protected]/testing/bdd.ts";
import { expect } from "https://deno.land/[email protected]/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/[email protected]/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
已在此版本中添加。此模块目前导出 2 个 API:parseArgs
和 promptSecret
。
import {
parseArgs,
promptSecret,
} from "https://deno.land/[email protected]/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
已在此版本中添加。此模块导出 1 个 API:getAvailablePort
,它对于选择可用的 TCP 端口很有用。
import { getAvailablePort } from "https://deno.land/[email protected]/net/mod.ts";
const port = await getAvailablePort();
感谢 Harry Solovay 为此功能做出的贡献。
TypeScript 5.3
Deno v1.39 附带最新版本的 TypeScript 5.3,请在 宣布 TypeScript 5.3 博客文章中了解更多信息。
装饰器的即将发布的更改
目前,Deno 默认启用 实验性 TypeScript 装饰器。由于 TC39 装饰器提案 处于第 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 支持。