如何安全同时发布两个npm包?实现类似Maven的原子发布
实现npm多包原子发布(类似Maven父pom的部署效果)
核心思路
要实现"要么全发布成功,要么全不发布"的原子性,需要通过预发布验证+原子发布/回滚的组合流程来实现——npm本身没有原生多包原子发布机制,需借助工具或自定义脚本达成类似Maven的效果。
方案一:npm Workspace + 自定义脚本(适合轻量场景)
1. 配置根目录package.json
在project根目录创建package.json,启用npm工作区来统一管理子包:
{ "name": "project-root", "private": true, "workspaces": ["package1", "package2"], "scripts": { "prepublish": "npm run validate && npm run sync-version", "validate": "cd package1 && npm run test && cd ../package2 && npm run test", "sync-version": "node ./sync-version.js", "publish-all": "npm run prepublish && npm run publish-packages || npm run rollback-publish" } }
private: true避免根包被误发布workspaces关联两个子包,方便统一执行脚本和管理依赖
2. 版本同步脚本(sync-version.js)
确保两个子包版本完全一致,模拟Maven父pom的统一版本管理:
const fs = require('fs'); const path = require('path'); // 以根包版本作为统一版本号,也可改为手动传入 const rootPkg = require('./package.json'); const targetVersion = rootPkg.version; // 更新package1版本 const pkg1Path = path.join(__dirname, 'package1', 'package.json'); const pkg1 = require(pkg1Path); pkg1.version = targetVersion; fs.writeFileSync(pkg1Path, JSON.stringify(pkg1, null, 2)); // 更新package2版本 const pkg2Path = path.join(__dirname, 'package2', 'package.json'); const pkg2 = require(pkg2Path); pkg2.version = targetVersion; fs.writeFileSync(pkg2Path, JSON.stringify(pkg2, null, 2));
3. 发布与回滚逻辑
- 预发布验证:
prepublish先执行测试用例、同步版本,确保子包状态正常 - 发布脚本:
publish-packages内容如下,按顺序发布子包:
cd package1 && npm publish && cd ../package2 && npm publish
- 回滚脚本:若第二个包发布失败,立即撤销第一个已发布的包(注意:npm撤销有严格限制):
cd package1 && npm unpublish @your-scope/package1@$(node -p "require('./package1/package.json').version") --force
提示:
npm unpublish仅支持发布72小时内、未被其他包依赖的版本,仅适合紧急回滚场景,核心还是要靠预发布测试减少失败概率。
方案二:使用Lerna(专业多包管理工具)
Lerna是专为多包仓库设计的工具,原生支持原子发布模式:
1. 安装并初始化Lerna
npm install lerna -D lerna init
2. 配置lerna.json
修改根目录的lerna.json,开启原子发布:
{ "packages": ["package1", "package2"], "version": "0.0.0", "command": { "publish": { "atomic": true } } }
"atomic": true开启原子发布:若任意子包发布失败,Lerna会自动尝试撤销已发布的所有包
3. 统一版本与发布
- 同步版本:执行
lerna version,交互式或自动更新所有子包的版本号 - 原子发布:执行
lerna publish,Lerna会按流程发布所有子包,中途失败则自动回滚
关键注意事项
- 版本一致性:必须确保两个子包版本相同,避免出现版本不一致的发布结果
- 预发布测试:发布前务必执行全量测试,从源头减少发布失败的可能
- npm撤销限制:若版本发布超过72小时或已被其他包依赖,无法撤销,因此原子发布的核心是"预防失败"而非事后回滚
内容的提问来源于stack exchange,提问作者Max Trunnikov
相关产品推荐
相关产品推荐

