跳至主要内容
在本页

模块和依赖项

Deno 使用 ECMAScript 模块 作为其默认模块系统,以符合现代 JavaScript 标准并提升更高效和一致的开发体验。它是 JavaScript 模块的官方标准,允许更好的摇树优化、改进的工具集成以及跨不同环境的原生支持。

通过采用 ECMAScript 模块,Deno 确保与不断发展的 JavaScript 生态系统的兼容性。对于开发者来说,这意味着一个简化且可预测的模块系统,避免了与 CommonJS 等传统模块格式相关的复杂性。

导入模块 跳转到标题

在此示例中,从本地 calc.ts 模块导入 add 函数。

calc.ts
export function add(a: number, b: number): number {
  return a + b;
}
main.ts
// imports the `calc.ts` module next to this file
import { add } from "./calc.ts";

console.log(add(1, 2)); // 3

您可以在包含 main.tscalc.ts 的目录中通过调用 deno run main.ts 来运行此示例。

使用 ECMAScript 模块时,本地导入说明符必须始终包含完整的文件扩展名,不能省略。

example.ts
// WRONG: missing file extension
import { add } from "./calc";

// CORRECT: includes file extension
import { add } from "./calc.ts";

导入第三方模块和库 跳转到标题

在 Deno 中使用第三方模块时,请使用与本地代码相同的 import 语法。第三方模块通常从远程注册表导入,并以 jsr:npm:https:// 开头。

main.ts
import { camelCase } from "jsr:@luca/[email protected]";
import { say } from "npm:[email protected]";
import { pascalCase } from "https://deno.land/x/case/mod.ts";

Deno 推荐使用现代 JavaScript 注册表 JSR 来获取第三方模块。在那里,您可以找到许多为您的项目准备的文档完善的 ES 模块,包括 Deno 标准库

您可以在此处阅读有关 Deno 对 npm 包支持的更多信息

管理第三方模块和库 跳转到标题

在多个文件中导入远程模块时,完整键入模块名称和版本说明符可能会变得很繁琐。您可以使用 deno.json 文件中的 imports 字段集中管理远程模块。我们将此 imports 字段称为**导入映射**,它基于 导入映射标准

deno.json
{
  "imports": {
    "@luca/cases": "jsr:@luca/cases@^1.0.0",
    "cowsay": "npm:cowsay@^1.6.0",
    "cases": "https://deno.land/x/case/mod.ts"
  }
}

使用重新映射的说明符后,代码看起来更简洁

main.ts
import { camelCase } from "@luca/cases";
import { say } from "cowsay";
import { pascalCase } from "cases";

重新映射的名称可以是任何有效的说明符。这是 Deno 中一个非常强大的功能,可以重新映射任何内容。您可以在此处了解更多关于导入映射的功能。

使用 deno add 添加依赖项 跳转到标题

使用 deno add 子命令可以轻松完成安装过程。它会自动将您请求的最新版本包添加到 deno.json 中的 imports 部分。

# Add the latest version of the module to deno.json
$ deno add jsr:@luca/cases
Add @luca/cases - jsr:@luca/[email protected]
deno.json
{
  "imports": {
    "@luca/cases": "jsr:@luca/cases@^1.0.0"
  }
}

您还可以指定确切的版本

# Passing an exact version
$ deno add jsr:@luca/[email protected]
Add @luca/cases - jsr:@luca/[email protected]

deno add 参考中了解更多信息。

您还可以使用 deno remove 删除依赖项

$ deno remove @luca/cases
Remove @luca/cases
deno.json
{
  "imports": {}
}

deno remove 参考中了解更多信息。

包版本 跳转到标题

可以为要导入的包指定版本范围。这是使用 @ 符号后跟版本范围说明符来完成的,并遵循 semver 版本控制方案。

例如

@scopename/mypackage           # highest version
@scopename/[email protected]    # exact version
@scopename/mypackage@16        # highest 16.x version >= 16.0.0
@scopename/mypackage@^16.1.0   # highest 16.x version >= 16.1.0
@scopename/mypackage@~16.1.0   # highest 16.1.x version >= 16.1.0

以下是指定版本或范围的所有方法的概述

符号 描述 示例
1.2.3 确切版本。仅使用此特定版本。 1.2.3
^1.2.3 兼容 1.2.3 版本。允许不更改最左边非零数字的更新。
例如,允许 1.2.41.3.0,但不允许 2.0.0
^1.2.3
~1.2.3 大约相当于 1.2.3 版本。允许更新补丁版本。
例如,允许 1.2.4,但不允许 1.3.0
~1.2.3
>=1.2.3 大于或等于 1.2.3 版本。允许 1.2.3 或更高版本。 >=1.2.3
<=1.2.3 小于或等于 1.2.3 版本。允许 1.2.3 或更低版本。 <=1.2.3
>1.2.3 大于 1.2.3 版本。仅允许高于 1.2.3 的版本。 >1.2.3
<1.2.3 小于 1.2.3 版本。仅允许低于 1.2.3 的版本。 <1.2.3
1.2.x 次要版本 1.2 中的任何补丁版本。例如,1.2.01.2.1 等。 1.2.x
1.x 主要版本 1 中的任何次要版本和补丁版本。例如,1.0.01.1.01.2.0 等。 1.x
* 允许任何版本。 *

