发布包
您可以将大多数使用 ESM 模块编写的 JavaScript 和 TypeScript 代码发布为 JSR 包。JSR 包发布到 jsr.io,并且可以从 Deno、Node.js 和其他工具中导入。 了解有关使用包的更多信息。
最初编写为使用 package.json
的代码和最初为 Deno 编写的代码都可以发布为 JSR 包。JSR 支持并鼓励发布 TypeScript 源代码,而不是 .js
+ .d.ts
文件对。这使 JSR 能够提供更有用的自动生成的文档,并有助于在编辑器中提供改进的自动完成。
JSR 包规则
上传到 JSR 的所有包在发布期间都会自动处理和验证,以确保 JSR 上托管的所有代码都遵守一致的规则集。这些规则旨在实现跨环境的可移植性。您的代码必须遵循这些规则才能发布到 JSR。
- 仅限 ESM 模块:JSR 包发布为 ESM 模块。这意味着您只能发布使用
import
和export
关键字的模块。您无法发布 CommonJS 模块。 - 支持 npm 包:您可以通过在
package.json
的dependencies
中指定它们,或在代码中使用npm:
指定符(例如import { cloneDeep } from "npm:lodash@4";
)来引用它们,来依赖 npm 包。 - 支持 jsr 包:您可以通过在
package.json
的dependencies
中指定它们,或在代码中使用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 publish
或 deno 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 publish
或 deno 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
文件中指定 include
和 exclude
字段,以包含、忽略或取消忽略特定文件。
例如,要仅选择性地包含某些文件,可以使用 `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` 文件中,它也会在发布时被包含。