原文:Deno 官方博客
作者:Bartek Iwańczuk、Andy Jiang 2024 年 8 月 22 日
译者注:原文链接过多,已将大部分删除,有需要的读者请阅读原文
Deno 的目标是通过提供 原生 TypeScript 支持、一体化工具链、Web 标准 API 支持,以及 默认安全的代码执行 来提升 JavaScript 编写方式。
Deno 1.46(我们的最终 1.x 版本)继续朝着这一愿景迈进,通过 简化 CLI 的 更短的调用 和 简写的权限标志,实现 使用 deno serve --parallel 的多线程 Web 服务器,并添加了许多 Node.js/npm 兼容性改进(支持 playwright、@google-cloud、mysql2、pglite、ssh2 等)。
除了这些突出的更新,1.46 还提供了 更好的依赖管理,包括 deno remove 和 deno clean, deno compile 的代码签名 以提高软件的可移植性,以及 新增对 HTML、CSS、YAML 等的支持 的 deno fmt。
要升级到 Deno 1.46,请在终端中运行以下命令:
deno upgrade
如果尚未安装 Deno,请运行以下命令之一进行安装,或在此处学习如何安装。
curl -fsSL https://deno.land/install.sh | sh
iwr https://deno.land/install.ps1 -useb | iex
更简单的 CLI
此版本为 deno CLI 带来了重大更新。
更短的调用
此版本带来了长期请求和期待的变化,改变了运行 Deno 程序的方式。
deno 和 deno run 被修改为提供更符合人机工程学的常用任务方式。
现在,你可以仅用 deno 运行程序,而不必指定 run 子命令:
# Deno v1.45
deno run hello.ts
Hello world 🦕
# Deno v1.46
deno hello.ts
Hello world 🦕
你仍然可以将所有必要的标志传递给 deno 子命令:
# Deno v1.45
deno run --allow-read main.ts
Reading ./log.txt...
# Deno v1.46
deno --allow-read hello.ts
Reading ./log.txt...
另一个符合人机工程学的变化是能够使用 deno run 运行任务:
// deno.json
{
"tasks": {
"test": "deno test --allow-read --allow-net"
}
}
# Deno v1.45
deno task test
# Deno v1.46
deno run test
这可能是一个小变化,但肌肉记忆是实际存在的!对于有多年使用 npm run <script> 经验的用户,这应该是一个改变游戏规则的功能。
⚠️ 预 v1.45 行为仍然支持。 你仍然可以像以前一样使用
deno task和deno run。这些变化旨在使熟悉其他脚本环境的用户更容易过渡,这些环境默认执行第一个参数作为脚本。
简写权限标志
Deno 的权限系统是 Deno 提供的最重要的功能之一。--allow-* 和 --deny-* 标志用于限制对系统某些部分的访问。由于其冗长,很多用户选择使用 --allow-all 标志,或更准确地说是其简写 -A。
在 Deno v1.46 中,你现在可以享受大多数常用权限标志的一字母变体:
| 长格式 | 短格式 |
|---|---|
--allow-read | -R |
--allow-write | -W |
--allow-env | -E |
--allow-net | -N |
--allow-sys | -S |
这些简写标志与长格式一样接受允许列表 - 例如,-R=./static、-E=DEBUG,LOG、-N=deno.com。
如果你不想提供允许列表,可以将它们组合在一起 - 例如,-RWN 将启用 read、write 和 net 权限。
以下是一些缩短 CLI 调用的示例:
# Deno v1.45
deno run --allow-read=./static --allow-env --allow-net=myapi.example.com main.ts
# Deno v1.46
deno run -R=./static -E -N=myapi.example.com main.ts
# Deno v1.46 无需 `run` 子命令
deno -R=./static -E -N=myapi.example.com main.ts
# Deno v1.45
deno run --allow-read --allow-write --allow-env --allow-sys main.ts
# Deno v1.46
deno run -RWES main.ts
# Deno v1.46 无需 `run` 子命令
deno -RWES main.ts
新的帮助输出
CLI 选项标志现在被逻辑地分组到不同的类别中:
权限提示链接到文档
权限提示现在链接到相关权限标志的文档:
deno help <subcommand>
--allow-* 标志的帮助输出
权限标志的帮助文本已刷新,包括示例用法。
--env 重命名为 --env-file
--env 标志提供了“dotenv”功能,可以从指定文件中读取环境变量,并在 JavaScript 代码执行之前设置它们。这是非常方便的,所有流行的 JS 运行时都提供了此功能。为了与其他运行时对齐并简化迁移,--env 标志已重命名为 --env-file。旧标志将继续有效,但不会在帮助输出中显示。
新的进度条
一些反馈指出,Deno 有时似乎在下载依赖项时卡住了。实际上,问题有很多种 - 网络连接差、包注册表的速率限制等等。尽管如此,缺乏交互式的工作指示并没有帮助那些急于开始编码的用户。
为了明确表示 Deno 仍在工作,我们刷新了进度条以提供更多交互性。
Deno 1.45:掘金放不了视频
Deno v1.46:掘金放不了视频
deno check 和 deno cache 参数的 Glob 支持
Deno v1.34 添加了对配置文件和 CLI 标志中的 glob 的支持。这种 glob 功能自那时起已扩展到大多数 Deno 子命令,现在你可以在 deno check 和 deno cache 子命令中享受 glob 扩展。
⚠️ 确保将 glob 放在引号中。 否则,你的 shell 将展开它而不是 Deno,这可能导致由于 glob 实现差异而出现微妙的错误。
# 类型检查当前目录及其子目录中的所有 `.ts` 文件
deno check "*/**/*.ts"
# 缓存当前目录中的所有 JS 文件
deno cache "*.js"
更快的 deno serve
deno serve 在 Deno v1.43 中引入,并收到了很多积极的反馈。这个版本为deno serve带来了一些备受期待的变更。
1. 开发
通过添加 deno init --serve 选项,你可以在 10 秒内启动一个服务器。
示例项目包括使用 @std/http 的路由和集成的文件服务器,以实现高效的静态资产服务。
$ deno init --serve
$ deno serve -R main.ts
Listening on http://localhost:8000
$ curl http://localhost:8000/hello
这个子命令旨在成为一个快速原型制作工具,随着你的项目的发展,你可以对它进行扩展,并且并非旨在替代像 Fresh 这样的框架。
2. 类型检查
deno serve 的一个限制是正确设置入口文件的类型检查的复杂性。有了 Deno v1.46 和最新的 TypeScript 特性,现在这变得简单了:只需在入口文件的 default export 添加 satisfies Deno.ServeDefaultExport:
export default {
fetch(req) {
console.log(req.RequestDoesntHaveThisPropery);
return new Response("Hello world!");
},
} satisfies Deno.ServeDefaultExport;
如果你类型检查这个文件,Deno 会警告任何 API 兼容性问题:
$ deno check server.ts
Check file:///dev/server.ts
error: TS2339 [ERROR]: Property 'RequestDoesntHaveThisPropery' does not exist on type 'Request'.
console.log(req.RequestDoesntHaveThisPropery);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
at file:///dev/server.ts:3:21
注意:deno init --serve 会在你搭建新服务器项目时自动添加 satisfies Deno.ServeDefaultExport 到你的 deno serve 入口点。
3. 扩展
Deno.serve() API 为 deno serve 子命令提供动力,已经非常快速。但它默认只使用一个线程。这是有意义的,因为 JavaScript 是单线程语言,假设你没有使用像 new Worker() 这样的 API。但现代服务器有多个核心,应该利用这些核心以最有效地使用资源。
为了帮助你根据可用资源实现最佳性能,deno serve 现在支持一个 --parallel 标志,让你通过利用 CPU 的多个核心在多个线程上运行你的服务器:
$ deno serve --parallel main.ts
deno serve: Listening on http://0.0.0.0:8000 with 10 threads
你可以通过使用 DENO_JOBS 环境变量来指定要使用的线程数量。如果你没有指定这个变量,它将默认为你的机器提供的线程数量。例如,要将线程数量限制为 4,你可以运行:
$ DENO_JOBS=4 deno serve --parallel main.ts
deno serve: Listening on http://0.0.0.0:8000 with 4 threads
这里没有魔法 —— Deno 只是运行 X 份相同的服务器,保持每个线程为单线程 JavaScript 运行时。这使得你的应用程序状态的推理变得更简单,因为本地扩展的行为就像在云中扩展一样。
了解更多关于这个功能的工作方式,可以查看这个关于并行化 deno serve 的 Deno 演讲。
deno fmt 现在支持 HTML、CSS、YAML 等
这个版本为 Deno 的内置格式化程序 deno fmt 带来了重大升级。
deno fmt 现在可以用来格式化 HTML、CSS、SCSS、Sass、Less、YAML、Astro、Angular、Svelte 和 Vue 文件。
让我们格式化这个 HTML 文件:
// index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello `deno fmt`</title>
</head>
<body>
<h1>Hello <pre>
deno fmt!
</pre></h1>
</body></html>
$ deno fmt --unstable-html index.html
$ cat index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Hello `deno fmt`</title>
</head>
<body>
<h1>Hello <pre>
deno fmt!
</pre></h1>
</body>
</html>
由于这是 deno fmt 的一个重大变更,这些新格式的格式化目前是不稳定的。为了在 deno fmt 中启用这些新格式,需要传递 --unstable-* 标志或在 deno.json(c) 文件中添加选项。
请注意,当这些选项启用时,deno fmt 将自动拾取相应的文件。
使用 CLI:
# 格式化 HTML
$ deno fmt --unstable-html index.html
# 格式化 CSS/SCSS/Sass/Less
$ deno fmt --unstable-css styles.css
# 格式化 YAML
$ deno fmt --unstable-yaml config.yml
# 格式化组件文件
$ deno fmt --unstable-component App.vue App.svelte
使用配置文件:
// deno.json
{
"unstable": [
"fmt-html",
"fmt-css",
"fmt-yaml",
"fmt-component"
]
}
$ deno fmt index.html styles.css config.yml App.vue App.svelte
非常感谢 Pig Fang 提供这些格式化程序!
导入断言已弃用
Deno 在 v1 中引入了导入断言提案,允许你导入 JSON 文件:
import data from "./data.json" assert { type: "json" };
console.log(data);
从那时起,该提案经历了重大变化,包括将关键字从 assert 更新为 with,并被重命名为导入属性。
在 Deno 2 中,将不再支持导入断言。为了帮助你迁移到导入属性,从 Deno v1.46 开始,每次使用 assert 关键字时都会打印警告,应该用 with 关键字替换:
// data.json
{
"deno": "2"
}
$ deno run main.js
⚠️ Import assertions are deprecated. Use `with` keyword, instead of 'assert' keyword.
import data from "./data.json" assert { type: "json" };
at file:///dev/main.js:1:31
{ deno: "2" }
让我们将 assert 更改为 with:
import data from "./data.json" with { type: "json" };
console.log(data);
$ deno run main.js
{ deno: "2" }
依赖管理
Deno v1.46 带来了几个依赖管理的改进:
deno add 现在支持 dist 标签并建议使用 npm 包
现在可以使用 dist 标签添加 npm 依赖,例如使用 deno add npm:ajv@latest 来获取 ajv 包的 latest 标签。
此外,当你尝试添加一个仅在 npm 上可用的 JSR 包时,deno add 现在会提供一条有用的消息:
$ deno add ajv
error: jsr:ajv was not found, but a matching npm package exists. Did you mean `deno add npm:ajv`?
deno remove
由于一项普遍的请求,deno 现在有一个子命令,可以从你的配置和锁文件中移除依赖:
$ deno remove @std/assert @std/path
Removed @std/assert
Removed @std/path
请记住,这些包仍将保留在全局缓存中以备将来使用。如果你想完全清理你的环境,请查看 deno clean。
deno clean
Deno 有一个全局缓存,你可以使用 DENO_DIR 环境变量来控制。这个缓存用来存储远程依赖项以在多个项目中有效使用,用于更快启动的 V8 代码缓存,以及 deno fmt、deno lint 等子命令的缓存,以最大程度减少每次运行时的工作量。
你现在可以通过调用 deno clean 来快速清除整个缓存:视频演示
为 deno compile 添加代码签名
由 deno compile 生成的程序现在可以进行代码签名:
deno compile app.ts
# 在 macOS 上使用 `codesign` 工具
codesign --sign ./app
# 在 Windows 上使用 `signtool`
signtool sign /fd SHA256 .\app.exe
除此之外,为 Windows 编译的程序可以有一个自定义图标:
deno compile --icon=./icon.ico game.tsx
最后,调整了权限提示,以便在遇到缺少权限时提供更有用的错误信息:
console.log(Deno.readTextFileSync("./log.txt"));
# compile with no permissions
deno compile ./app.js
./app
Requires read access to ./log.txt, specify the required permissions during compilation using `deno compile --allow-read`
# compile again with suggested permissions
deno compile --allow-read ./app.js
./app
Hello world!
了解更多关于这个最新更新的信息,可以查看这个关于 deno compile 的 Deno 演讲。
deno publish 帮助确保包是许可的
为了确保包获得正确许可,deno publish 现在在发布包时需要一个license字段或文件。
> deno publish
error[missing-license]: missing license field or file
--> deno.json
= hint: add a "license" field. Alternatively, add a LICENSE file to the package and ensure it is not ignored from being published
docs: https://jsr.io/go/missing-license
error: Found 1 problem
要解决这个问题,向你的 deno.json 或 jsr.json 文件添加一个 "license" 字段。
{
"name": "@deno/add",
"version": "1.0.0",
"license": "MIT", // 添加这个或包含一个 LICENSE 文件
"exports": "./mod.ts"
}
deno upgrade 改进
deno upgrade 是一个方便的方式,用来保持 Deno 的最新状态,或Canary版本。
这个版本让它更加方便,一旦你升级到 Deno v1.46.0,你可以省略任何 CLI 标志,改为使用:
# 升级到最新的稳定版本
$ deno upgrade
# 升级到特定版本
$ deno upgrade v1.46.0
# 升级到最新的金丝雀版本
$ deno upgrade canary
# 升级到特定的发布版本
$ deno upgrade 526f39fbb9dacce12c69d24a55798d0bde8f2707
此外,我们添加了一个新的发布通道:发布候选(Release Candidate)通道。我们计划在发布 Deno 2 之前提供几个发布候选项。
你可以通过运行 deno upgrade rc 来试用它,但请记住目前只有 v1.46.0 的发布候选项可用。
Node.js 和 npm 兼容性
这个版本带来了 Deno 对 Node.js 和 npm 包的兼容性的许多改进。这个周期专注于让几个被强烈要求的流行包工作:
playwright现在在 Linux 和 macOS 上得到支持,这要归功于node:child_processAPI 中改进的管道支持- 许多
node:cryptoAPI 被重写,修复了许多错误并支持多个包(例如ssh2):- 添加了
CipherIv.setAutoPadding()修复了ethereum-cryptography - 现在可用的
crypto.diffieHellman crypto.randomFillSync()尊重偏移量- 加密密钥的处理已经彻底改革,增加了对 PKCS#1、PKCS#8、RSA-PSS、X25519、ED25519、DH 等密钥的支持
- 支持
ieee-p1363ECDSA 签名 crypto.createPublicKey()使用 PEM 私钥- ...
- 添加了
- 由于对
Http2Session.socket的支持,@google-cloud包现在得到支持 npm:bindings和npm:callsites包由于Error.prepareStackTraceAPI 的修复而正确工作fsevent模块现在得到支持vitest兼容性因以下原因而向前发展:- 现在可用的
node:inspector node:inspector#Session构造函数不会抛出异常
- 现在可用的
yoctocolors现在通过修复tty.WriteStream.hasColor并支持tty.hasColors()和tty.getColorDepth()正确工作util.debug现在得到支持chokidar由于 Windows 上的固定定位而更加可靠mongodb由于net.SocketAPI 的修复和另一个在node:http中的修复而更加稳定mysql2包现在得到支持node:vm接收了另一个重大改革size-limit由于node:zlib模块的更好覆盖而正确工作aws-sdk由于更好的子数组处理而更加可靠ecmarkup现在正确工作pglite现在完全支持grpc-js应该由于释放流容量而更加可靠paper-js或prismjs通过修复暴露给 npm 包的全局变量而得到更好的支持fs.exist和fs.existSync已经优化shelljs现在使用npm:指定符工作- 更好的
Buffer性能,当从字符串转换时
Node.js 和 npm 支持的其他变更包括:
.npmrc文件现在支持username和_password选项- 使用 Node.js global,而不导入它们会生成 lint 警告。提供免费的快速修复操作。
性能改进
Deno v1.46 带来了一些性能改进:
Deno.serve()API 现在快了 8-15%crypto.randomUUID()现在快了 5 倍Response.clone()快了 80%deno doc获得多项优化,以改善内存使用率
测试和覆盖率改进
这个版本为 deno test 和 deno coverage 带来了以下改进:
deno coverage --html现在显示面包屑导航,便于导航
deno test获得一个新的--hide-stacktraces标志,它将禁用在测试失败时打印错误堆栈跟踪deno test中的--allow-none标志已被重命名为--permit-no-files。我们打算在 Deno 2 中弃用旧标志,所以如果你依赖它,请确保更新你的脚本!
更简洁的冻结锁文件
在 Deno v1.46 中引入的冻结锁文件,是一种简单方便的方式,以确保当新的依赖项被添加到锁文件时,Deno 会报错。
这个版本通过在配置文件中指定以下内容,使每个人都能更容易地使用这个选项:
{
"lock": {
"frozen": true
}
}
每当更新将更改 lockfile 的依赖项时,Deno 都会抛出一个错误,要求你显式传递 --frozen=false 标志,这使得添加依赖项成为你有意识的决定。
此外,为了节省带宽和检查 git diff 所需的时间,lockfile格式在 Deno 2 中将变得更加简洁。
你今天就可以试用它,通过使用 DENO_FUTURE=1 环境变量。注意,切换回不使用 DENO_FUTURE 将需要重新生成锁文件。
文件监视器
在 Deno v1.38 中添加的热模块替换,现在在 --watch-hmr 标志下被认为是稳定的。它将显示在相关子命令的帮助输出中 --watch 标志旁边。
此外,deno test 得到了 --watch=<PATHS> 标志的支持,允许你传递其他要监视的文件路径,以触发重新运行测试。
Web API
Deno v1.46 带来了两个显著的 Web API 补充:
AsyncIterable<T>现在可以用来构造Request和Response类的主体。例如,node:fs中的createReadStream是一个实现AsyncIterable协议的 API,所以它可以像这样与fetchAPI 一起使用:
const file = createReadStream("./fixture.json");
const response = await fetch("http://example.com", {
method: "POST",
body: file,
});
Deno 现在将在数据变得可用时(从磁盘读取)流式传输数据,以实现高效的 HTTP 调用。
URLPatternAPI 现在支持ignoreCase和hasRegExpGroups。前者允许不区分大小写的模式匹配:
const pattern = new URLPattern({
pathname: "/foo/bar",
}, {
ignoreCase: true,
});
pattern.test("/foo/bar"); // true
pattern.test("/fOo/BaR"); // true
hasRegExpGroups 属性让你知道模式是否使用任何正则表达式组:
const pattern = new URLPattern({
pathname: "/foo/bar/(.+)",
});
pattern.hasRegExpGroups; // true
标准库稳定
Deno 标准库提供了一组从数据解析和操作、使用 Web 协议、以及一般实用程序的高质量包,这些包由核心团队审核,并保证与 Deno 兼容。
我们很高兴地宣布,我们已经完成了我们的稳定化过程,有 30 个包达到了 v1 或更高版本。
- std/assert
- std/async
- std/bytes
- std/cli
- std/collections
- std/crypto
- std/csv
- std/data-structures
- std/encoding
- std/expect
- std/fmt
- std/front-matter
- std/fs
- std/html
- std/http
- std/json
- std/jsonc
- std/media-types
- std/msgpack
- std/net
- std/path
- std/regexp
- std/semver
- std/streams
- std/testing
- std/text
- std/toml
- std/ulid
- std/uuid
- std/yaml
为了分享使用标准库模块可以完成的事情,我们发布了一个推文线程,每条推文都有一个模块的代码示例。
如果你想了解有关我们的标准库的更多信息,请查看我们短暂的 3 分钟视频。
V8 12.9
Deno 1.46 配备了最新的 V8 12.9。
致谢
没有我们社区的帮助,我们无法构建 Deno!无论是在我们社区 Discord 服务器回答问题,还是报告错误,我们都非常感谢你的支持。特别感谢下面这些人对 Deno 1.46 的贡献:Andreas Deininger、Bedis Nbiba、Birk Skyum、Hajime-san、HasanAlrimawi、Ian Bull、Igor Borisoglebski、Ivancing、Kenta Moriuchi、Kyle Kelley、MrEconomical、MujahedSafaa、Pig Fang、Rano | Ranadeep、Roy Ivy III、Sean McArthur、Yazan AbdAl-Rahman、Zebreus、chirsz、i-api、melbourne2991、seb、vwh,和 Łukasz Czerniawski。
你想加入 Deno 贡献者的行列吗?在这里查看我们的贡献文档,下次我们会在名单上见到你。
信不信由你,上面列出的更改仍然没有告诉你 1.46 中所有的改进。你可以在 GitHub 上查看合并到 Deno 1.46 的所有拉取请求的完整列表。
感谢你关注我们的 1.46 版本发布,我们希望你喜欢使用 Deno 构建!
接下来是什么?
🚨️ Deno 2 即将到来 🚨️
几天后,Deno 2 的第一个“发布候选版本”将被发布。
Deno 2 中有一些小的破坏性变更。
你可以使用 deno upgrade rc 来获取它,但你今天就可以添加
DENO_FUTURE=1 环境变量来为你的代码提供未来的保障。