Deno 1.43:改进的语言服务器性能
编程应该简单。这就是我们让 Deno 成为一个零配置、包含电池的 JavaScript 运行时,并具有原生 TypeScript 支持,从而使您能够立即提高生产力。
在 1.43 版本中,我们通过将大型代码库的自动完成时间从 6-8 秒缩短到不到一秒,并显著降低内存使用量,从而增强了 Deno 在 IDE 中的性能。我们还通过重新设计 node:vm 和 node:worker_threads 实现,实现了更完整的 npm 兼容性,这些实现广泛用于 JavaScript CLI 工具(如测试运行器)。
要升级到 Deno 1.43,请在您的终端中运行以下命令
deno upgrade
如果 Deno 尚未安装,请 在此处了解如何安装它。
Deno 1.43 中的新功能
- 加速 Deno 的语言服务器
- Node.js 和 npm 兼容性
- 在 deno.json 任务中使用 npm 命令
- 更快的 ES 和 CommonJS 模块加载
- JSX 预编译改进
jsxImportSourceTypes
- 介绍
deno serve
子命令 Deno.serve()
更新URL.parse()
Web API- 标准库正在更接近稳定化
- 针对
rusty_v8
的 Android 构建 - V8 12.4
- 使用
DENO_FUTURE=1
试用 Deno 2 功能 - 鸣谢
加速 Deno 的语言服务器
一些 Deno 用户联系我们,告诉我们他们的语言服务器难以处理具有大量文件的较大项目。语言服务器(通常称为 Deno LSP)在您的编辑器中提供自动完成等功能。当他们分享这些项目中的编辑器体验时,我们意识到可以大幅度改善响应能力和内存消耗。
在本周期中,我们花费了大部分时间重新设计 LSP 的许多方面,使其更快、更高效。在大型项目中,自动完成以前大约需要 6-8 秒,现在我们已经将其缩短到不到一秒。类似地,内存消耗也得到了显著改善,使以前在我们的 LSP 中会导致内存不足错误的项目能够正常运行。
之前
之后
Node.js 和 npm 兼容性
此版本包括围绕 node:worker_threads
和 node:vm
模块的许多关键改进。这两个模块经常用于测试运行器(如 Jest 和 Vitest)以及 Docusaurus 等工具。事实上,我们现在正在使用 Deno 来运行 Docusarus 为我们的一些 文档站点 提供支持。
- 在 Rust 中实现
process.kill
以避免运行权限提示。这使ora
(一个流行的 CLI 旋转库)在 Deno 中正常工作。 - 添加缺少的
http.maxHeaderSize
值以使undici
正常工作。 fs.cpSync
:始终确保父目录存在以用于 SolidStart。- 支持
node:worker_threads
中的env
选项。这使得能够成功调用sveltekit build
。 - 在 node TLS 连接上正确发送 ALPN,这些连接会使上游服务器感到困惑
- 修复
AsyncResource
借用恐慌,这会导致ng serve
和vitest
崩溃。 - 修复
node:vm
上下文中出现的Promise
拒绝,这用于docusaurus build
。 - 实现
MessagePort.unref()
,用于@angular/cli serve
。 - 修复
fs.createWriteStream
的无序写入,这发生在koa-body
中。 - 确保
node:http
中的hostname
是一个有效的 IPv4 地址,这修复了docusaurus serve
。 - 为
docusaurus build
将module
添加到builtinsModule
。 - 修复
node:worker_thread
工作进程过早退出。 - 为
web-ext
填充node:domain
模块以修复配置发现。 - 修复传输的
MessagePort
没有.on
处理程序,这对于 Angular 中使用的piscina
是必需的。 - 修复
node:util
中的parseArgs
不支持default
选项。 - 添加缺少的
fs.readv
、fs.readvSync
函数。
其他框架(如 SolidStart)也越来越接近完全支持。我们已经掌握了基本原理,但还需要做一些工作才能完全支持它们的 https 服务器和 auth-js
SolidStart 和其他框架兼容性改进正在新的 DENO_FUTURE=1
环境变量后面完成,您可以在 下面 阅读相关内容。
我们解决的另一个领域是对 AsyncResource
的改进,这对于使 vitest
正常工作是必需的,因为它依赖于 tinypool
包,而该包又大量使用 Node 的 AsyncResource
。
当然,我们也在努力支持 Next.js。由于我们对 node_modules
目录中布局处理的一些改进,我们使初始化向导完全正常工作。
~/my-app $ DENO_FUTURE=1 deno task dev
Task dev next dev
▲ Next.js 14.1.3
- Local: https://127.0.0.1:3000
✓ Ready in 2.2s
○ Compiling / ...
✓ Compiled / in 5.5s (511 modules)
✓ Compiled in 381ms (241 modules)
当前运行 Next.js 需要在 Deno 中启用一些不稳定的标志,我们正在努力稳定这些标志。
在 deno.json 任务中使用 npm 命令
可执行的 npm 命令(如 vite,通常通过 package.json 脚本管理)现在也可以在 deno.json 中定义的任务中直接引用。
// deno.json
{
"tasks": {
"start": "vite"
}
}
更快的 ES 和 CommonJS 模块加载
此版本增加了对 V8 代码缓存(也称为字节码缓存)的支持,这可以显著缩短应用程序在解析和编译 JavaScript 模块上花费的时间。当首次加载模块时,编译后的字节码会自动缓存在本地磁盘上,然后在后续加载时重复使用。
在我们的测试中,我们观察到启动时间改进介于 5% 和 240% 之间,具体取决于应用程序。
JSX 预编译改进
自 v1.38 版本起,Deno 默认提供 precompile
JSX 变换,该变换针对服务器端渲染性能进行了优化。在某些情况下,框架可能希望阻止预编译元素以允许向其传递其他属性。我们的变换学习了新的技巧,可以使用 jsxPrecompileSkipElements
编译器选项实现这一点。
// deno.json
{
"compilerOptions": {
"jsx": "precompile",
"jsxImportSource": "preact",
// Don't precompile <a>, <body>, and <img> elements
"jsxPrecompileSkipElements": ["a", "body", "img"]
}
}
您可以向该选项传递一个元素数组,以将其从预编译中排除。
// Example: Input
const a = <a href="#">click me</a>;
// ...precompiled output
const $$_tpl_1 = ['<a href="#">click me</a>'];
const a = jsxTemplate($$_tpl_1);
// ...non-precompiled output
const a = jsx("a", {
href: "#",
children: "click me",
});
jsxImportSourceTypes
新的 jsxImportSourceTypes
准则和编译器选项允许为自动 JSX 变换指定类型。这对使用未提供其类型的库很有用。
/** @jsxImportSource npm:react@^18.3 */
/** @jsxImportSourceTypes npm:@types/react@^18.3 */
export function Hello() {
return <div>Hello!</div>;
}
或者,可以在 deno.json 文件中指定这一点
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "npm:react@^18.3",
"jsxImportSourceTypes": "npm:@types/react@^18.3"
}
}
deno serve
子命令
介绍 在此版本中,我们添加了 deno serve
子命令,它允许您以声明方式编写服务器
export default {
fetch(request) {
return new Response("Hello world");
},
};
$ deno serve server.ts
deno serve: Listening on https://127.0.0.1:8000/
$ curl https://127.0.0.1:8000/
Hello world
请注意,您不需要传递任何权限标志 - deno serve
会自动应用适当的 --allow-net
权限,允许它侦听传入的 HTTP 连接。但是,您仍然可以根据需要传递额外的权限标志。
此外,您可以使用 --host
和 --port
标志来配置服务器绑定到的接口
$ deno serve --host 0.0.0.0 --port 3000 server.ts
deno serve: Listening on http://0.0.0.0:3000/
$ curl http://0.0.0.0:3000/
Hello world
我们计划在将来引入自动负载均衡,这将使服务器在多个 CPU 内核上运行,从而更好地利用您的系统资源。
Deno.serve()
更新
响应完成
现在你可以使用 Deno.ServeHandlerInfo.completed
promise 获取响应是否成功发送或出现错误的信息。
Deno.serve((req, info) => {
info.completed.then(() => {
console.log("Response sent successfuly!");
}).catch(() => {
console.error("Failed sending the response.");
});
return new Response("Hello world");
});
此外,附加到 Request
参数的 AbortSignal
将在事务完成后始终被中止 - 无论是通过客户端关闭连接还是服务器发送响应。
Deno.serve((req, info) => {
req.signal.addEventListener("abort", () => {
console.log("Response finished");
});
return new Response("Hello world");
});
更简单的服务器地址访问方式
我们添加了一个小而重要的生活质量改进,使从 Deno.serve
获取服务器地址变得更容易。之前,你必须编写类似这样的代码:
let listenPort: number | null = null;
Deno.serve(
{
onListen: ({ port }) => (listenPort = port),
},
() => new Response("hello world"),
);
通过在服务器实例上直接添加一个新的 addr
属性,这变得更加简单。
const server = Deno.serve(() => new Response("hello world"));
const port = server.addr.port;
URL.parse()
Web API
新的 Web API URL.parse()
在你需要解析 URL 时提供了更简单的控制流程。
在此之前,解析 URL 的方法是构造一个新的 URL
实例。关键在于 new URL(input, base)
在你解析的 URL 无效时会抛出一个错误;而 URL.parse(input, base)
对于无效的 URL 则只返回 null
。
因此,如果你正在解析一个 URL 并且需要在解析失败时提供一个回退,你可以用以下代码替换:
let url;
try {
url = new URL(userProvidedValue, "http://deno.land");
} catch {
url = new URL("http://deno.land");
}
用以下代码替换:
const url = URL.parse(userProvidedValue, "http://deno.land") ??
new URL("https://deno.land");
感谢 Kenta Moriuchi 实现这个 API。
标准库正在逐步走向稳定
Deno 标准库 (deno_std
) 提供了一套高质量的包,这些包由核心团队审核,并保证与 Deno 兼容。
我们将在未来几天发布一篇关于此的完整博客文章,但从 Deno 1.43 开始,标准库将只发布到 JSR,位于 @std
范围。现有版本的标准库将继续保留在 https://deno.land/std。此举,以及 Deno 的新工作区功能,是 Deno 2 中即将出现的变化的一部分。有关更多详细信息,请查看 标准库的稳定化路线图。
rusty_v8
Android 构建 虽然我们没有提供 Android 构建,但我们收到了一份很棒的补丁,使构建 Android 的 rusty_v8
变得更容易。
感谢 @Taknok 的贡献。
V8 12.4
Deno 1.43 附带 V8 12.4,它增加了对一种新的 TypedArray
类型 Float16Array
的支持。
此 API 在 一些 GPU 相关应用程序 中非常有用。
DENO_FUTURE=1
试用 Deno 2 功能
使用 为了迎接即将到来的 Deno 2 版本发布,我们把 Deno 2 的重大变更放在了 DENO_FUTURE=1
环境变量之后。启用它可以让你测试你的项目与 Deno 2 的兼容性。
这包括以下内容
- 用
nodeModulesDir
设置覆盖 BYONM - 删除 Web Workers 中已弃用的
Deno.*
API - 在
package.json
存在时默认启用 BYONM - 删除
Deno.ConnectTlsOptions.certFile
- 删除
Deno.ConnectTlsOptions.certChain
- 删除
Deno.ConnectTlsOptions.privateKey
- 删除
Deno.ListenTlsOptions.keyFile
- 删除
Deno.ListenTlsOptions.certFile
- 删除
Deno.customInspect
- 删除
Deno.Conn.prototype.rid
- 删除
Deno.TlsConn.prototype.rid
- 删除
Deno.Listener.prototype.rid
- 删除
Deno.TlsListener.prototype.rid
- 删除
Deno.UnixConn.prototype.rid
- 删除
Deno.FsWatcher.prototype.rid
- 使
Deno.FsFile
构造函数非法
鸣谢
没有社区的帮助,我们无法构建 Deno!无论是回答社区 Discord 服务器 中的问题,还是 报告错误,我们对你们的支持表示衷心的感谢。特别是,我们要感谢以下人员对 Deno 1.43 的贡献:Alex Yang, Carlos Precioso, JOTSR, Javier Viola, Kenta Moriuchi, MAKS11060, nokazn, welfuture, youngwendy, 林炳权, chirsz-ever。
你想加入 Deno 贡献者行列吗?查看我们的贡献文档,下次你就会出现在列表中。
信不信由你,上面列出的更改仍然没有告诉你 1.43 中所有改进的地方。你可以在这里 GitHub 上查看 Deno 1.43 中合并的所有 pull request。
感谢你关注我们的 1.43 版本发布,我们希望你喜欢用 Deno 构建东西!
🍋 新鲜的 2.0 版本即将推出。
我们的下一个主要的 Fresh 版本将更简单,具有更可组合的路由 API。点击这里了解更多。