跳至主要内容

查看目录

发布包

您可以将大多数使用 ESM 模块编写的 JavaScript 和 TypeScript 代码发布为 JSR 包。JSR 包发布到 jsr.io,并且可以从 DenoNode.js 和其他工具中导入。 了解有关使用包的更多信息。

最初编写为使用 package.json 的代码和最初为 Deno 编写的代码都可以发布为 JSR 包。JSR 支持并鼓励发布 TypeScript 源代码,而不是 .js + .d.ts 文件对。这使 JSR 能够提供更有用的自动生成的文档,并有助于在编辑器中提供改进的自动完成。

JSR 包规则

上传到 JSR 的所有包在发布期间都会自动处理和验证,以确保 JSR 上托管的所有代码都遵守一致的规则集。这些规则旨在实现跨环境的可移植性。您的代码必须遵循这些规则才能发布到 JSR。

  • 仅限 ESM 模块:JSR 包发布为 ESM 模块。这意味着您只能发布使用 importexport 关键字的模块。您无法发布 CommonJS 模块。
  • 支持 npm 包:您可以通过在 package.jsondependencies 中指定它们,或在代码中使用 npm: 指定符(例如 import { cloneDeep } from "npm:lodash@4";)来引用它们,来依赖 npm 包。
  • 支持 jsr 包:您可以通过在 package.jsondependencies 中指定它们,或在代码中使用 jsr: 指定符(例如 import { encodeBase64 } from "jsr:@std/encoding@1/base64";)来引用它们,来依赖 JSR 包。
  • node: 内置模块受支持:您可以使用 node: 方案导入 Node.js 内置模块。例如,您可以使用 import { readFile } from "node:fs"; 导入 fs 模块。如果您的包具有 package.json,您也可以使用裸规范(不带 node: 前缀)导入 Node.js 内置模块。
  • 简单文件名:文件名必须与 Windows 和 Unix 兼容。这意味着文件名不能包含 *:? 等字符。您也不能拥有多个具有相同名称但大小写不同的文件。
  • 最好不要使用 TypeScript “慢类型”:为了加快类型检查、支持文档生成和 Node.js 兼容性,JSR 包不应在导出的函数、类或变量中使用某些 TypeScript 类型。这在默认情况下是强制执行的,但可以选择退出。 了解有关“慢类型”的更多信息。
  • 有效的跨文件导入:您包中模块之间的所有相对导入都必须在发布时解析。支持的规范格式取决于是否使用 package.json,并在下面详细说明。

编写代码

仅限 ESM

要发布 JSR 包,您必须首先编写包的代码。JSR 包是用 JavaScript 或 TypeScript 编写的,并作为 ESM 模块发布。

// greet.ts
/**
 * Greet a person.
 * @param name The name of the person to greet.
 */
export function greet(name: string) {
  console.log(`Hello, ${name}!`);
}

相对导入

一个包可以包含多个模块。您可以使用相对导入引用包中的其他模块。您*应该*在导入中使用正确的扩展名 - ./greet.ts 来导入 greet.ts,而不是 ./greet./greet.js

当您的包中存在 package.json 时,模块*可以*使用“松散导入”。使用“松散导入”,您*可以*导入没有扩展名的文件,或者使用 .js 扩展名,即使底层文件是 .ts。您还可以使用带有 index.js 解析的目录导入。

// mod.ts
/**
 * A module providing a function to greet people.
 *
 * @example
 * ```ts
 * import { greet } from "@luca/greet";
 *
 * greet("Luca");
 * ```
 *
 * @module
 */

export * from "./greet.ts";

导入 npm 包

您可以导入 package.json"dependencies" 中指定的 npm 包,导入映射或 deno.json 中指定的 npm 包,或者使用 npm: 说明符在源代码中指定的 npm 包。

// package.json
{
  "dependencies": {
    "chalk": "5"
  }
}
// mod.ts
import * as chalk from "chalk";

import * as express from "npm:express@4";

导入 JSR 包

您可以导入在 package.json"dependencies" 中指定的 JSR 包,在导入映射或 deno.json 中指定的包,或在源代码中使用 jsr: 指定符指定的包。 了解有关使用包的更多信息。