HTTPS 导入 跳转到标题

Deno 也支持直接引用 HTTP/HTTPS URL 的导入语句

import { Application } from "https://deno.land/x/oak/mod.ts";

或者作为 deno.json 导入映射的一部分

{
  "imports": {
    "oak": "https://deno.land/x/oak/mod.ts"
  }
}

由于以下 JavaScript CDN 提供了对 JavaScript 模块的 URL 访问,因此支持 HTTPS 导入使我们能够支持它们:

如果您有一个小型(通常是单个文件)的 Deno 项目,并且不需要任何其他配置,那么 HTTPS 导入非常有用。使用 HTTPS 导入,您可以完全避免使用 deno.json 文件。然而,不建议在较大的应用程序中使用这种导入方式,因为您最终可能会遇到版本冲突(不同的文件使用不同的版本说明符)。

信息

请谨慎使用 HTTPS 导入,并且只从受信任的来源导入。如果服务器遭到入侵,它可能会向您的应用程序提供恶意代码。如果您在不同的文件中导入不同的版本,它们也可能导致版本控制问题。HTTPS 导入仍然受支持,但我们建议使用包注册表以获得最佳体验。

覆盖 HTTPS 导入 跳转到标题

导入映射非常有用的另一种情况是覆盖特定模块中的 HTTPS 导入。

假设您要将 https://deno.land/x/[email protected]/mod.ts 说明符(在来自 https://deno.land/x/example/ 的文件中使用)覆盖为本地补丁版本。您可以通过在导入映射中使用如下所示的作用域来实现此目的

{
  "imports": {
    "example/": "https://deno.land/x/example/"
  },
  "scopes": {
    "https://deno.land/x/example/": {
      "https://deno.land/x/[email protected]/mod.ts": "./patched/mod.ts"
    }
  }
}

注意

HTTPS 导入没有包的概念。仅使用项目根目录下的导入映射。URL 依赖项中使用的导入映射将被忽略。

发布模块 跳转到标题

任何定义了导出的 Deno 程序都可以作为模块发布。这允许其他开发人员在他们自己的项目中导入和使用您的代码。模块可以发布到

  • JSR - 推荐,原生支持 TypeScript 并自动为您生成文档
  • npm - 使用 dnt 创建 npm 包
  • deno.land/x - 对于 HTTPS 导入,如果可能,请改用 JSR

重新加载模块 跳转到标题

默认情况下,Deno 使用全局缓存目录 (DENO_DIR) 来存放下载的依赖项。此缓存由所有项目共享。

您可以使用 --reload 标志强制 deno 重新获取模块并将其重新编译到缓存中。

# Reload everything
deno run --reload my_module.ts

# Reload a specific module
deno run --reload=jsr:@std/fs my_module.ts

仅使用缓存的模块 跳转到标题

要强制 Deno 仅使用以前缓存的模块,请使用 --cached-only 标志

deno run --cached-only mod.ts

如果 mod.ts 的依赖项树中存在尚未缓存的依赖项,则此操作将失败。

将远程模块加入 vendor 跳转到标题

如果您的项目具有外部依赖项,您可能希望将它们存储在本地,以避免每次构建项目时都从互联网下载它们。在 CI 服务器或 Docker 容器中构建项目,或者修补或修改远程依赖项时,此功能尤其有用。

Deno 通过 deno.json 文件中的设置提供此功能

{
  "vendor": true
}

将上述代码段添加到您的 deno.json 文件中,Deno 将在项目运行时将所有依赖项本地缓存在 vendor 目录中,或者您可以选择运行 deno install --entrypoint 命令立即缓存依赖项

deno install --entrypoint main.ts

然后,您可以使用 deno run 照常运行应用程序

deno run main.ts

完成依赖项缓存后,您可以使用 --cached-only 标志运行 main.ts,无需联网。此标志强制 Deno 仅使用本地可用的模块。

完整性检查和锁文件 跳转到标题

假设您的模块依赖于位于 https://some.url/a.ts 的远程模块。当您首次编译模块时,会获取、编译并缓存 a.ts。此缓存版本将一直使用,直到您在其他机器上运行模块(例如在生产环境中)或手动重新加载缓存(使用类似 deno install --reload 的命令)。

