Files
2026-07-13 21:35:40 +08:00

4.0 KiB
Raw Permalink Blame History

name, description
name description
library-development 使用 tsdown 构建和发布 TypeScript 库。适用于创建 npm 包、配置库打包或设置 package.json 导出字段时。

库开发

方面 选择
打包工具 tsdown
输出格式 仅纯 ESM(无 CJS
类型声明 通过 tsdown 生成
导出 通过 tsdown 自动生成

tsdown 配置

使用 tsdown 并启用以下选项:

// tsdown.config.ts
import { defineConfig } from 'tsdown'

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  exports: true,
})
选项 用途
format ['esm'] 纯 ESM,无 CommonJS
dts true 生成 .d.ts 文件
exports true 自动更新 package.json 中的 exports 字段

多个入口点

export default defineConfig({
  entry: [
    'src/index.ts',
    'src/utils.ts',
  ],
  format: ['esm'],
  dts: true,
  exports: true,
})

当运行 tsdown 时,exports: true 选项会自动生成 package.json 中的 exports 字段。


API 稳定性

对于已发布的库,锁定公开 API 表面,使意外的破坏性变更在代码审查中以差异形式显现。

工具 用途
tsnapi 通过 Vitest 将运行时导出与类型声明快照到已提交的 .snapshot.js / .snapshot.d.ts 文件中
tsdown-stale-guard 记录构建输入/输出哈希值,以便针对过时构建运行测试时快速失败

将两者安装为开发依赖。将 tsdown-stale-guard 作为 tsdown 插件接入,使每次构建都记录其哈希值:

// tsdown.config.ts
import { defineConfig } from 'tsdown'
import { StaleGuardRecorder } from 'tsdown-stale-guard'

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  exports: true,
  plugins: [
    StaleGuardRecorder(),
  ],
})

从 Vitest 测试中快照公开 API——优先使用 Vitest 辅助函数而非 tsdown/Rolldown 插件,以便构建配置专注于构建。每个文件通过一个文件级别的 beforeAll(guardStaleBuild) 来确保构建是最新的,从而使已提交的 dist/ 永远不会与源码脱节:

// test/api.test.ts(单个包)
import { beforeAll } from 'vitest'
import { snapshotApiPerEntry } from 'tsnapi/vitest'
import { guardStaleBuild } from 'tsdown-stale-guard'

beforeAll(async () => {
  await guardStaleBuild()
})

await snapshotApiPerEntry(new URL('..', import.meta.url).pathname)

对于 monorepo,将 describePackagesApiSnapshots() 包裹在 describe 中,使每个包的测试套件共享一个过时构建检测门:

// test/api.test.tsmonorepo,从根目录运行)
import { beforeAll, describe } from 'vitest'
import { describePackagesApiSnapshots } from 'tsnapi/vitest'
import { guardStaleBuild } from 'tsdown-stale-guard'

describe('packages api', async () => {
  beforeAll(async () => {
    await guardStaleBuild()
  })

  await describePackagesApiSnapshots()
})

更新快照

在有意的 API 变更之后,一次性重建并更新两个快照:

nr build           # 重新生成 dist/ 和过时构建哈希值
nr test -u         # 更新 .snapshot.js / .snapshot.d.ts 文件

package.json

纯 ESM 库的必填字段:

{
  "type": "module",
  "main": "./dist/index.mjs",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.mts",
  "files": ["dist"],
  "scripts": {
    "build": "tsdown",
    "prepack": "pnpm build",
    "test": "vitest",
    "release": "bumpp -r"
  }
}

exports: true 时,exports 字段由 tsdown 管理。

prepack 脚本

对于每个公开包,在 scripts 中添加 "prepack": "pnpm build"。这确保在发布前(例如运行 npm publishpnpm publish 时)自动构建该包。这可以防止意外发布过时或缺失的构建产物。