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 的语言服务器速度
- Node.js 和 npm 兼容性
- 在
[deno.json](https://deno.com/blog/v1.43#using-npm-commands-in-denojson-tasks)
任务中使用 npm 命令 - 更快的 ES 和 CommonJS 模块加载速度
- JSX 预编译改进
[jsxImportSourceTypes](https://deno.com/blog/v1.43#jsximportsourcetypes)
- 介绍
[deno serve](https://deno.com/blog/v1.43#introducing-deno-serve-subcommand)
子命令 [Deno.serve()](https://deno.com/blog/v1.43#denoserve-updates)
更新- 响应完成
- 更简单的服务器地址访问
[URL.parse()](https://deno.com/blog/v1.43#urlparse-web-api)
Web API- 标准库更接近稳定
- 为
[rusty_v8](https://deno.com/blog/v1.43#android-builds-for-rusty_v8)
构建 Android 版本 - V8 12.4
- 使用
[DENO_FUTURE=1](https://deno.com/blog/v1.43#try-out-deno-2-features-with-deno_future1)
体验 Deno 2 的功能 - 致谢
一些Deno用户向我们反馈,我们的语言服务器在处理大规模项目时出现了问题,这些项目包含大量文件。语言服务器(通常被称为Deno LSP)提供诸如自动完成功能等特性。当我们了解到他们在这些项目中的编辑器体验后,我们意识到我们可以在响应速度和内存消耗方面做出显著改善。
这一周期,我们大部分时间都在重新调整LSP的许多方面,使其更快、更高效。在较大的项目中,自动完成以前需要大约6到8秒,现在已减少到不到1秒。同样地,内存消耗也有了显著的改进,使得之前因LSP内存不足而出错的项目现在可以正常运行。
关于Node.js和npm的兼容性此版本包括了对 node:worker_threads
和 node: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 serve
和vitest
的正常使用。 - 修复在
node:vm
上下文中Promise
的拒绝问题,这在docusaurus build
中使用。 - 实现
MessagePort.unref()
以便@angular/cli serve
能正常运行。 - 修复
fs.createWriteStream
的顺序写入问题,这个问题出现在koa-body
中。 - 确保
node:http
中的hostname
是有效的 IPv4 地址,以修复docusaurus serve
中的问题。 - 为
docusaurus build
向builtinsModule
添加module
。 - 修复
node:worker_thread
中工作进程过早退出的问题。 - 修补
node:domain
模块以解决web-ext
中的配置发现问题。 - 修复传输的
MessagePort
没有.on
处理程序的问题,这是piscina
在 Angular 中需要的。 - 修复
node:util
中的parseArgs
不支持default
选项的问题。 - 添加缺少的
fs.readv
和fs.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.4Deno 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。了解更多详情请。
共同学习,写下你的评论
评论加载中...
作者其他优质文章