Deno 1.43:改进的语言服务器性能
编程应该简单。这就是我们打造 Deno 的原因,它是一个零配置、内置电池的 JavaScript 运行时,原生支持 TypeScript,可实现即时生产力。
在 1.43 版本中,我们通过将大型代码库中的自动补全时间从 6-8 秒缩短到一秒以内,并显著降低内存使用,从而提升了 Deno 在 IDE 中的性能。我们还通过重构 node:vm 和 node:worker_threads 的实现,实现了更完整的 npm 兼容性,这两个模块广泛用于 Jest 等 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 运行 Docusaurus 来支持我们的一些文档网站。
- 在 Rust 中实现 process.kill以避免运行权限提示。这使得流行的 CLI spinner 库ora可以在 Deno 中运行。
- 添加缺失的 http.maxHeaderSize值以使undici工作。
- fs.cpSync:始终确保 SolidStart 的父目录存在。
- 支持 node:worker_threads中的env选项。这使得调用sveltekit build能够成功完成。
- 正确发送节点 TLS 连接上的 ALPN,这曾导致上游服务器混淆。
- 修复导致 ng serve和vitest崩溃的AsyncResource借用恐慌。
- 修复 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_threadworker 过早退出的问题。
- Polyfill node:domain模块以修复web-ext中的配置发现问题。
- 修复传输的 MessagePort没有.on处理程序的问题,这在 Angular 中使用的piscina中是必需的。
- 修复 node:util中的parseArgs不支持default选项的问题。
- 添加缺失的 fs.readv、fs.readvSync函数。
其他框架,如 SolidStart,也正在逐步接近完全支持。我们已经掌握了基础,但要完全支持它们的 https 服务器和 auth-js,还有一些工作要做。

SolidStart 和其他框架的兼容性改进正在通过新的 DENO_FUTURE=1 环境变量实现,您可以在下方阅读更多信息。
我们解决的另一个领域是 AsyncResource 的改进,这对于使 vitest 工作至关重要,因为它依赖于 tinypool 包,而 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://:3000
 ✓ Ready in 2.2s
 ○ Compiling / ...
 ✓ Compiled / in 5.5s (511 modules)
 ✓ Compiled in 381ms (241 modules)目前运行 Next.js 需要在 Deno 中启用一些不稳定标志,我们正在积极稳定这些标志。
在 deno.json 任务中使用 npm 命令
现在,诸如 vite 等通常通过 package.json 脚本管理的 npm 可执行命令,也可以直接在 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 pragma 和编译器选项允许为自动 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://:8000/
$ curl https://: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 实例。关键在于,如果解析的 URL 无效,new URL(input, base) 会抛出错误;而 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 中合并的完整拉取请求列表。
感谢您关注我们的 1.43 版本发布,希望您喜欢使用 Deno 进行开发!
🍋 Fresh 2.0 即将到来。
我们的下一个主要 Fresh 版本将更简单,具有更可组合的路由 API。在此处阅读更多信息。



