首页
/ Next.js 发布通道解析:stable 与 canary 双通道机制、dist-tag 策略与发布脚本源码剖析

Next.js 发布通道解析:stable 与 canary 双通道机制、dist-tag 策略与发布脚本源码剖析

2026-09-04 23:57:56作者:卓艾滢Kingsley

Next.js 通过 stablecanary 两条发布通道向 npm 分发版本:stable 是绝大多数用户 npm install next 得到的正式版本,canary 则是基于 canary 分支自动递增、用于在真实应用中提前验证新特性与修复的预发布版本。本文以官方发布流程文档为骨架,结合 scripts/ 下的发布脚本与 lerna.json 配置,完整讲清两条通道的语义差异、版本号生成规则、npm dist-tag 映射逻辑,以及一次完整发布背后 native 二进制、wasm 包与 GitHub Release 的联动细节。

两条发布通道:stable 与 canary

Next.js 官方维护两个发布通道:

  • stable(稳定通道):用户执行 npm install next 时安装的版本,是绝大多数 Next.js 用户使用的版本。该通道按固定节奏发布,并遵循语义化版本(semantic versioning)规范。
  • canary(金丝雀通道):需要用户显式安装——npm install next@canary。该通道基于 canary 分支提前发布,承载所有等待进入 stable 通道的变更,用于在真实世界应用中测试最新特性与 bugfix。用户定期升级到 next@canary 可以提前检查尚未发布的变更是否影响自己的应用。

两条通道的核心区别在于版本号的确定方式面向的用户群体

维度 stable canary
安装方式 npm install next(默认 latest npm install next@canary
版本号来源 语义化版本,发布时由维护者选择 bump 级别 自动从上一版本递增
代码来源 稳定的发布基线 canary 分支
定位 生产可用、固定节奏发布 真实环境预演最新变更

仓库中的版本载体:lerna.json

两条通道的版本号都保存在仓库根目录的 lerna.json 中。该文件同时揭示了发布流程的几个关键约束:

{
  "npmClient": "pnpm",
  "packages": ["packages/*"],
  "command": {
    "version": { "exact": true },
    "publish": {
      "npmClient": "npm",
      "allowBranch": ["canary"],
      "registry": "https://registry.npmjs.org/"
    }
  },
  "version": "16.4.0-canary.14"
}
  • "version": "16.4.0-canary.14":当前 canary 分支的版本。可以推断,每次 canary 发布都会在 16.4.0-canary.x 的 prerelease 序号上递增,这正是文档中“canary 版本号自动决定”的落点;
  • "version": { "exact": true }:所有包使用精确版本号(不带 ^/~),保证多包仓库内依赖版本严格锁定;
  • "publish": { "allowBranch": ["canary"] }:Lerna 默认只允许在 canary 分支执行发布,这是通道与分支绑定的直接证据;
  • 发布目标固定为 npm 官方 registry。

stable 通道的发布流程

文档指出,仓库维护者通过 pnpm publish-stable 发布新的 stable 版本,命令会询问要发布 majorminor 还是 patch

版本 bump 的执行:lerna version

从源码结构看,这套流程当前由 scripts/start-release.js 驱动。该脚本接受 --release-typestablecanaryrelease-candidatebetapreview)与 --semver-typepatchminormajor)两组参数,其中:

  • stable 通道必须显式指定 --semver-type,对应文档中“命令询问 major/minor/patch”的交互——脚本在第 131 行校验:canarypreview 自动推导版本,不需要 semver type,其余通道必须传入合法的 patch/minor/major 之一;
  • 参数映射到 Lerna 子命令(scripts/start-release.js):
    • stable 直接传 patch/minor/major
    • canary/rc/beta 映射为 prerelease/premajor/preminor 并附加 --preid canary|rc|beta
    • 统一追加 --force-publish -y --no-push:强制发布(即使无变更提交)、跳过确认、版本提交后不立即推送,改由脚本统一创建签名的发布提交。

随后脚本调用 createGitHubReleaseCommit 通过 GitHub API 创建提交与 v<version> 标签(scripts/release-github-api.js)。脚本还支持 --dry-run:此时所有 GitHub API 调用走一个 mock client(仅打印 method/path/body),完整演练签名、打标签、推送、创建 Release 的流程而不产生任何远端副作用(scripts/start-release.js)。

stable 发布到 npm 的 dist-tag:latest 与 backport

发布到 npm 时,dist-tag 的决定逻辑集中在 scripts/publish-release.js。核心规则(第 32-36 行):

const prereleaseChannel = parsedVersion.prerelease[0] // 如 'canary'、'rc'、'beta'
const isPrerelease = prereleaseChannel != null
let npmDistTag = isPrerelease ? String(prereleaseChannel) : 'latest'

即:带 prerelease 后缀的版本打对应标签(canaryrcbeta…),纯版本号则打 latest——这解释了为什么 npm install next 能始终拿到 stable。

