Chapter 07

包管理与 JSR

新一代 JavaScript 包注册表——JSR 的设计理念与 Deno 2 包管理全貌

JSR:JavaScript Registry

JSR(jsr.io)是由 Deno 团队在 2024 年推出的新一代 JavaScript 包注册表,旨在解决 npm 的几个历史问题:

npm 的问题
  • 发布 TypeScript 需先编译为 JS
  • 类型定义文件(.d.ts)与实现分离
  • 仅支持 Node.js 运行时约定
  • 无内置文档生成
  • 无模块图可视化
JSR 的改进
  • 直接发布 TypeScript 源码
  • 类型内嵌,文档自动生成
  • 支持 Deno/Node/Bun/浏览器
  • 包页面自动生成 API 文档
  • 模块依赖图可视化

jsr: 前缀导入

// 基本用法:jsr:@scope/package@version
import { assertEquals } from "jsr:@std/assert@^1.0.0";
import { join } from "jsr:@std/path@^1.0.0";
import { Hono } from "jsr:@hono/hono@^4.0.0";

// 推荐在 deno.json 中统一管理版本
// {
//   "imports": {
//     "@std/assert": "jsr:@std/assert@^1.0.0"
//   }
// }
// 代码中直接用别名:
import { assertEquals } from "@std/assert";

npm: 前缀兼容 npm 包

// Deno 2 完整支持 npm 包,无需 npm install
import express from "npm:express@4";
import { z } from "npm:zod@3";
import axios from "npm:axios@1";

// 指定精确版本
import { Hono } from "npm:hono@4.2.0";

// 访问子路径
import { cors } from "npm:hono/cors";

// node: 协议访问 Node 内置模块
import { createReadStream } from "node:fs";
import { join } from "node:path";

发布包到 JSR:deno publish

准备包结构

my-package/
├── deno.json        # 包配置
├── mod.ts           # 主入口(约定)
├── utils.ts
└── README.md
// deno.json — 发布配置
{
  "name": "@your-scope/your-package",
  "version": "1.0.0",
  "exports": {
    ".": "./mod.ts",
    "./utils": "./utils.ts"
  },
  "license": "MIT"
}
// mod.ts — 主入口

/**
 * 格式化日期为中文格式
 * @param date 日期对象
 * @returns 格式化字符串,如 "2024年1月15日"
 */
export function formatDate(date: Date): string {
  return `${date.getFullYear()}${date.getMonth() + 1}${date.getDate()}日`;
}

/** 判断是否为闰年 */
export function isLeapYear(year: number): boolean {
  return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
# 预检查(不实际发布,检查问题)
deno publish --dry-run

# 发布(需要先在 jsr.io 注册账号和 scope)
deno publish

# CI 环境使用 token
deno publish --token $JSR_TOKEN

workspace 多包管理(Deno 2 新特性)

Deno 2 支持 workspace,在单个仓库中管理多个相互依赖的包(monorepo):

my-monorepo/
├── deno.json          # 根配置
├── packages/
│   ├── core/
│   │   ├── deno.json  # { "name": "@my/core", "version": "1.0.0" }
│   │   └── mod.ts
│   └── server/
│       ├── deno.json  # { "name": "@my/server", "version": "1.0.0" }
│       └── mod.ts
└── apps/
    └── web/
        ├── deno.json
        └── main.ts
// 根目录 deno.json — workspace 配置
{
  "workspace": [
    "./packages/core",
    "./packages/server",
    "./apps/web"
  ],
  "imports": {
    // 共享依赖统一版本
    "hono": "npm:hono@^4.0.0"
  }
}
// apps/web/main.ts — 引用 workspace 内的包
import { someUtil } from "@my/core";  // 自动解析到 ./packages/core
import { createServer } from "@my/server";

lock 文件管理

Deno 通过 deno.lock 文件锁定依赖版本,确保团队成员使用完全相同的依赖版本:

# 自动生成/更新 deno.lock
deno cache --lock=deno.lock --lock-write main.ts

# 使用 lock 文件(CI 环境推荐)
deno run --lock=deno.lock main.ts

# 更新所有依赖
deno outdated
deno outdated --update --recursive

# deno.json 中启用自动 lock(默认已启用)
// deno.json — lock 配置
{
  "lock": true  // 默认值,生成 deno.lock
  // "lock": false  — 禁用 lock 文件(不推荐生产环境)
}

本章小结:JSR 是 Deno 团队对 npm 多年问题的系统性解决方案——TypeScript 原生、多运行时支持、自动文档生成。Deno 2 通过 jsr: 和 npm: 前缀同时支持两个生态,无需选边站。workspace 让 monorepo 管理变得简单,lock 文件保证依赖一致性。对于新项目,优先使用 jsr: 包;已有 npm 包通过 npm: 前缀无缝引用。