Storybook Upgrade 命令实战:用 npx storybook@<version> upgrade 安全升级所有 Storybook 包
这篇指南聚焦 Storybook 仓库中 storybook upgrade 命令的完整使用方式与底层实现:如何把项目中的全部 @storybook/* 包一次性升级到 canary、stable 或指定 release 版本,为什么不能手动 npm add 各个包、为什么一次只能跨一个大版本,以及该命令在源码层面如何执行版本校验、依赖更新、自动迁移(automigrations)、依赖安装与健康检查(doctor)。读完后你能独立完成 Storybook 项目的版本升级流程,并能读懂升级过程中的每一步输出与失败原因。
命令用途与适用场景
Storybook 仓库内置了一个面向 AI Agent 的技能文档 storybook-upgrade,它定义了将项目中所有 Storybook 包升级到指定版本的标准操作。该技能的核心定位是在本仓库之外的下游项目上验证 Storybook 变更:
- 在一个下游应用中 QA 某个 Storybook PR 产出的 canary 构建;
- 在外部项目中复现或验证某个 bug。
对应的标准命令只有一行:
npx storybook@<VERSION> upgrade
三种典型用法(均继承自技能文档的 Examples 小节):
# 升级到 canary 版本(由 PR 构建产物)
npx storybook@0.0.0-pr-33526-sha-a2e09fa2 upgrade
# 升级到最新稳定版
npx storybook@latest upgrade
# 升级到某个具体 release
npx storybook@8.5.0 upgrade
这里的关键点是 npx 指定的版本号决定了升级目标:npx storybook@latest 会拉取最新的 CLI 包并在你的项目里执行其 upgrade 子命令,目标版本就是这个 CLI 包自身携带的 versions.storybook。因此升级 "8.5.0" 时执行的正是 8.5.0 版本的 CLI,而不是本地已经安装的旧版本 CLI。
命令的完整参数(来自 CLI 源码)
技能文档只展示了最基本的调用形式,但 CLI 源码中注册了更丰富的选项。以下参数全部定义在 run.ts 的 command('upgrade') 注册段中:
| 参数 | 说明 |
|---|---|
--package-manager <type> |
强制指定安装依赖使用的包管理器(npm / yarn / pnpm 等) |
-y, --yes |
跳过交互提示,全部采用默认答案 |
--features <list> |
逗号分隔的实验性 feature flag 列表,通过 automigrations 在升级过程中启用 |
-f, --force |
强制升级,跳过 autoblockers(自动拦截检查) |
-n, --dry-run |
只检查可升级内容,不真正安装 |
-s, --skip-check |
跳过 postinstall 版本与 automigration 检查 |
--skip-automigrations |
完全跳过 automigrations,仅更新包版本并安装 |
-c, --config-dir <dir-name...> |
指定一个或多个 Storybook 配置目录(支持 monorepo 多项目) |
此外,所有子命令共享一组全局选项(同样在 run.ts 中定义):--disable-telemetry(可用环境变量 STORYBOOK_DISABLE_TELEMETRY 控制)、--debug、--enable-crash-reports、--logfile [path]、--loglevel <trace \| debug \| info \| warn \| error \| silent>。
需要注意两个约束,均来自源码中的显式检查:
--features与--skip-automigrations不能组合使用,因为--features本身就是通过 automigrations 机制生效的,组合时 upgrade.ts 会直接抛出HandledError;- 若命令执行失败,日志会先写入文件(默认
debug-storybook.log,可由--logfile指定路径)再退出,方便排查自动化迁移失败的具体原因。
升级流程的源码级拆解
技能文档概括升级命令会做四件事:检测项目中所有 @storybook/* 包、把它们全部升到目标版本、自动处理 peer 依赖、兼容 npm/yarn/pnpm。upgrade.ts 中的 upgrade(options) 函数给出了完整实现,实际调用链比文档描述更细:
- 收集项目(getProjects):
getProjects会扫描出所有 Storybook 项目(monorepo 下可能有多个配置目录),并区分allProjects与用户实际选中的selectedProjects;多项目时会逐行打印每个项目的升级方向(beforeVersion -> currentCLIVersion)。 - 运行 autoblockers(自动拦截):
processAutoblockerResults检查是否存在阻断条件(如大版本跳跃、降级),发现阻断时打印 "Blockers detected" 并中止,除非使用--force。 - 版本合法性校验:如果目标版本低于当前已安装版本(
lt(project.currentCLIVersion, project.beforeVersion)),抛出UpgradeStorybookToLowerVersionError;如果读不到当前版本,抛出UpgradeStorybookUnknownCurrentVersionError。 - 更新 package.json:
upgradeStorybookDependencies遍历每个项目,把所有 Storybook 相关依赖写到目标版本(dry-run时跳过此步)。 - 执行 automigrations:调用
runAutomigrations运行配置与代码的自动迁移修复(可被--skip-automigrations跳过)。 - 安装依赖:对 npm 会带
force: true安装(源码注释指出这是为了规避 npm 的一个已知问题);yarn / pnpm 走常规安装。 - monorepo 去重:在非 Yarn 1 的 monorepo 场景中,命令会提示并可选执行
dedupe,避免同一 Storybook 包存在多个物理副本。 - 配置延迟安装的 addons:某些 automigration 会引入新 addon 但把 postinstall 配置推迟到依赖安装完成之后(
configureDeferredAddons),保证 "先装后配" 的顺序。 - 运行 doctor 健康检查:
runMultiProjectDoctor+displayDoctorResults对每个项目输出诊断,最终由logUpgradeResults汇总为三类结果:成功升级、升级失败(automigration 失败或 check 失败)、无需迁移。
从源码结构看,升级的最终判定是:存在成功修复且无失败项才算成功;若所有项目 doctor 结果均为 healthy,会输出 "Your project(s) have been upgraded successfully! 🎉",否则提示存在需要人工关注的问题。
为什么必须一次只升一个大版本
技能文档中最强调的一条规则是:
ALWAYS upgrade only 1 major version at a time! 例如 8.x → 9.x → 10.x → 10 的 canary;绝不允许从 8.x 直接跳到 10.x。
这条规则不是口头建议,而是由 autoblocker 机制在源码中强制执行的。block-major-version.ts 中定义了 major-version-gap 拦截器:
validateVersionTransition(currentVersion, targetVersion)比较当前版本与目标版本:若当前版本更高,判定为downgrade(不支持降级);若目标 major 与当前 major 之差大于 1,判定为gap-too-large(跳跃过大);major 为 0 的版本(如0.0.0-pr-*这类 canary)不参与拦截。- 命中拦截后,CLI 会打印明确指引,例如大版本跳跃时会直接给出下一步该执行的命令:
npx storybook@<nextMajor> upgrade
也就是说,如果你从 8.x 直接执行 npx storybook@10 upgrade,命令会被阻断,并提示你先用 9 的 major 版本过渡一次。这就是 "8.x → 9.x → 10.x" 链式升级在工具层的落地方式,其目的正是让每一级 major 的破坏性变更和 automigrations 都能被独立应用与验证。
为什么不能手动 npm add Storybook 包
技能文档给出了另一条硬性禁令:
DO NOT manually install storybook packages with
npm add/yarn add/pnpm add。Always usenpx storybook@<version> upgradeto ensure all packages stay in sync.
原因在源码中可以得到印证:Storybook 由大量同版本的包组成(core、renderer、framework、addons 等),upgrade 命令通过 upgradeStorybookDependencies 统一解析并更新所有相关依赖,保证它们指向同一版本线;而手动逐个 add 很容易造成版本错位。仓库甚至内置了版本一致性检查逻辑:checkVersionConsistency(位于 upgrade.ts)通过 npm ls 输出解析所有 @storybook/* 包版本,发现同一项目里存在多个版本时会打印 "Found N outdated packages" 的告警,提示你确认包已对齐;upgrade.test.ts 中的 getStorybookVersion 用例覆盖了带 ├─┬ 前缀、dedupe 行、peer dep 报错行等各种 npm ls 输出格式的解析。
从 upgrade.test.ts 的 generateUpgradeSpecs 用例还可以看到一个细节:升级时依赖声明中的版本修饰符会被尽量保留(~8.0.0 → ~9.0.0、^8.0.0 → ^9.0.0、>=8.0.0 → >=9.0.0),而 *、workspace:* 这类无法保留修饰符的写法会被归一为精确版本。这解释了为什么用统一命令升级比手工编辑 package.json 更安全——它同时处理了 peer 依赖与版本区间语义。
验证升级结果:doctor 与 automigration 摘要
升级结束时,命令会做两件事帮你确认状态:
- automigration 摘要:
logUpgradeResults按项目输出 "Successfully upgraded / Failed to upgrade / No applicable migrations" 三类清单,并附上每个已执行 automigration 的说明链接,方便对照迁移指南理解每项变更; - doctor 诊断:
runMultiProjectDoctor检查已知问题并给出修复建议;doctor 发现 issues 时会自动启用日志落盘(logTracker.enableLogWriting()),把详细调试信息写入日志文件。
如果升级后仍有异常,推荐的操作顺序是:查看命令输出的日志文件路径 → 定位失败的 automigration 或 doctor 项 → 按提示单独重跑对应修复(storybook automigrate [fixId] 命令同样在 run.ts 中注册,支持 --list 查看全部可用迁移、--dry-run 只做检查)。
适用前提与限制
- 该命令面向外部应用、复现工程或测试项目使用(技能文档明确说它是 "mainly for validating Storybook changes outside this repository"),Storybook 仓库自身作为 monorepo 的内部版本管理走的是另一套发布流程,不应在仓库内直接跑此命令;
- 目标版本由 npx 中指定的
storybookCLI 版本决定,因此升级 canary 时使用的是 PR 构建产物的 tag(形如0.0.0-pr-XXXXX-sha-XXXXXXX); - 降级不被支持(源码层面直接报错),跨大版本跳跃会被 autoblocker 拦截,
--force可以跳过 autoblockers 但意味着你自行承担多级变更叠加的风险; --dry-run只读不写,适合升级前先确认影响范围;--skip-install/--skip-check等选项面向自动化流水线场景,手动升级时建议保留默认检查以获得完整诊断。
参考路径
- 技能文档(本文骨架来源):.agents/skills/storybook-upgrade/SKILL.md
- 升级命令实现:code/lib/cli-storybook/src/upgrade.ts
- 命令注册与参数定义:code/lib/cli-storybook/src/bin/run.ts
- 大版本拦截器:code/lib/cli-storybook/src/autoblock/block-major-version.ts
- 单元测试:code/lib/cli-storybook/src/upgrade.test.ts
- 升级相关的 Agent 评测用例:agent-eval/evals/821-upgrade-from-sb9、agent-eval/evals/822-upgrade-from-stable、agent-eval/evals/823-setup-outdated-storybook
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00