但是,如果 https://some.url/a.ts 的内容发生变化怎么办?这可能导致您的生产模块运行的依赖项代码与本地模块不同。为了检测这种情况,Deno 使用完整性检查和锁文件。

Deno 使用 deno.lock 文件来检查外部模块的完整性。要启用锁文件,您可以:

  1. 在当前目录或祖先目录中创建一个 deno.json 文件,这将自动在 deno.lock 创建一个增量锁文件。

    请注意,可以通过在 deno.json 中指定以下内容来禁用此功能

    deno.json
    {
      "lock": false
    }
    
  2. 使用 --lock 标志启用并指定锁文件检查。

冻结锁文件 跳转到标题

默认情况下,Deno 使用增量锁文件,其中新的依赖项会被添加到锁文件中,而不是报错。

在某些情况下(例如 CI 管道或生产环境),您可能希望 Deno 在遇到以前从未见过的依赖项时报错,而不是自动添加。要启用此功能,您可以指定 --frozen 标志或在 deno.json 文件中设置以下内容

deno.json
{
  "lock": {
    "frozen": true
  }
}

当使用冻结的锁文件运行 deno 命令时,任何尝试用新内容更新锁文件的操作都将导致命令以错误退出,并显示将要进行的修改。

如果您希望更新锁文件,请在命令行上指定 --frozen=false 以临时禁用冻结的锁文件。

更改锁文件路径 跳转到标题

可以通过指定 --lock=deps.lock 或在 Deno 配置文件中指定以下内容来配置锁文件路径

deno.json
{
  "lock": {
    "path": "deps.lock"
  }
}

私有仓库 跳转到标题

注意

如果您正在寻找私有 npm 注册表和 .npmrc 支持,请访问npm 支持页面。

在某些情况下,您可能希望加载位于*私有*仓库中的远程模块,例如 GitHub 上的私有仓库。

Deno 支持在请求远程模块时发送 Bearer 令牌。Bearer 令牌是 OAuth 2.0 使用的主要访问令牌类型,并且受到托管服务(例如 GitHub、GitLab、Bitbucket、Cloudsmith 等)的广泛支持。

DENO_AUTH_TOKENS 跳转到标题

Deno CLI 将查找名为 DENO_AUTH_TOKENS 的环境变量,以确定在请求远程模块时应考虑使用哪些身份验证令牌。环境变量的值的格式是由分号 (;) 分隔的 *n* 个令牌,其中每个令牌可以是:

  • 格式为 {token}@{hostname[:port]} 的 Bearer 令牌,或
  • 格式为 {username}:{password}@{hostname[:port]} 的基本身份验证数据

例如,deno.land 的单个令牌如下所示

DENO_AUTH_TOKENS=[email protected]

或者

DENO_AUTH_TOKENS=username:[email protected]

多个令牌如下所示

DENO_AUTH_TOKENS=[email protected];[email protected]:8080;username:[email protected]

当 Deno 获取远程模块时,如果远程模块的主机名与请求的主机名匹配,Deno 会将请求的 Authorization 标头设置为 Bearer {token}Basic {base64EncodedData} 的值。这允许远程服务器识别该请求是与特定已认证用户关联的授权请求,并提供对服务器上相应资源和模块的访问权限。

GitHub 跳转到标题

要访问 GitHub 上的私有仓库,您需要为自己创建一个*个人访问令牌*。您可以通过登录 GitHub 并进入*设置 -> 开发者设置 -> 个人访问令牌*来完成此操作。

Personal access tokens settings on GitHub

然后,您需要选择*生成新令牌*,并为您的令牌提供描述和对 repo 范围的适当访问权限。repo 范围将启用读取文件内容(更多信息请参阅GitHub 文档中的范围)。

Creating a new personal access token on GitHub

创建完成后,GitHub 将只显示一次新令牌,您需要将该令牌的值用于环境变量中。

Display of newly created token on GitHub

为了访问 GitHub 上私有仓库中包含的模块,您需要在 DENO_AUTH_TOKENS 环境变量中使用生成的令牌,并将其作用域设置为 raw.githubusercontent.com 主机名。例如:

DENO_AUTH_TOKENS=[email protected]

这应该允许 Deno 访问为其颁发令牌的用户有权访问的任何模块。

当令牌不正确或用户无权访问模块时,GitHub 将返回 404 Not Found 状态,而不是未授权状态。因此,如果您在命令行上收到您尝试访问的模块未找到的错误,请检查环境变量设置和个人访问令牌设置。

此外,deno run -L debug 应该会打印一条关于从环境变量中解析出的令牌数量的调试消息。如果它认为任何令牌格式错误,它将打印一条错误消息。出于安全考虑,它不会打印任何有关令牌的详细信息。