Storybook 开源贡献实战:Monorepo 开发环境、沙盒调试与 CI 沙盒过滤
本文以 Storybook 仓库根目录的 CONTRIBUTING.md 为核心骨架,系统讲解贡献者如何从零搭建 Storybook 的本地开发环境:包括 Node.js 版本管理、monorepo 目录结构、yarn start 一键启动沙盒的原理、watch 模式增量构建指定包、Angular 代码的特殊构建要求,以及当 CI 中某个沙盒(sandbox)失败时如何聚焦调试。读完后,你可以独立完成一次针对 Storybook 源码的本地修改、验证与提交流程。
贡献方式与 AI 贡献规范
Storybook 欢迎任何形式的贡献,不限于代码。根据 CONTRIBUTING.md,贡献渠道包括:
- 为功能请求创建 RFC(仓库内对应文档见 docs/contribute/RFC.mdx);
- 更新文档,修正、改进或澄清现有说明(文档源码位于 docs/ 目录);
- 为 Storybook 与各 JS 框架的集成添加新的代码片段示例(文档片段源码位于 docs/_snippets/ 目录);
- 集成新的 JS 框架或改进现有框架支持(框架集成代码位于 code/frameworks/ 目录,见 docs/contribute/framework.mdx);
- 编写 addon 扩展 Storybook 的功能(addon 源码位于 code/addons/ 目录);
- 报告 Bug、在 GitHub Discussions 的 Help 分类回答他人问题、浏览并修复标注了
good first issue的问题——这是快速上手的前端与文档类小任务。
文档中特别强调了一条 AI 贡献规范(“Never let an LLM speak for you”):
- 团队允许把 AI 作为个人助理辅助贡献,但每个 issue 和 PR 背后必须有真实的人;
- 所有 issue 和 PR 必须由真人使用官方模板创建,若 AI 辅助生成了 PR,需披露所用工具(如 Claude、Codex、Copilot);
- 完全由 AI 自动生成、无人类参与(例如自动 agent 提交)的 PR/issue 会被维护者打标,3 天内无真人响应即自动关闭;
- 对 issue、PR 或 Discussions 中无价值或包含错误信息的 AI 生成评论,维护者会隐藏,构成垃圾行为可能导致封禁。
此外,文档要求开始贡献前先阅读 CODE_OF_CONDUCT.md,并对流程有疑问时联系维护者。
前置条件:Node.js 版本与版本管理器
Storybook 的代码库针对 .nvmrc 文件中指定的 Node.js 版本进行开发。当前仓库中 .nvmrc 的内容为 22.22.3,即需要 Node.js 22 系列。文档推荐使用 fnm 作为版本管理器,配置步骤如下:
- 检查当前 Node.js 版本,并按所用工具切换:
# Check which version you're using
node --version
# node version manager
nvm use 22
# pnpm
pnpm env use --global 22
- 安装 fnm 并调整 shell 配置,加入以下四个关键参数:
fnm env、use-on-cd、corepack-enabled和version-file-strategy recursive:
eval "$(fnm env --use-on-cd --corepack-enabled --version-file-strategy recursive)"
其中 use-on-cd 表示进入目录时自动切换 Node 版本,version-file-strategy recursive 使 fnm 能向上递归查找 .nvmrc——这一点在 monorepo 中进入 code/ 等子目录时尤其有用。corepack-enabled 则配合仓库通过 packageManager 字段锁定的包管理器版本:根目录 package.json 中声明了 "packageManager": "yarn@4.18.0",即本仓库使用 Yarn 4(Berry)管理 workspace。
- Windows 用户需要启用 Windows Subsystem for Linux(WSL),并在 Windows 环境下以管理员权限的终端运行所有命令。
仓库结构:monorepo 全景
Storybook 采用 Yarn workspaces + Nx 的 monorepo 结构管理项目与各个包。根目录 package.json 的 workspaces.packages 字段声明了所有参与 workspace 的目录:agent-eval、code、code/addons/*、code/builders/*、code/core、code/frameworks/*、code/lib/*、code/presets/*、code/renderers/* 和 scripts。
CONTRIBUTING.md 给出的目录概览(与当前仓库实际布局对照后,各目录职责如下):
.
├── CHANGELOG.md # 当前版本 Changelog
├── CHANGELOG.prerelease.md
├── CHANGELOG.v1-5.md
├── CHANGELOG.v6.md
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING # 面向维护者的信息(如发布流程)
├── CONTRIBUTING.md <--------- 你在这里!
├── LICENSE
├── MAINTAINERS.md
├── MIGRATION.md # 版本迁移指南
├── README.md
├── RESOLUTIONS.md
├── SECURITY.md
├── code # Storybook 代码库
│ ├── __mocks__
│ ├── addons # 内置 addon(a11y、docs、mcp、themes、vitest 等)
│ ├── builders # builder-vite、builder-webpack5
│ ├── core # Storybook UI 与 API 的核心包
│ ├── e2e-internal # 针对内部 Storybook UI 的 Playwright e2e 测试
│ ├── e2e-sandbox # 针对生成沙盒的 Playwright e2e 测试
│ ├── frameworks # 各框架-打包器组合(react-vite、vue3-vite、sveltekit…)
│ ├── lib # CLI(cli-sb、cli-storybook)与插件
│ ├── presets # 预设包(react-webpack、create-react-app、server-webpack)
│ ├── renderers # 各框架的 renderer(react、vue3、svelte、preact…)
│ ├── sandbox # 用于 Bug 复现或实验的沙盒模板清单
│ ├── playwright.config.ts
│ └── vitest.config.storybook.ts
├── codecov.yml
├── dependabot.yml
├── docs # 文档(mdx + 片段)
│ ├── _assets
│ ├── _snippets
│ ├── addons / api / builders / configure / contribute / essentials
│ ├── get-started / sharing / writing-docs / writing-stories / writing-tests
│ └── index.mdx
├── package.json # yarn monorepo 的根
├── nx.json # Nx 工作区配置
├── scripts # 构建与辅助脚本(task.ts、build-package.ts、ci/…)
├── test-storybooks # 独立测试工程(ember-cli、mcp、yarn-pnp 等)
└── yarn.lock
值得注意的几个实际细节:
- 版本信息:code/package.json 中当前版本为
10.6.0-beta.1,说明该快照处于 10.x 的 beta 周期; - 沙盒清单:code/sandbox/ 下每个目录(如
react-vite-default-ts、nextjs-15-ts、svelte-kit-skeleton-ts)只包含一个template.json,描述该沙盒使用的框架、builder 与模板参数; - CI 配置由 scripts/ci/ 下的 TypeScript 生成(当前使用 CircleCI 配置生成器),而不是手写的静态 YAML。
Fork 仓库与配置 upstream
计划修改 Storybook 代码库时,应先 fork 仓库到你的 GitHub 账号,以便在本地修改后向主仓库提交 PR。同时把官方仓库添加为 upstream,确保可以随时 rebase 到主仓库最新变更:
git remote add upstream https://github.com/storybookjs/storybook.git
git fetch upstream
git branch --set-upstream-to upstream/main main
启动本地开发环境:yarn start 到底做了什么
开始贡献时,应在仓库根目录运行 yarn start。它会自动安装依赖、构建项目(包括各包)、并生成一个基于 React + TypeScript 的沙盒环境,其中带有一组测试 stories 供你快速上手:
# Navigate to the root directory of the Storybook repository
cd path/to/your/storybook/fork
# Install the required dependencies
yarn
# start the development environment
yarn start
从源码看,根 package.json 中 start 脚本的真实定义是:
"start": "yarn task --task dev --template react-vite/default-ts --start-from=install"
即它并非独立的启动逻辑,而是委托给仓库统一的任务运行器 scripts/task.ts。该运行器的工作机制包括:
- 任务图与拓扑排序:所有任务(
install、compile、check、publish、generate、sandbox、dev、serve、test-runner、chromatic、e2e-tests等,见 scripts/task.ts 中的tasks对象)声明dependsOn依赖关系,运行器通过拓扑排序决定执行顺序; - 就绪检测与 startFrom:每个任务都有
ready()方法判断产物是否已就绪;--start-from可取auto(CI 下默认)、task(只跑目标任务)、never(要求全链路就绪)或某个具体任务名(如install、publish),从该任务起强制重跑,之前的产物被复用; - dev 是服务型任务:
dev任务会启动并常驻服务,运行器在最终任务为 service 时保持进程打开直到 Ctrl-C; - 交互式选择:直接运行
yarn task不带参数时,运行器会提示你选择模板(template)和任务(task),这正是后文“选择不同沙盒模板”功能的入口; - 模板来源:可选模板列表由 code/lib/cli-storybook/src/sandbox-templates.ts 导出,与 code/sandbox/ 目录下的
template.json清单一一对应。
修改代码:watch 模式构建指定包
在沙盒运行期间修改 Storybook 各包源码时,需要在第二个终端中进入 code/ 目录并运行 watch 模式构建:
# Navigate to the code directory
cd path/to/your/storybook/fork/code
# Build the specified packages in watch mode
yarn build --watch react core-server api addon-docs
构建命令由 scripts/build-package.ts 实现,其行为与文档描述完全对应:
- 包名规则:包名取发布包名去掉
@storybook/前缀后的部分(如@storybook/react→react,@storybook/builder-vite→builder-vite,@storybook/addon-docs→addon-docs);storybook包本身直接叫storybook。脚本会为每个 workspace 生成对应的短名(suffix),命令行参数命中哪个短名就构建哪个包; - 无效包名提示:传入不存在的包名时,脚本会基于最接近匹配提示 “Did you mean xxx?” 并以非零码退出;
- 无参数交互选择:不带包名时进入多选交互界面,可勾选 watch 模式与 production 模式;
- 构建执行:每个选中的包会以
NODE_ENV=production在各自目录下执行 scripts/build/build-package.ts 的构建入口,输出按包名着色区分。
构建完成后的验证方式分两种沙盒模式:
- linked 模式(默认):改动在刷新浏览器后即可看到;如果修改的是 server 侧包,可能需要重启沙盒;
- unlinked 模式:需要从
publish步骤重新跑沙盒才能看到改动:
yarn task --task dev --template <your template> --start-from=publish
无论哪种模式,只要改动了 /code 或其他包内的代码,都应进入对应包目录运行 yarn test,确认改动没有破坏测试(仓库使用 Vitest,根 package.json 的 test 脚本为 NODE_OPTIONS=--max_old_space_size=4096 vitest run)。
Angular 专用代码的构建要求
如果你在修改 Angular 相关代码,需要在上述命令后追加 --prod,以确保 Angular 编译器能正确拾取改动、不报错——即以生产模式构建所有包:
# Starts the build process in production mode
yarn task --prod
# Builds the specified packages in production mode
yarn build --prod --watch angular storybook addon-docs
--prod 参数在 scripts/build-package.ts 中通过 commander 的 --prod/--no-prod 选项解析,并透传给每个包的构建子进程。
针对不同沙盒模板进行调试
如果想换一个框架组合的沙盒来验证改动(例如 Vue3 + Vite 或 Next.js),直接运行 yarn task,运行器会交互式提示选择模板与任务:
yarn task --task dev --template vue3-vite/default-ts
可选模板即 code/sandbox/ 下的目录名(如 vue3-vite-default-ts、nextjs-15-ts、svelte-kit-skeleton-ts、react-webpack-18-ts 等),每个目录中的 template.json 描述了该沙盒的框架、builder 与参数。沙盒被生成到 code/sandbox/<模板名>/ 目录(运行器中 templateSandboxDir 的计算逻辑见 scripts/task.ts)。
聚焦调试 CI 中失败的沙盒
CI(尤其是 ci:daily workflow)会运行大量沙盒。当某个沙盒失败时,文档建议优先本地复现调试;若本地无法复现,可以强制 CI 只跑选定的沙盒子集。具体做法是在 CI 配置生成器中编辑过滤函数——当前仓库中对应位置为 scripts/ci/main.ts 中的 job 过滤逻辑:
/**
* If you want to filter down to a particular job, e.g.for debugging purposes.. you can do that
* here. You can filter on the `job.id` for example.
* ...
* @example
* ```ts
* const filteredTodos = todos.filter((job) => !!job.id.includes('qwik'));
* ```
*/
const filteredJobs = jobs.filter((job) => !!job.id.includes('qwik'));
源码注释明确说明:可以按任意 job.id 过滤,例如只运行 test-runner、e2e、vite 类沙盒;而且无需关心 requires 依赖字段,生成器内部的 ensureRequiredJobs 会自动补齐被过滤 job 所需的前置 job。过滤后若 job 数量减少,生成器会识别为“调试模式”。
故障排查
初始化过程抛错:如果运行 yarn start 时遇到如下错误,尝试第二次运行 yarn start:
> NX ENOENT: no such file or directory, open 'storybook/code/node_modules/nx/package.json'
这是 Nx 在首次安装阶段解析自身包路径的已知时序问题,重跑通常即可解决。
Storybook 检测不到代码库变化:如果贡献过程中仍然遇到改动不生效的问题,建议先检查本地工作区是否混入了意外的本地变更。可运行:
git clean -dx --dry-run
该命令以 dry-run 方式列出如果加上 --force 将被删除的未跟踪/被忽略文件与目录。在真正执行带 --force 的命令之前,务必先提交需要保留的本地改动,否则这些内容会丢失。清理后重新执行 yarn start,让依赖与构建产物回到干净状态。
进一步阅读
- docs/contribute/code.mdx 与 docs/contribute/index.mdx:仓库内维护的贡献者指南(代码贡献、RFC 流程);
- MAINTAINERS.md:维护者名单与职责;
- CONTRIBUTING/RELEASING.md:面向维护者的发布流程说明;
- MIGRATION.md:Storybook 大版本迁移指南,理解包间 API 变化时的参照;
- code/vitest.config.storybook.ts 与 code/playwright.config.ts:单元/组件测试与 e2e 测试的配置入口。
整体而言,CONTRIBUTING.md 提供的是一条完整可复现的贡献流水线:fork + upstream → yarn start(等价于 yarn task --task dev --template react-vite/default-ts --start-from=install)→ 在 code/ 下 yarn build --watch <包名> 增量构建 → 刷新沙盒验证 → 包内 yarn test 保障 → 必要时切换沙盒模板或用 scripts/ci/main.ts 的过滤逻辑聚焦 CI 问题。这条流水线以任务图驱动的沙盒机制为核心,是深入 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 StartedRust0622
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