一个容易被忽略的细节是 backport(回移)保护scripts/publish-release.js):如果当前待发布版本低于 npm 上已有的 latest 版本(典型的旧版本线安全回移场景),由于 npm 发布时默认会把 latest 指向新包、可能让用户装到比线上更旧的版本,脚本会显式把 dist-tag 改为 backport 而非 latest。仓库中还有配套的 scripts/check-backport-canary-release.jsscripts/normalize-version-bump.js 处理回移发布时版本号与 canary 线的一致性,说明回移是被正式支持、且有专门校验的发布场景。

canary 通道的发布流程

文档说明维护者通过 pnpm publish-canary 发布 canary,版本号自动从上一版本递增。结合源码可以完整还原这一“自动决定”的机制:

  1. lerna version prerelease --preid canarylerna.json 当前版本(如 16.4.0-canary.14)基础上递增 prerelease 序号(如 16.4.0-canary.15);
  2. --force-publish 保证即使当次只有一个改动也能产出新版本;
  3. scripts/publish-release.js 读取新版本,prerelease[0]canary,故 dist-tag 直接取 canary,用户侧 npm install next@canary 即可安装;
  4. canary 等预发布通道在 GitHub 上创建的是 draft releasescripts/start-release.js 中对 canary/rc/beta/preview 调用 createGitHubRelease),待 npm 发布完成后,scripts/publish-release.js 轮询 GitHub releases 列表找到 v<version> 标签,PATCH {"draft": false} 将其转为正式发布。

canary 与 stable 的衔接点在于:canary 分支累积所有待发变更(lerna.jsonallowBranch: ["canary"] 限定发布只从该分支发起),待其被认为足够稳定后,再走 stable 通道按 semver 规则正式放出。仓库中 scripts/check-is-release.js 用于识别一个提交是否为“发布提交”,scripts/create-release-branch.jsscripts/normalize-version-bump.js 则负责发布分支的创建与版本号规范化——.github/workflows/create_release_branch.yml.github/workflows/trigger_release.yml 等 CI 工作流把这些脚本串成了自动化的发布流水线。

一次完整发布到底发布了什么

阅读 scripts/publish-release.js 可以看清 Next.js 发布不止是发一个 next 包,而是一组联动的 npm 包,全部使用同一个 dist-tag:

  1. 平台原生二进制:遍历 crates/next-napi-bindings/npm 下的各平台目录(linux-x64、darwin-arm64 等),把 packages/next-swc/native/ 下编译好的 next-swc.<platform>.node 复制进去,同步版本号后逐个发布为 @next/swc-<platform> 包;
  2. wasm 包:把 crates/wasm 下的 pkg-web/pkg-nodejs 改名发布为 @next/swc-wasm-web@next/swc-wasm-nodejs;wasm 发布失败默认不中止整个发布(可设 BAIL_ON_NATIVE_WASM_PUBLISH_FAILURE=true 强制中止),而原生包任一失败则 process.exit(1)
  3. 主包 next:把各平台 @next/swc-<platform> 写进 packages/next/package.jsonoptionalDependencies,并删除 devDependenciestaskrscripts 字段以压缩 npm 上该包的历史元数据体积(源码注释提到上限 100MB、当前约 30MB),随后 pnpm --filter './packages/**' publish --recursive --access public --no-git-checks --ignore-scripts --tag <dist-tag> 一次性发布整个 packages/* 工作区(对应 lerna.json"packages": ["packages/*"]);
  4. 可靠性保障:每次 npm publish 通过信号量并发限制为 2,失败后按 15 秒间隔重试,最多 4 次;若错误信息包含 “cannot publish over the previously published versions”(同版本号重复发布)则直接忽略,使发布流程具备幂等性(scripts/publish-release.js)。

延伸:rc、beta 与 preview 通道

scripts/start-release.js 支持的 --release-type 取值可以看出,实际发布矩阵比文档列举的两条通道更宽:

这些通道共享同一套 dist-tag 规则:版本号的 prerelease 段第一个 token 就是 npm 标签名。

总结:通道、分支与标签的对应关系

发布动作 分支/基线 版本号形态 npm dist-tag GitHub Release
stable 发布基线 16.x.y(semver bump) latest(回移时为 backport 正式
canary canary 分支 16.x.y-canary.n(自动 +1) canary draft → 转正
rc / beta 发布流程 16.x.y-rc.n / 16.x.y-beta.n rc / beta draft → 转正
preview 从 canary 临时切出 16.x.y-preview.n(推导后 revert canary 线) preview draft → 转正

对使用者而言,记忆点很简单:npm install next 走 stable,npm install next@canary(或 next@rcnext@beta)做提前验证;对维护者而言,发布是一个“Lerna 定版 → GitHub 签名打标签 → npm 多包联动发布 → draft release 转正”的确定性流水线,全部逻辑沉淀在 scripts/start-release.jsscripts/publish-release.jslerna.json 中,可按需阅读源码深入。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384