跳到主要内容
Deno 2.4 来了,带来了 deno bundle、字节/文本导入、OTel 稳定版以及更多功能
了解更多
Deno 1.34

Deno 1.34:deno compile 支持 npm 包

在我们继续向 Deno 2 迈进的开发之旅中,本次小版本发布主要致力于提升与 npm 和 Node.js 的兼容性,改善整体使用便利性和开发者体验,并为未来的性能增强奠定基础。

本次发布最重要的更新包括三项备受期待的功能

除了上述功能外,还有许多其他值得一提的改进和错误修复



deno compile 支持 npm 包

v1.6 发布以来,deno compile 已允许您将项目编译为单个二进制可执行文件。这项发展已被证明具有重要意义,因为它使开发者能够

  • 在所有主流平台上分发和执行二进制文件,无需安装 Deno 或依赖项
  • 将资产包含在可执行文件内部以提高可移植性
  • 通过单个二进制文件简化部署
  • 实现更快的启动时间

此后,我们通过添加对 Web Worker 和动态导入的支持,并于今日支持 npm 包,持续提升 deno compile 的实用性。

以下是使用 cowsay 创建单个二进制可执行文件的示例

$ cat main.ts
import { say } from "npm:cowsay@1.5.0";
console.log(say({ text: "Hello from Deno!" }));

$ deno compile --allow-read main.ts
$ ./main
 __________________
< Hello from Deno! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

cowsay 只是一个简单的例子,但您可以将 deno compile 用于更复杂的项目。我们来试试 vite

$ deno compile --allow-read --allow-write --allow-env --allow-net npm:vite
$ ./vite
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

或者 eslint

$ deno compile --allow-read --allow-write --allow-env --allow-net npm:eslint
$ cat .eslintrc.js
module.exports = {
    "env": {
        "es2021": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "overrides": [
    ],
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": "module"
    },
    "rules": {
    }
}

$ cat foo.js
function foo() {
}

$ ./eslint
/dev/foo.js
  1:10  error  'foo' is defined but never used  no-unused-vars

✖ 1 problem (1 error, 0 warnings)

使用 deno compile 创建 eslint 二进制文件与 npm install -g eslint 的区别在于,Deno 将 eslint 及其所有依赖项和配置与实际的 deno 可执行文件一起打包。这意味着生成的可执行文件可确保其依赖项不会意外更改,并且在不受系统上其他依赖项干扰的情况下继续以相同方式工作。此外,我们的测试表明,deno compile 生成的二进制文件启动速度通常比执行本地缓存了依赖项的相同程序更快。

我们还有更多工作来改进 deno compile,包括最小化总二进制大小,我们计划在未来的版本中解决这些问题。

您对 deno compile 有具体的反馈吗?告诉我们

deno.json 和 CLI 标志中的 Glob 支持

Glob 模式现在在配置文件 deno.jsondeno task 和 CLI 参数中支持用于指定文件。Glob 语法是跨平台的,因此您可以在 Windows、macOS 和 Linux 上放心使用它。

deno.json 中,您可以使用 * 匹配路径中的任意数量字符,? 匹配单个字符,以及 ** 匹配任意数量的目录

{
  "fmt": {
    "include": ["data/example?.txt"],
    "exclude": ["testdata/**/*.ts"]
  }
}

您还可以将 glob 模式用作 CLI 参数。以下是上述示例,但使用了 deno fmt

$ deno fmt --exclude="testdata/**/*.ts" "data/example?.txt"

⚠️ 请注意,我们将 glob 模式放在引号中,以防止 shell 展开它。

使用 deno task,除了上述 glob 语法外,您还可以使用方括号匹配一系列字符

{
  "task": {
    "files": "echo **/*.ts",
    "data": "echo data[0-9].txt"
  }
}

支持 IP 地址的 TLS 证书

最受期待的功能之一终于来了。您现在可以使用包含 IP 地址的 TLS 证书。

引用 rustls 团队的话:

这对于 Kubernetes pods 等场景非常有用,它们通常使用 IP 地址而不是域名;也适用于 DNS over HTTPS/TLS,后者需要服务器的 IP 地址来避免名称解析的循环依赖。

在 Deno v1.34 中,任何使用 TLS 的 API 都将支持 IP 地址。例如

const resp = await fetch("https://1.1.1.1");
console.log(await resp.text());

配置文件改进

为所有子命令排除文件或文件夹

以前,如果您希望 Deno 对每个子命令都忽略某个文件或文件夹,您必须重复指定它

