在上个月,我在 npm 文档里挖到一个被埋得很深的细节——那种多数人根本不会翻到的角落。这个细节直接改变了我对 预发布(prerelease)工作流 的理解。
我之所以把它写出来,是因为我曾反复踩进同一个坑:想发布实验代码给测试者,却一不小心把不稳定版本喂给了所有用户。 只要某一次发布没处理好,下一秒就可能出现灾难——用户群体安装了他们根本不需要的 alpha 版本,而你只能在工位上当场出汗。
版本号背后的“沉默劳模”:npm version
npm 有个命令叫 npm version,你可能用过,但未必认真看过它的“全能程度”。这个命令会帮你一条龙处理版本变更:
- 更新
package.json
- 更新
package-lock.json
- 甚至能自动创建 git commit 和 tag
而且它严格遵循 语义化版本(Semantic Versioning,SemVer) 的 MAJOR.MINOR.PATCH 规则。
假设你当前版本是 23.1.6。
npm version major 会把版本变成 24.0.0
npm version minor 会把版本变成 23.2.0
npm version patch 会把版本变成 23.1.7
到这里,一切都很“教科书”。但真正的核心技巧,藏在下一层:预发布版本号。
那个“没人提醒你,直到你需要它”的隐藏功能:预发布标识
SemVer 允许你在版本后面加一个连字符 -,接上预发布标签,比如:
24.0.0-alpha.0
24.0.0-alpha.1
24.0.0-alpha.2
- ...
要开启这种模式,你需要使用三个命令:premajor / preminor / prepatch。再配合 --preid 参数(注意格式是 --preid=),你就能把这个实验阶段命名得很清楚,比如 alpha、beta、rc 都可以。
假设你现在是 23.1.6:
npm version premajor --preid=alpha
# 23.1.6 -> 24.0.0-alpha.0
npm version preminor --preid=alpha
# 23.1.6 -> 23.2.0-alpha.0
npm version prepatch --preid=alpha
# 23.1.6 -> 23.1.7-alpha.0
从这一刻开始,你就进入了“试验迭代”的节奏。接下来你不需要再动 major/minor/patch,只需不断推进 alpha 的计数:
npm version prerelease
# 24.0.0-alpha.0 -> 24.0.0-alpha.1
npm version prerelease
# 24.0.0-alpha.1 -> 24.0.0-alpha.2
npm version prerelease
# 24.0.0-alpha.2 -> 24.0.0-alpha.3
等你觉得“可以上桌了”,再用标准命令把它“洗干净”,变成正式版本:
npm version major
# 24.0.0-alpha.3 -> 24.0.0
npm version minor
# 23.2.0-alpha.5 -> 23.2.0
npm version patch
# 23.1.7-alpha.2 -> 23.1.7
版本号这部分,看懂规律之后其实不难。真正的陷阱在于:你刚把版本号打出来,下一步 publish 的时候,会发生一件“静悄悄但致命”的事。
发版为什么会翻车:npm publish 的“默认行为”太阴险
npm 有 dist-tag(分发标签),概念上有点像 git tag——它告诉 npm:“哪个版本是默认给所有人安装的”。
关键点来了:你如果直接 npm publish,不写 tag,npm 会默认把你刚发布的版本标成 latest。 哪怕你发布的是 alpha.0。
你想一下就知道会发生什么:
- 用户执行
npm install your-package
- npm 会去找
latest 标签
- 然后把你的
alpha 版本送到他电脑里
- 你甚至来不及阻止
很多开发者都是“事后才知道”,那一刻的感觉通常是:我不是在发版本,我是在发事故。
解决办法却简单得惊人:发布预发布版本时,加上 --tag next。
npm publish --tag next
这会把你的 24.0.0-alpha.0 挂在 next 这个标签下,而不是 latest。于是:
latest 仍然指向你上一次的稳定版本(默认安装不受影响)
next 只给“明确想当小白鼠的人”
测试者想跟进最新 alpha,只需要这样安装:
npm install example-package@next
他们会自动拿到你最新的 prerelease 版本,而你不必每次都发“请装 24.0.0-alpha.3”这种版本号短信。
等你最终发布 24.0.0:
npm publish
这时 npm 才会把它正常标成 latest,推给所有默认安装的用户。
最后一步:多数人会忘,但你不该忘——清理 dist-tag
当正式版本已经稳稳占住 latest,那个临时的 next 标签就该退场了。否则你的 tag 列表会越来越像“没收拾的桌面”。
清理命令是:
npm dist-tag rm example-package next
一个干净的 tag 列表,会让人感觉你做事是闭环的。一个乱糟糟的 tag 列表,会让人怀疑你是不是把发布当成抽卡。
六步走:把“实验”关进笼子里,再放它出来
我把整个安全可控的预发布流程压缩成最关键的六步,照着做基本不会翻车:
-
用预发布启动下一阶段(例:大版本 alpha)
npm version premajor --preid=alpha
-
迭代推进 alpha 计数(每修复一次或完成一个里程碑就发一次)
npm version prerelease
-
发布预发布版本,但一定挂 next 标签,别污染 latest
npm publish --tag next
-
实验结束,转为正式版本号
npm version major
-
正式发布,让它成为默认 latest
npm publish
-
清掉临时标签,保持发布历史清爽可读
npm dist-tag rm example-package next
最后的话:这套流程不“酷”,但它让人信任你
这不是什么玄学,也不是高深技巧。它只是把 npm 的原生能力拼成一套可控的预发布工作流:
- 你可以大胆试验
- 你不会误伤默认用户
- 测试者也能稳定拿到“最新实验版”
这就是“技术细节”真正该发挥的作用:让你的发布看起来不危险、不偷偷摸摸,而是可预期、可选择、可追踪。
你们团队现在的 prerelease 或发版流程是怎样的?有没有踩过 latest 被污染的坑?欢迎在 云栈社区 等技术论坛交流讨论。下次再见,我再分享一个冷门但很香的 npm 实用技巧。