Deno 1.45:工作区和 Monorepo 支持
Deno 1.45 发布,Deno 持续进化。此版本最突出的功能是引入了工作区(workspaces),为管理单体仓库(monorepos)提供了强大的解决方案。这一新增功能简化了大型代码库的依赖管理、配置共享和模块组织。除了工作区,本次更新还包括对 Node.js 兼容性的改进、`deno install` 的更新、新的 `deno init --lib` 命令、`deno vendor` 的废弃,以及更多。
要升级到 Deno 1.45,请在终端中运行以下命令
deno upgrade
如果 Deno 尚未安装,请运行以下命令之一进行安装或在此处了解如何安装。
# 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
Deno 1.45 中的新特性
- 工作区支持
- Node.js 兼容性改进
- 冻结锁文件
- `deno install` 更新
deno init --lib
- `deno vendor` 现已废弃
- `deno test` 文件发现
- Jupyter notebook 改进
- `deno compile` 支持 `--env` 标志
- 更灵活的语言服务器
- 标准库更接近稳定版
- V8 12.7 和 TypeScript 5.5.2
- 使用
DENO_FUTURE=1
尝试 Deno 2 功能 - 致谢
工作区支持
Deno v1.45 新增了对工作区和单体仓库的支持。目前支持两种形式的工作区:在 `deno.json` 中定义的 Deno 优先工作区和向后兼容的 npm 工作区。
Deno 工作区使用起来很简单。全局定义的配置会应用于每个成员包,但可以被成员覆盖。你可以混合使用 npm 和 Deno 工作区——Deno 工作区内的 npm 包,或反之。
将工作区成员发布到 JSR 就像运行 `deno publish` 一样简单。标准库是有效使用工作区的一个很好的例子。
要开始使用,请在 `deno.json` 中定义一个 `"workspace"` 元素,并列出成员目录。
{
"workspace": ["./add", "./subtract"]
}
`npm` 工作区在 Deno 中也能无缝工作。无论你是在更大的 npm 工作区中包含 Deno 库,还是在更大的 Deno 工作区中包含 npm 库,依赖都将正确解析。
要了解更多关于工作区支持的信息,请访问 Deno 文档。
我们还将于太平洋时间(UTC-7)7月16日星期二上午9点在 YouTube 上举办一场一小时的直播,详细介绍我们的新工作区支持并回答您的问题。在此处报名。
Node.js 兼容性改进
Node-API 支持已全面改进,修复了 `prisma`、`sqlite3`、`paper`、`duckdb`、`nodejs-polars` 等软件包的许多现有问题。
其他 Node.js 兼容性改进包括
我们正在努力支持 dd-trace。虽然尚未完全实现,但我们正通过以下方式逐渐接近:
- 新增了 `net.BlockList` 和 `net.SocketAddress`
- 为 `node:diagnostics_channel` 模块添加了缺失的 API
- 支持 `Module.parent`
`fs.lutimes` 和 `fs.lutimesSync` 现已支持,同时支持 [ `fs.lchown` 和 `process.getegid` ] (https://github.com/denoland/deno/pull/24418)
新增了 `node:crypto` 和 `node:zlib` 常量
在 `node:fs` 中,现已提供 `Dirent.path` 和 `Dirent.parentPath`
`node:http` 模块获得了重大更新
- `Server#close()` 现在可以优雅地关闭,允许正在处理的请求完成
- 新增了 `ServerResponse#appendHeader()`
- 所有 `ServerResponse#writeHead()` 签名现已支持
- `ServerResponse#setHeaders` 现在可以处理头数组
- `ServerResponse` 正确处理分块写入
- `ServerResponse` 在流式传输时不会使进程崩溃
- 如果 `Server` 尚未开始监听,则 `address` 返回 `null`
- `ClientRequest` 现在能正确发送请求
`node:vm` 将消耗更少的内存
`crypto.Hash` 实现已重新设计
`@grpc/grpc-js` 支持现在更稳健,正确设置了 `end_stream` 标志
`node:child_process` API 现在支持 `stdio` 选项的 `"ipc"` 值
`readline/promises` 模块现在在 ES 模块中可用
此外,还有其他与 npm 支持相关的改进
- Deno 将发现放置在您主目录中的 `.npmrc` 配置文件,以更好地支持私有注册表
- 软件包附带的类型现在优先于 `@types` 范围的类型
- Deno 现在支持更多形式的 SemVer 约束
冻结锁文件
已新增一个 `--frozen`(别名为 `--frozen-lockfile`)标志,用于控制锁文件的行为。
您可以使用此标志,在锁文件过时时让 Deno 报错。这在 CI 流水线中特别有用,您可以确保所有推送的代码都是最新的,并且依赖项没有新的或意外的更改。
当使用 `--frozen` 标志运行 Deno 命令时,任何尝试使用新内容更新锁文件的操作都将导致命令退出并显示错误,其中包含本应进行的修改。
例如,假设您的项目中某个地方导入了 `npm:chalk@5.3.0`。后来,有人从一个稍旧的、只知道 chalk 5.2.0 版本的 AI 聊天机器人那里复制了一段代码,导致文件中出现了类似的导入:
import chalk from "npm:chalk@5.2.0";
幸运的是,您的 CI 流水线中有一个指定了 `--frozen` 的测试步骤
deno test --frozen --coverage
它不会默默地将第二个(过时的)chalk 版本添加到您的依赖树中,而是会失败并显示 chalk 5.3.0 本应被添加到您的锁文件中。
error: The lockfile is out of date. Run `deno cache --frozen=false` or rerun with `--frozen=false` to update it.
changes:
5 | - "npm:chalk@5.3.0": "npm:chalk@5.3.0"
6 | - },
7 | - "npm": {
5 | + "npm:chalk@5.2.0": "npm:chalk@5.2.0",
6 | + "npm:chalk@5.3.0": "npm:chalk@5.3.0"
7 | + },
8 | + "npm": {
9 | + "chalk@5.2.0": {
10 | + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==",
11 | + "dependencies": {}
12 | + },
如果您打算明确更新锁文件,可以指定 `--frozen=false`,这将更新锁文件而不会出错。
有了上述设置,每次依赖更新都需要使用 `--frozen=false` 标志运行命令或任务,从而使这些更新变得有意和明确。
最后,`--lock-write` 现已废弃,并将在 Deno 2 中移除。您可以用 `--frozen=false` 替换 `--lock-write` 的用法。
`deno install` 更新
在 Deno 2 中,`deno install` 子命令的行为将更像 `npm install`,以支持常见的工作流程。目前在 Deno 中,`deno install
要在您的项目中试用新的安装命令,请使用 `DENO_FUTURE=1` 运行
DENO_FUTURE=1 deno install
带参数,例如 `deno add`
DENO_FUTURE=1 deno install @david/dax
我们鼓励您试用新的 `deno install` 并报告您遇到的任何问题!
npm 生命周期脚本支持
`package.json` 中的某些脚本很特殊,它们会在特定的操作中由 npm 自动执行。npm 支持许多生命周期脚本,但作为包的使用者,主要相关的脚本是安装前/安装后脚本,这些脚本在包安装时(即通常在 `npm install` 期间)执行。
一些包依赖其安装脚本来执行设置步骤(例如,下载或构建原生插件的artifact),如果不安执行,它们将无法正常工作。以前,Deno 不支持执行生命周期脚本,因此在使用某些包时可能会导致令人困惑的错误,并且没有简单的解决方案。
现在,Deno 支持在 `deno cache`(和 `DENO_FUTURE=1 deno install`)中运行生命周期脚本,并且如果检测到某个包具有未运行的生命周期脚本,它将发出警告。
通过在 `deno cache`(或 `DENO_FUTURE=1 deno install`)中使用 `--allow-scripts` 标志,您可以选择为特定包运行生命周期脚本。
deno cache --allow-scripts=npm:duckdb main.ts
ℹ️ 注意
目前,我们仅在使用本地 `node_modules` 目录时(即在 `deno.json` 中设置 `"nodeModulesDir": true`)支持生命周期脚本。
将来,我们计划在没有 `node_modules` 的情况下添加对生命周期脚本的支持,但这将是尽力而为的,因为有些包依赖于位于 `node_modules` 目录中。
`deno init --lib` - 轻松设置新库
`deno init` 子命令在 Deno v1.25 中引入,允许您通过几次按键快速启动 Deno 项目的最小骨架。
自从引入 JSR 以来,用户一直要求提供一种快速启动将发布到 JSR 的项目的方法。
您可以使用 Deno v1.45 和 `deno init --lib` 来做到这一点。
✅ Project initialized
Run these commands to get started
# Run the tests
deno test
# Run the tests and watch for file changes
deno task dev
# Publish to JSR (dry run)
deno publish --dry-run
在发布之前,请务必更新生成的 `deno.json` 文件中的 `name` 和 `version` 字段!
`deno vendor` 现已废弃
`deno vendor` 在 Deno v1.19 中添加,允许用户将所有依赖项导入到项目目录中。
从那时起,Deno v1.37 中引入了另一种导入依赖项的方式,即通过 `--vendor` 标志或配置文件中的 ` { "vendor": true }` 选项。
此选项收到了大量积极反馈,并指出了 `deno vendor` 子命令的缺点和较差的开发者体验(DX)。考虑到这一点,`deno vendor` 现已废弃,并计划在 Deno 2 中移除。
请迁移到使用 `--vendor` 标志或配置文件中的 `vendor` 选项。
`deno test` 文件发现
`deno test` 可以自动发现并运行与特定模式匹配的文件中的测试
- 文件名以 `_test` 结尾 - 例如 `app_test.ts`, `component_test.tsx`
- 文件名以 `.test` 结尾 - 例如 `router.test.ts`, `controller.test.js`
- 文件名为 `test` - 例如 `test.ts`, `test.js`
为了提高与更广泛生态系统的兼容性,`deno test` 现在将自动发现并运行 `__tests__` 目录下的文件
$ tree
.
├── __tests__
│ ├── integration.ts
│ └── unit.ts
└── main.ts
2 directories, 3 files
在 Deno v1.44 中
$ deno test
error: No test modules found
在 Deno v1.45 中
$ deno test
deno test
Check file:///Users/ib/dev/test_discovery/__tests__/integration.ts
Check file:///Users/ib/dev/test_discovery/__tests__/unit.ts
running 1 test from ./__tests__/integration.ts
integration test ... ok (0ms)
running 1 test from ./__tests__/unit.ts
unit test ... ok (0ms)
ok | 2 passed | 0 failed (11ms)
`Blob.bytes()`
继 Deno v1.44 的更改以及 Web File API 规范的更新之后,现已支持 `Blob.bytes()`。
const jsonStr = JSON.stringify({ hello: "world" }, null, 2);
// Before:
const blob = new Blob([jsonStr], { type: "application/json" });
const buffer = new Uint8Array(await blob.arrayBuffer());
// After:
const blob = new Blob([jsonStr], { type: "application/json" });
const buffer = await blob.bytes();
Jupyter notebooks 改进
您现在可以在 Jupyter notebook 中使用 `prompt` 和 `confirm` API,以提供更大的灵活性和交互性。
为了进一步改善 JavaScript(和 TypeScript)的数据科学生态系统,我们计划在下一个版本中添加使用 JSX 和 React 的交互式小部件支持。
`deno compile` 支持 `--env` 标志
`--env` 标志在 Deno v1.38 中添加,增加了从 `.env` 文件加载进程环境变量的原生支持。
在 Deno v1.45 中,`--env` 标志可用于将某些环境变量嵌入到使用 `deno compile` 生成的二进制文件中。
🛑 注意
请记住,这些环境变量在检查发布程序的內容时仍然可以被读取,因此请谨慎使用此功能。将生产密钥写入二进制文件可能不是最佳实践。
当执行使用 `deno compile` 创建的程序时,所有对 `.env` 文件中提供的变量的 `Deno.env.get(
$ cat .env
HELLO_THERE=deno
$ cat main.ts
console.log("Hello there")
console.log(Deno.env.get("HELLO_THERE") + "!");
$ deno compile --env --allow-env main.ts
...
在 Deno v1.44.4 中
HELLO_THERE="General Kenobi" ./main
Hello there
General Kenobi!
在 Deno v1.45.0 中
HELLO_THERE="General Kenobi" ./main
Hello there
Deno!
更灵活的语言服务器
以前,VSCode 扩展只能读取和合并位于工作区根目录下的 `deno.json` 或 `deno.jsonc` 文件。其中的配置将应用于每个打开的源文件。这使得某些单体仓库配置无法实现。
1.45 版本使语言服务器更能独立于编辑器中打开的根文件夹。现在可以检测到子目录中的配置文件,即使存在多个。每个被发现的 `deno.json` 或 `deno.jsonc` 都将生成一个独立的作用域,拥有自己的类型检查环境、模块解析等。您可以为 `compilerOptions.libs` 配置不同的条目,或导入对全局类型进行增强的模块,这些都不会污染其他 `deno.json[c]` 作用域的环境。
标准库更接近稳定版
Deno 标准库提供了一组高质量的包,这些包经过核心团队审计,并保证与 Deno 兼容。
正如我们之前的博客文章中所述,标准库目前正在进行稳定化工作,目标是将 38 个包中的 31 个稳定下来。
截至目前,我们已稳定 13 个包
@std/assert
@std/bytes
@std/collections
@std/crypto
@std/data-structures
@std/encoding
@std/html
@std/media-types
@std/msgpack
@std/path
@std/regexp
@std/toml
@std/uuid
这些包已达到 1.0.0 版本,遵循语义化版本控制(SemVer)规范,并确保其 1.x.x 版本间的兼容性。
剩余的 18 个包已发布其发布候选(RC)版本(列表请参见路线图问题)。如果您目前正在使用这些包中的任何一个,请考虑测试 RC 版本并与我们分享您的反馈!
有关稳定时间线的更多详细信息,请参阅路线图问题。
V8 12.7 和 TypeScript 5.5.2
Deno 1.45 附带 V8 12.7 和 TypeScript 5.5.2。
使用 `DENO_FUTURE=1` 试用 Deno 2 功能
我们鼓励您尝试使用 `DENO_FUTURE=1` 环境变量运行现有项目,这将启用 Deno 2 的功能。我们预计迁移工作量极小。如果您的体验不同,请与我们分享。
致谢
没有社区的帮助,我们无法构建 Deno!无论是通过在我们的社区 Discord 服务器中回答问题,还是报告错误,我们都非常感谢您的支持。特别是,我们要感谢以下人员对 Deno 1.45 的贡献:Adam Gregory, Andreas Kohn, Andrew Johnston, Filip Skokan, HasanAlrimawi, Kenta Moriuchi, Luca Bruno, Oliver Medhurst, Richard Carson, Tom Alcorn, Victor Turansky, Yazan AbdAl-Rahman, Zander Hill, Zebreus, muddlebee, safaa-mojahed, ud2。
您想加入 Deno 贡献者的行列吗?在此处查看我们的贡献文档,下次我们会在列表中看到您。
信不信由你,上面列出的更改仍然没有告诉您 1.45 中所有改进之处。您可以在此处 GitHub 上查看 Deno 1.45 中合并的完整拉取请求列表。
感谢您关注我们的 1.45 版本发布,希望您喜欢使用 Deno 进行开发!