// package.json
{
  "dependencies": {
    "@std/encoding": "npm:@jsr/std__encoding@1"
  }
}
// mod.ts
import * as encoding from "@std/encoding";

import { camelCase } from "jsr:@luca/cases@1";

导入 Node.js 内置模块

您可以使用 node: 方案导入 Node.js 内置模块。如果您的包中存在 package.json,您也可以省略 node: 方案。

// mod.ts
import { readFileSync } from "node:fs";

export function readJsonFile(path: string) {
  return JSON.parse(readFileSync(path, "utf8"));
}

依赖项清单

您可以使用依赖项清单,例如 package.json导入映射(如 deno.json 文件)来简化您的导入。在发布过程中,jsr publish / deno publish 将自动将您源代码中的指定符重写为完全限定的指定符,这些指定符不再需要导入映射 / package.json

// import_map.json / deno.json
{
  "imports": {
    "@luca/greet": "jsr:@luca/greet@1",
    "@std/path": "jsr:@std/path@1"
  }
}
// mod.ts
export { greet } from "@luca/greet";
export { join } from "@std/path";

防止缓慢类型

在编写 TypeScript 时,您应该确保您的代码不使用“缓慢类型”,这些类型会阻止 JSR 生成文档,为 npm 兼容层生成类型声明,并加快对您包的消费者的类型检查。 了解有关“缓慢类型”的更多信息。

您可以使用 --allow-slow-types 标志临时绕过此限制。这将导致所有用户的类型检查速度明显变慢。此外,文档生成和节点兼容性也会受到影响。考虑修复缓慢类型以避免这些缺点,而不是使用此标志。

包配置⽂件

在您编写完代码后,您需要为您的包添加一个配置⽂件。此⽂件包含包元数据,例如名称、版本和⼊⼝点。此⽂件应命名为 jsr.json。Deno 用户也可以将其 deno.json 中包含所需的 JSR 属性,以避免创建另⼀个⽂件。

// jsr.json / deno.json
{
  "name": "@luca/greet",
  "version": "1.0.0",
  "exports": "./mod.ts"
}

详细了解配置 JSR 包。

创建作用域和包

JSR 组织成作用域。作用域是包的集合。作用域类似于 npm 组织。作用域以 @ 符号为前缀,后跟名称。例如,@luca 是⼀个作用域。

您可以在jsr.io/new创建作用域。作用域名称必须在 2 到 32 个字符之间,并且只能包含⼩写字母、数字和连字符。只有在名称未被占用时,您才能创建作用域。与现有作用域名称⾮常相似的作用域名称(例如,仅在连字符上有所不同的名称)是被禁止的。详细了解作用域。

创建作用域后,您可以在该作用域中创建包。您可以在jsr.io/new创建包。包名称必须在 2 到 20 个字符之间,并且只能包含⼩写字母、数字和连字符。只有在名称未被占用时,您才能创建包。与现有包名称⾮常相似的包名称(例如,仅在连字符上有所不同的名称)是被禁止的。详细了解包。

验证您的包

发布包,包括执行干运行以确认您的包符合所有 JSR 规则,需要使用 jsr publishdeno publish。这两个命令的语法基本相同。根据您的工具,您可以按如下方式调用发布命令。

# deno
deno publish
# npm
npx jsr publish
# yarn
yarn dlx jsr publish
# pnpm
pnpm dlx jsr publish

您可以使用 --dry-run 标志运行 jsr publish,以执行在实际发布期间会发生的全部发布验证。这将打印出将要发布的文件列表,但不会真正发布到注册表。

# deno
$ deno publish --dry-run
# npm
$ npx jsr publish --dry-run
# yarn
yarn dlx jsr publish --dry-run
# pnpm
pnpm dlx jsr publish --dry-run

从本地机器发布

您可以使用 jsr publishdeno publish 命令从本地机器发布包。

身份验证将通过您的浏览器进行,因此您无需向 CLI 提供任何凭据。

进入您的包的根目录(包含 jsr.json / deno.json 文件),然后运行 jsr publish

# deno
$ deno publish
# npm
$ npx jsr publish
# yarn
yarn dlx jsr publish
# pnpm
pnpm dlx jsr publish

