为了账号安全,请及时绑定邮箱和手机立即绑定

Deno 1.43:提升了语言服务器的性能

(最初发布于 deno.com/blog)

编程应该很简单。这就是为什么我们将 Deno 设计为一个无需配置、直接可用的 JavaScript 运行时环境,并且内建支持 TypeScript,从而立即提高生产力。

在 1.43 版本中,我们通过将大型代码库中的自动完成功能的响应时间从 6–8 秒减少到不到 1 秒,并显著降低了内存消耗,从而增强了 Deno 在 IDE 中的性能表现。我们还通过重新设计我们的 node:vm 和 node:worker_threads 实现,使 npm 兼容性更加完善,这些实现广泛应用于如测试运行器等 JavaScript CLI 工具。

要升级到 Deno 1.43,请在终端中输入以下命令。

运行 `deno upgrade` 升级Deno

如果还没有安装 Deno,可以在这里查看安装方法

Deno 1.43 新增功能

加快 Deno 的语言服务

一些Deno用户向我们反馈,我们的语言服务器在处理大规模项目时出现了问题,这些项目包含大量文件。语言服务器(通常被称为Deno LSP)提供诸如自动完成功能等特性。当我们了解到他们在这些项目中的编辑器体验后,我们意识到我们可以在响应速度和内存消耗方面做出显著改善。

这一周期,我们大部分时间都在重新调整LSP的许多方面,使其更快、更高效。在较大的项目中,自动完成以前需要大约6到8秒,现在已减少到不到1秒。同样地,内存消耗也有了显著的改进,使得之前因LSP内存不足而出错的项目现在可以正常运行。

关于Node.js和npm的兼容性

此版本包括了对 node:worker_threadsnode:vm 模块的重要改进。这两个模块常被测试运行器(如 Jest 和 Vitest)和工具(如 Docusaurus)使用。实际上,我们现在使用 Docusaurus 和 Deno 来支持一些 我们的文档网站

  • 在 Rust 中实现 process.kill 以避免运行时权限提示,这可以让流行的 CLI 转盘库 ora 在 Deno 中也能正常运行。
  • 添加缺少的 http.maxHeaderSize 值,以便 undici 可以正常工作。
  • fs.cpSync:始终确保父目录存在以支持 SolidStart 的需求。
  • node:worker_threads 中支持 env 选项,这样 sveltekit build 就可以成功调用了。
  • 正确发送节点 TLS 连接中的 ALPN 以避免上游服务器产生混淆。
  • 修复 AsyncResource 的借用恐慌,这影响了 ng servevitest 的正常使用。
  • 修复在 node:vm 上下文中 Promise 的拒绝问题,这在 docusaurus build 中使用。
  • 实现 MessagePort.unref() 以便 @angular/cli serve 能正常运行。
  • 修复 fs.createWriteStream 的顺序写入问题,这个问题出现在 koa-body 中。
  • 确保 node:http 中的 hostname 是有效的 IPv4 地址,以修复 docusaurus serve 中的问题。
  • docusaurus buildbuiltinsModule 添加 module
  • 修复 node:worker_thread 中工作进程过早退出的问题。
  • 修补 node:domain 模块以解决 web-ext 中的配置发现问题。
  • 修复传输的 MessagePort 没有 .on 处理程序的问题,这是 piscina 在 Angular 中需要的。
  • 修复 node:util 中的 parseArgs 不支持 default 选项的问题。
  • 添加缺少的 fs.readvfs.readvSync 函数。

其他框架,例如 SolidStart,也在逐渐接近完全支持。我们已经掌握了基础知识部分,但仍有一些工作要做以全面支持他们的 https 服务器和 auth-js

SolidStart 和其他框架兼容性改进正在进行中,这些改进是通过设置新的 DENO_FUTURE=1 环境变量来实现的。您可以通过此链接了解更多详情。

我们还优化了 AsyncResource,以确保 vitest 能正常运行,因为 vitest 依赖于 tinypool 包,而 tinypool 包则大量依赖于 Node 的 AsyncResource

当然,我们也在支持Next.js的开发。我们通过对node_modules目录中布局的改进,已经成功地完成了初始化流程的设置。

    ~/my-app $ DENO_FUTURE=1 deno task dev  
    任务 dev,启动下一个 dev  
       ▲ Next.js 14.1.3  
       - 本地:        http://localhost:3000  

     ✓ 准备完毕,耗时 2.2s  
     ○ 编译 / ...  
     ✓ 编译完成,耗时 5.5s (511 模块)  
     ✓ 快速编译完成,耗时 381ms (241 模块)

要运行 Next.js,目前需要在 Deno 中启用一些实验性标志,我们已经在使这些标志稳定的过程中取得了很大进展。

在 deno.json 任务中用 npm 命令

像通过 package.json 脚本管理的执行 npm 命令(如 vite)一样,现在也可以直接在 deno.json 定义的任务中引用。

    // 这是 deno.json 文件中的配置,定义了一个名为 'start' 的任务,其值为 'vite'。
    {  
      "tasks": {  
        "start": "vite"  
      }  
    }
更快地加载 ES 和 CommonJS 模块

这个版本新增了V8代码缓存(也就是字节码缓存)的功能,这可以显著减少您的应用程序在解析和编译JavaScript模块上的时间消耗。当模块首次加载时,编译的字节码会自动缓存到本地磁盘,并在后续加载时再次使用。

