Storybook CLI 实战指南:从 `npx storybook init` 到 add / upgrade / migrate 命令的源码级解析
本文以 @storybook/cli 包(仓库路径 code/lib/cli-storybook)的 README 为主体,完整讲解 Storybook CLI 的安装、addon 管理、版本升级与 codemod 迁移能力,并结合 src/bin/run.ts、src/add.ts、src/upgrade.ts 等源码,帮助你在项目中熟练使用 init、add、upgrade、migrate 等命令,同时理解 storybook/components、storybook/theming 等核心 API 子导出的实际归属。
一、用 CLI 把 Storybook 引入项目
Storybook CLI(Command Line Interface)是把 Storybook 添加到你的项目中最简单的方式。按照 README 的标准流程:
cd my-app
npx storybook@latest init
init 命令会在你的项目中完成框架检测、依赖安装和 .storybook/ 配置目录的初始化。从 src/bin/run.ts 中 command('init') 的注册代码可以看到,它实际支持一组丰富的选项:
| 选项 | 说明 |
|---|---|
-f, --force |
强制添加 Storybook |
-s, --skip-install |
跳过依赖安装 |
--package-manager <type> |
强制指定安装依赖所用的包管理器 |
--use-pnp |
为 Yarn 2+ 启用 PnP 模式(源码中标注计划在 SB11 移除) |
-p, --parser <babel | babylon | flow | ts | tsx> |
指定 jscodeshift 使用的解析器 |
-t, --type <type> |
为特定项目类型添加 Storybook |
-y, --yes |
对所有交互提示自动回答 yes |
-b, --builder <webpack5 | vite> |
指定构建器 |
-l, --linkable |
准备可 link 的安装(贡献者辅助选项) |
--dev / --no-dev |
初始化完成后是否启动开发服务器(默认不启动) |
入口与 Node 版本门禁
CLI 的构建入口由 build-config.ts 声明,打包 src/bin/index.ts 为 Node 产物;发布产物中 bin 字段指向 ./dist/bin/index.js(见 package.json)。而 src/bin/index.ts 在真正执行前有一道版本门禁:
if (!isNodeVersionSupported(major, minor, patch)) {
logger.error(dedent`To run Storybook, you need Node.js version ${MIN_SUPPORTED_NODE_DESCRIPTION}.
You are currently running Node.js ${process.version}. Please upgrade your Node.js installation.`);
process.exit(1);
}
即如果当前 Node 版本低于 storybook/internal/common 导出的最低支持版本,命令会直接报错退出——遇到此类提示时升级 Node 即可。
全局选项
run.ts 中的 command() 工厂为每个子命令统一挂载了以下全局选项,任何子命令(add、upgrade、doctor 等)均可使用:
--disable-telemetry:关闭遥测数据上报(读取STORYBOOK_DISABLE_TELEMETRY环境变量);--debug:输出 debug 级别日志;--enable-crash-reports:允许将崩溃报告发送到遥测数据中;--logfile [path]:运行结束后把调试日志写入文件(默认debug-storybook.log);--loglevel <trace | debug | info | warn | error | silent>:定义日志级别,默认info。
另外值得一提的是容错细节:当用户输入不存在的命令时,CLI 会用 leven 库计算与已有命令的编辑距离(小于 3 视为匹配),给出 “Did you mean xxx?” 的拼写建议,这一点在 run.ts 末尾的 program.on('command:*') 钩子中实现。README 中提示的 -h / --help 同样适用于列出所有命令。
二、命令全景:README 之外还有哪些命令
README 列出的核心命令是 init、add、info、upgrade、migrate。对照 run.ts 的源码,当前 CLI 实际注册的完整命令集还包括:
remove <addon>:从 Storybook 中移除 addon(README 未提及,但源码中已实现);automigrate [fixId]:检查不兼容项或迁移并应用修复,是upgrade内部自动迁移能力的独立入口;doctor:检查已知问题并给出建议或修复(实现见 src/doctor/index.ts);sandbox [filterValue](别名repro):从模板集合创建沙盒项目,可选--no-init创建未初始化 Storybook 的模板(实现见 src/sandbox.ts);link <repo-url-or-directory>:从 URL 或本地目录拉取复现工程并 link、运行 Storybook,支持--local、--no-start。
三、add:安装 addon 并自动注册到 main 配置
npx storybook@latest add <addon> 会完成两件事:安装 addon 包,并把它注册进 main.ts 的 addons 数组。源码 src/add.ts 中的关键逻辑:
export const getVersionSpecifier = (addon: string) => {
const groups = /^(@{0,1}[^@]+)(?:@(.+))?$/.exec(addon);
if (groups) {
return [groups[1], groups[2]] as const;
}
return [addon, undefined] as const;
};
也就是说 @storybook/addon-vitest@9.0.1 会被拆分为包名和版本;若省略版本说明符且目标是 Storybook 官方 addon,则会自动使用与你当前 Storybook 安装版本一致的版本说明符(源码注释中明确:If there is no version specifier and it's a Storybook addon, it will try to use the version specifier matching your current Storybook install version)。
实现层面还有两个判断函数:
checkInstalled:遍历main配置中已有的addons条目(兼容字符串与{ name }对象两种写法),检查是否已注册,避免重复添加;isCoreAddon:通过Object.hasOwn(versions, addonName)判断该 addon 是否属于 Storybook 官方发布物集合。
add 支持的主要选项(来自 run.ts):
storybook add <addon>
--package-manager <type> # 强制指定包管理器
-c, --config-dir <dir> # Storybook 配置目录
--skip-install # 跳过依赖安装
-s --skip-postinstall # 跳过包相关的 postinstall 配置修改
-y --yes # 跳过用户交互提示
--skip-doctor # 跳过 doctor 检查
安装完成后,postinstallAddon(src/postinstallAddon.ts)会处理包特有的 postinstall 配置修改。整个 add 动作被 withTelemetry('add', ...) 包裹,即默认会记录一次遥测事件,可用全局 --disable-telemetry 关闭。
四、upgrade:升级 Storybook 到目标版本
npx storybook@latest upgrade 用于把项目中的 Storybook 相关包升级到指定版本(不带参数时默认升级到当前 CLI 携带的版本,即 package.json 中的 version,当前仓库快照为 10.6.0-beta.1)。
run.ts 中注册的选项包括:
| 选项 | 说明 |
|---|---|
--features <list> |
升级期间要启用的实验特性开关(逗号分隔),参数解析时会先经 resolveRequestedFeatures 校验合法性 |
-f, --force |
强制执行升级,跳过 autoblocker 检查 |
-n, --dry-run |
只检查是否可升级,不实际安装 |
-s, --skip-check |
跳过 postinstall 的版本检查与自动迁移检查 |
--skip-automigrations |
完全跳过自动迁移,只更新包版本并安装 |
-c, --config-dir <dir...> |
支持传入多个配置目录(monorepo 场景) |
从 src/upgrade.ts 的实现可以看到几个值得了解的机制:
- 版本解析:
getStorybookVersion用正则/(@storybook\/[^@]+)@(\S+)/从包管理器输出中解析每个@storybook/*包及其版本; - 废弃包提示:
deprecatedPackages列表维护了旧版本中的废弃包(如@storybook/addon-notes、@storybook/addon-info等),升级时会提示并附 MIGRATION 文档锚点链接; - autoblocker 机制:src/autoblock/ 目录下实现了 Node 版本、大版本、实验 addon(如
@storybook/addon-test)等阻断检查,processAutoblockerResults会汇总这些结果;--force即用于跳过这些检查; - 多项目支持:
upgrade通过 src/util.ts 的getProjects收集多个 Storybook 项目(monorepo),再调用runAutomigrations(src/automigrate/multi-project.ts)执行自动迁移。
自动迁移本身由 src/automigrate/fixes/ 下的一批 codemod 组成,覆盖诸如 addon 更名(@storybook/addon-a11y / addon-test 合并、@storybook/addon-mcp)、framework 包更名(@storybook/react → @storybook/react-vite 一类迁移)、main.ts 中 features/docs 配置项清理等,每个 fix 都配有对应的 .test.ts 用例,这也是 automigrate 命令可独立运行的基础。
五、migrate:手动运行 codemod 迁移
migrate 命令用于对源码文件运行特定的 codemod 迁移(如 CSF 2 → CSF 3 工厂写法迁移)。其实现非常薄——src/migrate.ts 完全委托给 @storybook/codemod 包:
import { listCodemods, runCodemod } from '@storybook/codemod';
export async function migrate(migration: any, { glob, dryRun, list, rename, parser }: CLIOptions) {
if (list) {
listCodemods().forEach((key: any) => logger.log(key));
} else if (migration) {
await runCodemod(migration, { glob, dryRun, logger, rename, parser });
} else {
throw new Error('Migrate: please specify a migration name or --list');
}
}
即:不带迁移名会报错;-l, --list 列出所有可用迁移;否则调用底层 jscodeshift 执行器(@storybook/codemod 基于 jscodeshift,见 package.json 的依赖声明)。
常用选项:
storybook migrate <migration>
-l --list # 列出可用迁移
-g --glob <glob> # 应用迁移的文件匹配模式,默认 **/*.js
-p --parser <babel|babylon|flow|ts|tsx> # jscodeshift 解析器
-c, --config-dir <dir> # Storybook 配置目录
-n --dry-run # 仅校验迁移存在并展示将处理的文件
-r --rename <from-to> # codemod 应用后重命名文件后缀,如 ".js:.ts"
六、info:为 bug 报告收集环境信息
README 提到 info 命令用于打印系统信息以便提交 bug 报告。从 run.ts 中 command('info') 的实现看,它基于 envinfo 收集:系统(OS / CPU / Shell)、二进制(Node / Yarn / npm / pnpm)、浏览器(Chrome / Edge / Firefox / Safari),以及项目内和全局安装的 {@storybook/*, *storybook*, sb, chromatic} 相关包,并高亮标记当前生效的包管理器。把这份输出贴进 issue,是 Storybook 维护者排查版本/环境问题的重要依据。
七、Core APIs:README 提到的 storybook/* 子导出
README 的 “Core APIs” 部分说明了一批可供 addon 作者使用的子导出。它们的实际归属在 storybook 核心包(code/core/package.json)的 exports 字段中:
storybook/components
面向 addon 作者的一组 UI 组件,用于保证 addon 与 Storybook 界面一致的观感、减少样板代码。从当前仓库源码结构看,组件实现在 code/core/src/components 目录,package.json 中对应导出路径为 ./internal/components,即内部子路径下提供,供 addon 生态引用。
storybook/theming
暴露主题相关工具函数,帮助组件自动适配当前主题(深浅色切换等)。实现位于 code/core/src/theming,在 code/core/package.json 的 exports 中注册为公开的 ./theming(另有 ./theming/create 子路径)。
storybook/preview-api
包含 preview iframe 内可用的 API(如 addons、parameters、types 等运行时能力),实现位于 code/core/src/preview-api,exports 中注册为 ./preview-api。
storybook/manager-api
包含 manager iframe 内可用的 API(面板注册、store 等),实现位于 code/core/src/manager-api,exports 中注册为 ./manager-api。
storybook/types
暴露 Storybook 各处使用的 TypeScript 接口,包括 StorybookConfig 等配置类型与 addon 相关类型,实现位于 code/core/src/types。从当前快照的 exports 结构看,它通过 ./internal/types 提供(README 文档中以 storybook/types 的语义对外描述)。
这组子导出构成了 addon 开发的基础面:用 components 写 UI、用 theming 适配主题、在 preview-api / manager-api 中访问各自 iframe 的运行时能力、用 types 保证类型安全。
八、小结:CLI 与仓库内相关文件的对应关系
| 能力 | 实现位置 |
|---|---|
| 命令注册与全局选项 | code/lib/cli-storybook/src/bin/run.ts |
| Node 版本检查入口 | code/lib/cli-storybook/src/bin/index.ts |
add 命令实现 |
code/lib/cli-storybook/src/add.ts |
upgrade 命令实现 |
code/lib/cli-storybook/src/upgrade.ts |
| 自动迁移 codemod 集合 | code/lib/cli-storybook/src/automigrate/ |
migrate 命令实现 |
code/lib/cli-storybook/src/migrate.ts |
doctor 检查 |
code/lib/cli-storybook/src/doctor/index.ts |
| 包定义与依赖 | code/lib/cli-storybook/package.json |
| 核心子导出(theming/preview-api/manager-api 等) | code/core/package.json |
日常使用时记住三条主线即可:初始化用 npx storybook@latest init(配合 --package-manager、--skip-install 等选项),日常增删 addon 用 add / remove,跨大版本演进用 upgrade(内部自动串联 autoblock 检查与 automigrate),而需要手动执行特定 codemod 时再用 migrate(可用 -l 查看可用迁移清单)。
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 StartedRust0627
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