当您运行 jsr publish 时,CLI 将打开您的浏览器以批准发布。如果您尚未登录,系统将提示您使用您的 JSR 帐户登录。登录后,系统将提示您授予 CLI 发布您尝试发布的特定包的权限。单击“允许”以授予 CLI 访问权限。

CLI 现在将您的包上传到 JSR 注册表。上传完成后,CLI 将输出您可以在 JSR 网站上查看该包的 URL。

在发布过程中,JSR CLI 和 JSR 服务器都会对您的包进行许多检查,以确保其有效性。如果任何检查失败,CLI 将输出错误消息。您必须修复这些错误才能再次尝试发布。 了解有关排查发布错误的更多信息。

从 GitHub Actions 发布

JSR 针对从 GitHub Actions 发布包提供了强大的支持。这使您无需配置任何密钥或身份验证即可从 CI 自动发布包。

要从 GitHub Actions 发布,您首先必须将您的包链接到您的 GitHub 存储库,方法是在 JSR 中的包设置中进行操作。为此,请访问 JSR 上您包的设置选项卡 jsr.io,输入您的 GitHub 存储库名称,然后单击“链接”。

将您的包链接到 GitHub 存储库后,您就可以从 GitHub Actions 发布。为此,请在您的存储库中创建一个工作流文件,例如在 .github/workflows/publish.yml 中。在此工作流文件中,您可以创建一个使用 jsr publish 命令发布包的作业。

# .github/workflows/publish.yml

name: Publish

on:
  push:
    branches:
      - main

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write # The OIDC ID token is used for authentication with JSR.    
    steps:
      - uses: actions/checkout@v4
      - run: npx jsr publish

此工作流将在您每次推送到存储库的 main 分支时运行。它会将您的包发布到 JSR,并会根据您 jsr.json 文件中的版本自动使用正确的版本号。如果您的 jsr.json 文件中指定的版本已发布到 JSR,则 jsr publish 不会尝试发布。

过滤文件

jsr publish 将忽略列在您包根目录中的 .gitignore 文件中的文件。此外,您可以在 jsr.json / deno.json 文件中指定 includeexclude 字段,以包含、忽略或取消忽略特定文件。

例如,要仅选择性地包含某些文件,可以使用 `include` 选项指定匹配所有文件的通配符。

// jsr.json
{
  "name": "@luca/greet",
  "version": "1.0.0",
  "exports": "./src/mod.ts",
  // note: this will be collapsed down to just include in the future
  "publish": {
    "include": [
      "LICENSE",
      "README.md",
      "src/**/*.ts"
    ]
  }
}

您也可以通过 `exclude` 选项排除某些文件。

// jsr.json
{
  "name": "@luca/greet",
  "version": "1.0.0",
  "exports": "./src/mod.ts",
  "publish": {
    "include": [
      "LICENSE",
      "README.md",
      "src/**/*.ts"
    ],
    "exclude": [
      "src/tests"
    ]
  }
}

在使用 Deno 时,`deno.json` 中的 `include` 和 `exclude` 选项也用于许多其他 Deno 子命令,例如 `deno test` 和 `deno bundle`。您可以在 `deno.json` 文件中使用 `publish.include` 和 `publish.exclude` 来指定仅适用于 `deno publish` 的选项。

// deno.json
{
  "name": "@luca/greet",
  "version": "1.0.0",
  "exports": "./dist/mod.ts",
  "publish": {
    "include": ["src"],
    "exclude": ["src/tests"]
  }
}

在不使用“include”的情况下取消 .gitignore 文件

您的包可能有一个 ` .gitignore` 文件,其内容如下:

.env
dist/

在这种情况下,发布时将忽略 `dist/` 目录中的任何文件以及名为 ` .env` 的任何文件。

但是,如果您想发布 `dist/` 目录,因为您有指向它(或其子目录)的 `“exports”`,这可能不方便。在这种情况下,您可以通过在 `jsr.json` / `deno.json` 文件的 `exclude` 字段中使用否定来取消忽略 `dist/` 目录。

// jsr.json
{
  "name": "@luca/greet",
  "version": "1.0.0",
  "exports": "./dist/mod.ts",
  "publish": {
    "exclude": ["!dist"]
  }
}

在这种情况下,即使 `dist/` 目录列在 ` .gitignore` 文件中,它也会在发布时被包含。

在 GitHub 上编辑此页面