启动时间缩短了5%到240%之间,这取决于具体的应用程序。

JSX 预编译优化

从版本v1.38开始,Deno 默认自带了一个 precompile 预编译功能,该功能优化了服务器端渲染的性能。在某些情况下,框架可能希望阻止某个元素被预编译,以便传递额外属性。我们的转换新增了一个功能,可以通过设置 jsxPrecompileSkipElements 编译器选项来实现这一点。

    // deno.json  
    {  
      "compilerOptions": {  
        "jsx": "precompile",  
        "jsxImportSource": "preact",  
        // 跳过预编译 <a>、<body> 和 <img> 元素。  
        "jsxPrecompileSkipElements": ["a", "body", "img"]  
      }  
    }

你可以将元素列表传递给该选项,以使它们不被预编译。

// 示例:
const a = <a href="#">点击我</a>;  

// ...预编译的结果
const $_tpl_1 = ['<a href="#">点击我</a>'];  
const a = jsxTemplate($_tpl_1);  
// ...未预编译的结果
const a = jsx("a", {  
  href: "#",  
  children: "点击我",  
});

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": "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: 在 http://localhost:8000/ 监听中  
    $ curl http://localhost:8000/  
    Hello world

注意,你无需传递任何权限标志——deno serve 会自动启用 --allow-net 权限,使其能够监听传入的 HTTP 请求。不过,如需,你也可以传递额外的权限标志。

此外,您可以使用 --host--port 标志来指定服务器绑定的接口,例如:

    $ deno serve --host 0.0.0.0 --port 3000 server.ts  
    deno serve: 监听中,网址为 http://0.0.0.0:3000/.
    $ curl http://0.0.0.0:3000/  
    Hello world

我们计划在未来引入自动负载均衡技术,这将使服务器能够在多个CPU核心上运行,从而更好地利用您的系统资源。

Deno.serve() 更新了
回复结束

你可以通过这种方式来检查响应是否成功发送,通过Deno.ServeHandlerInfo.completed

    Deno.serve((req, info) => {  
      info.completed.then(() => {  
        console.log("响应已成功发送!");  
      }).catch(() => {  
        console.error("发送响应失败了。");  
      });  
      return new Response("Hello world");  
    });

此外,与 Request 参数关联的 AbortSignal 在事务结束时总是会被取消——不管是客户端关闭了连接还是服务器发送了响应。

    Deno.serve((req, info) => {  
      req.signal.addEventListener("abort", () => {  
        console.log("请求已终止");  
      });  
      return new Response("Hello world");  
    });
更简单的访问服务器地址

为了提高生活质量,我们增加了一个小功能,使得从 Deno.serve 获取服务器地址变得更加容易。之前,你需要写这样的代码段:

    // 定义listenPort为number或null类型,并初始化为null
    let listenPort: number | null = null;  
    Deno.serve(  
      {  
        // 当服务器开始监听某个特定端口时,将listenPort设置为此端口
        onListen: ({ port }) => (listenPort = port),  
      },  
      // 当请求到达时,返回一个包含"hello world"的Response对象
      () => new Response("hello world"),  
    );

只需在服务器上直接添加一个addr属性,操作就变得简单多了。

const server = Deno.serve(() => new Response("hello world"));  
const port = server.addr.port;
URL.parse() 网页 API

新的 Web API URL.parse() (网络应用编程接口)在你需要解析 URL 时更加简单易用。

在此次增加之前,解析的方式是创建一个新的 URL 实例。主要问题在于,如果要解析的 URL 无效,new URL(input, base) 会抛出一个错误;而 URL.parse(input, base) 则会返回 null

那么,如果你在解析 URL 并需要在解析失败时提供一个备选方案,你可以用如下代码替换原来的解析代码。

    let url;  
    try {  
      url = new URL(userProvidedValue, "http://deno.land");  
    } catch {  
      url = new URL("http://deno.land");  
    }

尝试使用用户提供的值和 http://deno.land 创建一个新的 URL 对象。如果创建失败,则使用 http://deno.land 初始化一个新的 URL 对象。

如下代码:

    const url = URL.parse(userProvidedValue, "http://deno.land") ??  
      new URL("https://deno.land");

感谢Kenta Moriuchi实现了这个API功能。

标准库正逐步趋于稳定了

Deno 标准库 ([deno_std](https://github.com/denoland/deno_std/)) 提供了一系列高质量的包,这些包经过核心团队的审核,并确保与 Deno 兼容。

我们将在接下来的几天里发布一篇详细的博客文章,从 Deno 1.43 开始,标准库将仅在 [@std] 范围内发布。现有的版本将继续在 https://deno.land/std 上提供。这一变化,连同 Deno 的新工作区功能,是 Deno 2 版本即将推出的一系列变化之一。更多详情,请参阅 标准库的稳定路线图

Android 构建 rusty_v8

尽管我们不提供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 服务器 的社区回答问题,还是通过在 GitHub 报告错误,我们非常感谢大家的支持。特别要感谢以下人为 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的完整拉取请求(PR)列表在这里

感谢您跟进我们的1.43版本发布,希望您喜欢使用Deno进行构建。

🍋Fresh 2.0马上就要来了。

我们下一个主要的Fresh版本将更加简洁明了,将采用更可组合的路由API。了解更多详情请

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消