在此页面上
模块和依赖项
Deno 使用 ECMAScript 模块 作为其默认模块系统,以符合现代 JavaScript 标准,并促进更高效和一致的开发体验。它是 JavaScript 模块的官方标准,允许更好的 tree-shaking、改进的工具集成以及跨不同环境的本机支持。
通过采用 ECMAScript 模块,Deno 确保与不断发展的 JavaScript 生态系统的兼容性。对于开发人员来说,这意味着一个精简且可预测的模块系统,避免了与 CommonJS 等旧模块格式相关的复杂性。
导入模块 跳转到标题
在此示例中,add
函数是从本地 calc.ts
模块导入的。
export function add(a: number, b: number): number {
return a + b;
}
// imports the `calc.ts` module next to this file
import { add } from "./calc.ts";
console.log(add(1, 2)); // 3
您可以通过在包含 main.ts
和 calc.ts
的目录中调用 deno run main.ts
来运行此示例。
使用 ECMAScript 模块,本地导入说明符必须始终包含完整的文件扩展名。它不能被省略。
// WRONG: missing file extension
import { add } from "./calc";
// CORRECT: includes file extension
import { add } from "./calc.ts";
导入第三方模块和库 跳转到标题
当在 Deno 中使用第三方模块时,请使用与本地代码相同的 import
语法。第三方模块通常从远程注册表导入,并以 jsr:
、 npm:
或 https://
开头。
import { camelCase } from "jsr:@luca/[email protected]";
import { say } from "npm:[email protected]";
import { pascalCase } from "https://deno.land/x/case/mod.ts";
Deno 推荐 JSR,这是一个现代 JavaScript 注册表,用于第三方模块。在那里,您会找到大量文档完善的 ES 模块用于您的项目,包括 Deno 标准库。
您可以在此处阅读有关 Deno 对 npm 包支持的更多信息。
管理第三方模块和库 跳转到标题
在多个文件中导入模块时,键入带有完整版本说明符的模块名称可能会变得繁琐。您可以使用 deno.json
文件中的 imports
字段集中管理远程模块。我们将此 imports
字段称为 导入映射,它基于 导入映射标准。
{
"imports": {
"@luca/cases": "jsr:@luca/cases@^1.0.0",
"cowsay": "npm:cowsay@^1.6.0",
"cases": "https://deno.land/x/case/mod.ts"
}
}
使用重映射的说明符,代码看起来更简洁
import { camelCase } from "@luca/cases";
import { say } from "cowsay";
import { pascalCase } from "cases";
重映射的名称可以是任何有效的说明符。这是 Deno 中一个非常强大的功能,可以重映射任何内容。在此处了解有关导入映射可以执行的操作的更多信息:此处。
区分 deno.json
中的 imports
或 importMap
与 --import-map
选项 跳转到标题
导入映射标准 要求每个模块有两个条目:一个用于模块说明符,另一个用于带有尾部 /
的说明符。这是因为该标准仅允许每个模块说明符有一个条目,而尾部 /
表示该说明符引用一个目录。例如,当使用 --import-map import_map.json
选项时,import_map.json
文件必须包含每个模块的两个条目(请注意使用 jsr:/@std/async
而不是 jsr:@std/async
)
{
"imports": {
"@std/async": "jsr:@std/async@^1.0.0",
"@std/async/": "jsr:/@std/async@^1.0.0/"
}
}
相比之下,deno.json
扩展了导入映射标准。当您在 deno.json
中使用 imports 字段或通过 importMap
字段引用 import_map.json
文件时,您只需要指定不带尾部 /
的模块说明符
{
"imports": {
"@std/async": "jsr:@std/async@^1.0.0"
}
}
使用 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]
{
"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
{
"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.4 和 1.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.0 、1.2.1 等。 |
1.2.x |
1.x |
主要版本 1 内的任何次要版本和补丁版本。例如,1.0.0 、1.1.0 、1.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"
}
}
支持 HTTPS 导入使我们能够支持以下 JavaScript CDN,因为它们提供对 JavaScript 模块的 URL 访问
如果您有一个小的、通常是单文件的 Deno 项目,不需要任何其他配置,则 HTTPS 导入非常有用。使用 HTTPS 导入,您可以完全避免使用 deno.json
文件。但是,不建议在较大的应用程序中使用这种导入风格,因为您最终可能会遇到版本冲突(不同的文件使用不同的版本说明符)。
谨慎使用 HTTPS 导入,并且仅从受信任的来源使用。如果服务器被入侵,它可能会向您的应用程序提供恶意代码。如果您在不同的文件中导入不同的版本,它们也可能导致版本控制问题。HTTPS 导入仍然受支持,但我们建议使用包注册表以获得最佳体验。
覆盖依赖项 跳转到标题
Deno 提供了覆盖依赖项的机制,使开发人员能够在开发或测试期间使用自定义或本地版本的库。
注意:如果您需要本地缓存和修改依赖项以供跨构建使用,请考虑供应商化远程模块。
覆盖本地 JSR 包 跳转到标题
对于熟悉 Node.js 中的 npm link
的开发人员,Deno 通过 deno.json
中的 patch
字段为本地 JSR 包提供了类似的功能。这允许您在开发期间使用本地版本覆盖依赖项,而无需发布它们。
示例
{
"patch": [
"../some-package-or-workspace"
]
}
要点
patch
字段接受包含 JSR 包或工作区的目录的路径。如果您引用工作区中的单个包,则将包含整个工作区。- 此功能仅在工作区根目录中受到尊重。在其他地方使用
patch
将触发警告。 - 目前,
patch
仅限于 JSR 包。尝试修补npm
包将导致警告,但不会产生任何影响。
限制
- 尚不支持
npm
包覆盖。计划在未来的更新中支持。 - 基于 Git 的依赖项覆盖不可用。
patch
字段需要在工作区根目录中进行正确的配置。- 此功能是实验性的,可能会根据用户反馈进行更改。
覆盖 NPM 包 跳转到标题
我们计划使用上述补丁功能支持 NPM 包,但在那之前,如果您有一个 node_modules
目录,则可以使用 npm link
而无需更改即可实现相同的效果。这通常通过在 deno.json
文件中设置 { "nodeModulesDir": "manual" }
来完成。另请参阅有关 node_modules
的文档
覆盖 HTTPS 导入 跳转到标题
Deno 还允许通过 deno.json
中的 importMap
字段覆盖 HTTPS 导入。当使用本地修补版本替换远程依赖项以进行调试或临时修复时,此功能特别有用。
示例
{
"imports": {
"example/": "https://deno.land/x/example/"
},
"scopes": {
"https://deno.land/x/example/": {
"https://deno.land/x/[email protected]/mod.ts": "./patched/mod.ts"
}
}
}
要点
- 导入映射中的
scopes
字段允许您将特定导入重定向到备用路径。 - 这通常用于使用本地文件覆盖远程依赖项以进行测试或开发目的。
- 导入映射仅适用于项目的根目录。依赖项中嵌套的导入映射将被忽略。
供应商化远程模块 跳转到标题
如果您的项目具有外部依赖项,您可能希望将它们本地存储,以避免每次构建项目时都从互联网下载它们。当在 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 仅使用本地可用的模块。
对于更高级的覆盖,例如在开发期间替换依赖项,请参阅 覆盖依赖项。
发布模块 跳转到标题
任何定义导出的 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 的依赖树中存在任何尚未缓存的依赖项,则这将失败。
完整性检查和锁定文件 跳转到标题
假设您的模块依赖于位于 https://some.url/a.ts 的远程模块。当您首次编译模块时,将获取、编译和缓存 a.ts
。此缓存版本将一直使用,直到您在不同的机器(例如在生产环境中)上运行模块或手动重新加载缓存(使用类似 deno install --reload
的命令)。
但是,如果 https://some.url/a.ts
的内容发生更改怎么办?这可能会导致您的生产模块使用与本地模块不同的依赖项代码运行。为了检测到这一点,Deno 使用完整性检查和锁定文件。
Deno 使用 deno.lock
文件来检查外部模块的完整性。要选择使用锁定文件,请执行以下操作之一
-
在当前目录或祖先目录中创建一个
deno.json
文件,这将自动在deno.lock
处创建一个附加锁定文件。请注意,可以通过在 deno.json 中指定以下内容来禁用此功能
deno.json{ "lock": false }
-
使用
--lock
标志启用和指定锁定文件检查。
冻结锁定文件 跳转到标题
默认情况下,Deno 使用附加锁定文件,其中新依赖项被添加到锁定文件中,而不是报错。
在某些情况下(例如,CI 管道或生产环境),这可能不是期望的行为,在这些情况下,您宁愿 Deno 在遇到以前从未见过的依赖项时报错。要启用此功能,您可以指定 --frozen
标志或在 deno.json 文件中设置以下内容
{
"lock": {
"frozen": true
}
}
当使用冻结锁定文件运行 deno 命令时,任何尝试使用新内容更新锁定文件的操作都将导致命令退出并显示本应进行的修改的错误。
如果您希望更新锁定文件,请在命令行上指定 --frozen=false
以暂时禁用冻结锁定文件。
更改锁定文件路径 跳转到标题
可以通过指定 --lock=deps.lock
或在 Deno 配置文件中指定以下内容来配置锁定文件路径
{
"lock": {
"path": "deps.lock"
}
}
私有仓库 跳转到标题
在某些情况下,您可能想要加载位于私有仓库中的远程模块,例如 GitHub 上的私有仓库。
Deno 支持在请求远程模块时发送持有者令牌。持有者令牌是 OAuth 2.0 中使用的主要访问令牌类型,并受到托管服务(例如,GitHub、GitLab、Bitbucket、Cloudsmith 等)的广泛支持。
DENO_AUTH_TOKENS 跳转到标题
Deno CLI 将查找名为 DENO_AUTH_TOKENS
的环境变量,以确定在请求远程模块时应考虑使用哪些身份验证令牌。环境变量的值格式为 n 个以分号 (;
) 分隔的令牌,其中每个令牌可以是
- 持有者令牌,格式为
{token}@{hostname[:port]}
或 - 基本身份验证数据,格式为
{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 并转到设置 -> 开发人员设置 -> 个人访问令牌来完成此操作
然后,您将选择生成新令牌并为您的令牌提供描述和对 repo
范围的适当访问权限。repo
范围将启用读取文件内容(有关 GitHub 文档中的范围的更多信息)
创建后,GitHub 将单次显示新令牌,您希望在环境变量中使用该值
为了访问私有仓库中包含的模块在 GitHub 上,您将希望在 DENO_AUTH_TOKENS
环境变量中使用为 raw.githubusercontent.com
主机名限定范围的生成的令牌。例如
DENO_AUTH_TOKENS=[email protected]
这应该允许 Deno 访问令牌颁发给的用户有权访问的任何模块。
当令牌不正确或用户无权访问模块时,GitHub 将发出 404 Not Found
状态,而不是未经授权的状态。因此,如果您收到错误,指示您尝试访问的模块在命令行上找不到,请检查环境变量设置和个人访问令牌设置。
此外,deno run -L debug
应该打印一条调试消息,说明从环境变量中解析出的令牌数量。如果它认为任何令牌格式错误,它将打印一条错误消息。出于安全目的,它不会打印有关令牌的任何详细信息。