{
  "fmt": {
    "exclude": ["target/"]
  },
  "lint": {
    "exclude": ["target/"]
  },
  "test": {
    "exclude": ["target/"]
  },
  "bench": {
    "exclude": ["target/"]
  }
}

从本次发布开始,您可以使用顶层 exclude 属性

{
  "exclude": ["target/"]
}

感谢 @scarf005 实现了此功能。

nodeModulesDir 属性

现在可以在 deno.json 文件中指定 nodeModulesDir 属性,以明确启用或禁用 Deno 对 node_modules 目录的使用。

{
  "nodeModulesDir": true
}

如果您将 Deno 与 package.json 和 node_modules 目录一起使用,建议启用此设置,因为它将提供更好的体验。例如,启用后,Deno 的语言服务器将使用本地 node_modules 目录进行缓存和解析包。

语言服务器改进

Deno 1.33 在语言服务器中引入了文档预加载功能,它在初始化时预加载工作区中的模块,以便 Deno 了解它们及其内容。

在某些情况下,默认的 1000 个文件系统条目限制可能过少或过多,因此现在可以通过设置 deno.documentPreloadLimit 属性进行配置。

{
  "deno.enable": true,
  "deno.documentPreloadLimit": 2000
}

此外,语言服务器内部 TypeScript 隔离的默认最大内存限制已增加到 3GB,以匹配 VS Code 中 TypeScript 的默认设置。最后,此限制可以在 VSCode 扩展中通过 deno.maxTsServerMemory 进行配置。

{
  "deno.enable": true,
  "deno.maxTsServerMemory": 3072
}

Deno API 变更

Deno.serve()

上个月,我们曾暗示计划稳定 Deno.serve() API。然而,经过深思熟虑,我们决定将稳定工作再推迟一个月,以便使此 API 更具前向兼容性。

Deno.serve() 的签名已更改为返回 Deno.Server 实例而非 Promise<void>Deno.Server 具有一个 finished 属性,它是一个 Promise,当服务器关闭时(使用 AbortSignal)会解析。这为以编程方式控制服务器提供了更大的灵活性。

const ac = new AbortController();
const server = Deno.serve(
  { signal: ac.signal },
  (_req) => new Response("Hello world"),
);
setTimeout(() => {
  ac.abort();
}, 1000);
await server.finished;
console.log("Server has shut down");

此外,Deno.Server 还有 ref()unref() 方法。您可以使用这些方法控制服务器是否应保持进程活动。

Deno.createHttpClient()

这个不稳定的 API 现在公开了更多选项,可以更好地控制创建的客户端

const client = Deno.createHttpClient({
  // Set maximum number of idle connections in the connection pool per host to 10.
  poolMaxIdlePerHost: 10,

  // Set a timeout for idle connection being kept alive to 10s. You can disable
  // timeout all together by passing `false`.
  poolIdleTimeout: 10_000,

  // Configure if the client can use HTTP1.
  http1: false,

  // Configure if the client can use HTTP2.
  http2: true,
});

const resp = await fetch("...", { client });

Deno.FileInfo

Deno.FileInfo 接口现在包含以下新字段

  • Deno.FileInfo.isBlockDevice
  • Deno.FileInfo.isCharDevice
  • Deno.FileInfo.isFifo
  • Deno.FileInfo.isSocket

这些字段在 Linux 和 macOS 上可用。在 Windows 上,它们始终为 null

感谢 Hirotaka Tagawa 的贡献。

npm 和 Node 兼容性改进

npm 支持还有其他几项显著改进

  • deno vendor 支持处理 npm specifier,遇到时不再报错。
  • deno task 在执行 package.json 文件中的脚本时,会像 npm 一样运行存在的 prepost 脚本。感谢 Marvin Hagemeister 实现了此功能。

我们还 polyfill 了更多内置的 Node.js API

  • crypto.createDiffieHellman
  • crypto.createDiffieHellmanGroup
  • http.Server.unref
  • Module.runMain
  • performance.markResourceTiming
  • process.release
  • worker_threads

此外,以下 N-API 符号现在可正常工作

  • napi_async_init
  • napi_async_destroy
  • napi_add_finalizer

V8 11.5 和 TypeScript 5.0.4

最后,Deno v1.34 随附 V8 11.5 和 TypeScript 5.0.4。




了解 Deno KV,这是我们为 Deno Deploy 提供的全球分布式数据库,现已进入测试阶段