名称: publish-package-cicd 描述: 使用 Changesets + npm Trusted Publishers (OIDC) 的 npm 包 CI/CD 发布工作流。适用于为 monorepos 设置自动化 npm 发布、配置 GitHub Actions 进行发布、解决 workspace:* 协议解析问题、修复已发布包中的“找不到模块”错误或调试 npm OIDC 认证。涵盖 Bun + Turborepo + Changesets + npm Trusted Publishers 与 workspace 协议解析。
包发布 CI/CD
使用 Changesets + npm Trusted Publishers (OIDC) 自动化 Bun monorepos 的 npm 发布。无需 npm 令牌 - GitHub Actions 通过 OIDC 认证。
核心工作流
1. 创建 Changeset(手动文件创建)
关键:永远不要交互式运行 bunx changeset。 手动创建 changeset 文件以避免交互式 CLI:
cat > .changeset/your-change-name.md << 'EOF'
---
"package-name": patch
---
变更描述
EOF
版本更新类型:
patch- 错误修复、次要更新 (0.0.x)minor- 新功能、向后兼容 (0.x.0)major- 破坏性变更 (x.0.0)
2. 提交和推送
git add .changeset/your-change-name.md
git commit -m "feat: 您的功能描述"
git push origin main
3. 自动化发布流程
- Changesets Action (
.github/workflows/ci.yml) 检测 changeset 文件 - 创建/更新“chore: release packages”PR,包含版本更新 + CHANGELOG
- PR 合并后 → 触发发布工作流 (
.github/workflows/publish.yml) - 通过 OIDC 发布到 npm(无 npm 令牌)
Trusted Publishers (OIDC) 设置
初始包设置(一次性)
对于每个要发布的包:
-
手动发布 v0.1.0:
cd packages/your-package npm publish --access public -
配置 Trusted Publisher:
- 访问 https://www.npmjs.com/package/your-package/access
- 点击“Trusted Publishers” → “Add”
- 填写:
- 组织:
your-github-org - 仓库:
your-repo-name - 工作流:
publish.yml
- 组织:
- 保存
-
未来发布: 完全通过 GitHub Actions 自动化
OIDC 工作原理
- 无需
NPM_TOKEN密钥 - GitHub Actions 具有
id-token: write权限 - npm 包配置了 Trusted Publisher,指向仓库 + 工作流
- npm CLI 11.5.1+ 自动检测 OIDC 环境
- 自动生成溯源认证
workspace:* 协议解析
问题: package.json 依赖中的 workspace:* 在 npm publish 期间不解析,导致消费者出现“找不到模块”错误。
解决方案: 使用自定义发布脚本进行两步流程:
# 1. 同步 lockfile(从 lockfile 解析 workspace:*)
bun install
# 2. 打包 tarball(将 workspace:* 解析为实际版本)
bun pm pack
# 3. 发布 tarball(支持 npm OIDC)
npm publish <tarball>
为什么不使用 bun publish? Bun 解析 workspace 协议但不支持 npm OIDC - 需要 npm login。
完整实现见 references/publish-script.ts。
忽略的包(非发布)
在 .changeset/config.json 中排除包发布:
{
"ignore": ["@swarmtools/web", "docs-app"]
}
重要: Changeset 忽略仅影响版本控制,而不影响构建。必须也从 turbo 中排除:
# 在 CI 中,从构建中排除忽略的包
bun turbo build --filter='!@swarmtools/web'
常见问题
CLI 二进制脚本“找不到模块”
症状: 发布的包正常工作,但 CLI 二进制脚本因 Cannot find module '@clack/prompts' 失败。
根本原因: 二进制脚本导入是运行时依赖,而不是开发依赖。
修复: 将所有二进制脚本导入移动到 package.json 的 dependencies:
{
"dependencies": {
"@clack/prompts": "^0.7.0", // 由 bin/cli.ts 使用
"commander": "^11.0.0" // 由 bin/cli.ts 使用
}
}
锁文件在 Changeset 更新后过时
症状: 发布选取 workspace:* 依赖的旧版本。
根本原因: bun pm pack 从锁文件解析,锁文件在版本更新后过时。
修复: 在 bun pm pack 之前运行 bun install:
bun install # 同步锁文件与新版本
bun pm pack # 现在打包正确版本
npm publish <tarball>
见 references/publish-script.ts - 自动处理此问题。
本地 bunx changeset version 失败
症状: Error: GITHUB_TOKEN not found
根本原因: Changesets 需要 GitHub API 访问进行 PR/CHANGELOG 生成。在 CI 中工作(有 GITHUB_TOKEN),本地失败。
修复: 不要在本地运行 bunx changeset version 或 bunx changeset publish。让 CI 处理:
- 手动创建 changeset 文件
- 推送到 main
- CI 创建发布 PR
- 合并 PR → 自动发布
Bun Publish vs npm Publish
避免 bun publish - 不支持 npm OIDC(需要 npm login)。
使用 npm publish <tarball> - 支持 OIDC + 在发布由 bun pm pack 创建的 tarball 时解析 workspace 协议。
参考文件
- references/publish-workflow.yml - 完整的 GitHub Actions 工作流,含 OIDC + workspace 解析
- references/changeset-config.json - Changeset 配置,含忽略的包
- references/publish-script.ts - 自定义发布脚本,处理 workspace:* 解析
命令参考
# 创建 changeset(手动文件创建)
cat > .changeset/fix-thing.md << 'EOF'
---
"pkg-name": patch
---
修复了问题
EOF
# 预览版本更新(可选,仅信息性)
bunx changeset status
# 构建包(排除忽略的)
bun turbo build --filter='!@swarmtools/web'
# 发布(仅在 CI 中,通过 publish.yml)
bun install # 同步锁文件
bun pm pack # 创建 tarball,带解析的 workspace:*
npm publish <tarball> # 使用 OIDC 发布
跟踪问题
- Bun 原生 npm 令牌支持: https://github.com/oven-sh/bun/issues/15601
- 解决后,可直接切换到
bun publish - 目前必须使用
npm publish以获得 OIDC 支持
- 解决后,可直接切换到