Storybook Code Panel 使用指南:用 parameters.docs.codePanel 在 Canvas 中展示 Story 实时源码
Code Panel(代码面板)是 Storybook Docs 提供的一个面板型功能,在 Canvas(画布)浏览模式选中某个 Story 时,即时渲染该 Story 的源码片段,替代已停用的 Storysource 插件。本文以 docs/_snippets/code-panel-enable-in-preview.md 为骨架,结合 addon-docs 源码,讲清它的启用方式、作用范围(全局 / 组件 / Story 三级)以及与 Source 参数体系的联动关系,帮助你在 React、Vue、Angular、Web Components 等任意受支持框架下快速把"看代码"融入日常组件开发工作流。
Code Panel 是什么:从 Storysource 到内置 Docs 面板
在 Storybook 9 之前,要在预览界面查看当前 Story 的源码,通常依赖独立的 @storybook/addon-storysource 插件及其配套的 source-loader 来注入并展示源码。该方案需要额外安装插件与 loader,且在架构升级后逐渐被维护方弃用。根据仓库根目录 MIGRATION.md 的记录,Storybook 9 中 @storybook/addon-storysource 与 @storybook/source-loader 已被移除,替代方案正是由 @storybook/addon-docs 内置提供的 Code Panel——它在功能上与原插件类似,但集成方式更简单、性能表现更好,且与 Docs 的源码渲染体系复用同一套实现(见 MIGRATION.md 中 “Storysource Addon removed” 一节,可对照查看移除步骤)。
从渲染机制看,Code Panel 并非把 .stories 文件当作文本"原样打印",而是渲染 "当前参数的 Story 源码":Story 中通过 args 定义的输入值会被替换成实际生效的值后再输出。例如某个带 children、variant 等参数的 Button Story,在调整控制台参数后,面板里的 JSX 会同步显示控件当前传入的值,从而直观呈现"渲染此状态的代码长什么样"。
在 .storybook/preview 中全局启用 Code Panel
Code Panel 默认关闭,需要显式打开。推荐在 .storybook/preview.* 配置中把 parameters.docs.codePanel 设为 true,这样它会作用于项目中全部 Story,无需逐个组件文件重复配置。配置项的类型定义位于 code/addons/docs/src/types.ts:
/**
* Enable the Code panel.
*/
codePanel?: boolean;
下面的代码片段完整覆盖了不同框架与写法的全局启用方式,可依项目情况直接复制使用。
CSF 3(JavaScript,通用渲染器)
export default {
parameters: {
docs: {
codePanel: true,
},
},
};
CSF 3(TypeScript,通用渲染器)
// Replace your-framework with the framework you are using (e.g., react-vite, vue3-vite, angular, etc.)
import type { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
docs: {
codePanel: true,
},
},
};
export default preview;
使用 TS 时请务必把
your-framework换成你实际安装的框架包,例如@storybook/react-vite、@storybook/vue3-vite、@storybook/angular等。Preview类型能对parameters等字段做编译期校验,避免手写拼错配置。
CSF Next(React,实验性写法 🧪)
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { definePreview } from '@storybook/your-framework';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { definePreview } from '@storybook/your-framework';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
CSF Next(Vue 3)
import { definePreview } from '@storybook/vue3-vite';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
import { definePreview } from '@storybook/vue3-vite';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
CSF Next(Angular)
import { definePreview } from '@storybook/angular';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
CSF Next(Web Components)
import { definePreview } from '@storybook/web-components-vite';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
import { definePreview } from '@storybook/web-components-vite';
export default definePreview({
parameters: {
docs: {
codePanel: true,
},
},
});
说明:带 "CSF Next 🧪" 标签的是使用新一代组件类型推导 API(definePreview 配合 preview.meta())的写法,尚属实验性阶段;上方的 CSF 3 写法(export default 对象 + 类型标注)在当前版本中依然完全可用。两种写法最终都会落到 parameters.docs.codePanel 这一个布尔开关上,面板注册逻辑完全一致。
按组件或按 Story 精细控制
不需要全局开启时,可以把开关下沉到更细的粒度,这也是 docs/_snippets/code-panel-in-meta-and-story.md 里给出的用法:在 Meta 层开启,让本文件所有 Story 都显示 Code Panel;再在个别 Story 层用 codePanel: false 单独关闭。
以 CSF 3 + React 为例:
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Button } from './Button';
const meta = {
component: Button,
parameters: {
docs: {
// 👇 Enable Code panel for all stories in this file
codePanel: true,
},
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// 👇 This story will display the Code panel
export const Primary: Story = {
args: {
children: 'Button',
},
};
export const Secondary: Story = {
args: {
children: 'Button',
variant: 'secondary',
},
parameters: {
docs: {
// 👇 Disable Code panel for this specific story
codePanel: false,
},
},
};
JavaScript 版本与此等价,只是去掉 satisfies Meta<typeof Button> 的类型约束:
import { Button } from './Button';
export default {
component: Button,
parameters: {
docs: {
// 👇 Enable Code panel for all stories in this file
codePanel: true,
},
},
};
// 👇 This story will display the Code panel
export const Primary = {
args: {
children: 'Button',
},
};
export const Secondary = {
args: {
children: 'Button',
variant: 'secondary',
},
parameters: {
docs: {
// 👇 Disable Code panel for this specific story
codePanel: false,
},
},
};
Svelte(Svelte CSF / CSF 3)、Vue 3、Web Components、Angular 及 CSF Next 写法的完整对照示例,可直接参考 docs/_snippets/code-panel-in-meta-and-story.md 中的其余代码块——模式都是相同的:Meta 层开全局、Story 层做例外覆盖。三层配置(preview → meta → story)遵循 Storybook 常规的参数合并语义,离 Story 越近的层级优先级越高,因此这种"开启 + 定向豁免"的组合方式最适合组件库这种既有通用需求又有少量特例的场景。
Code Panel 在 addon-docs 中是如何被注册的
全局启用背后的实现,可以在 docs 插件的 manager 侧看到完整链路。code/addons/docs/src/manager.tsx 中,插件通过 addons.register 注册了一个名为 Code 的面板:
addons.register(ADDON_ID, (api) => {
addons.add(PANEL_ID, {
title: 'Code',
type: types.PANEL,
paramKey: PARAM_KEY,
disabled: (parameters) => !parameters?.docs?.codePanel,
match: ({ viewMode }) => viewMode === 'story',
render: ({ active }) => { /* ... */ },
});
});
从这段注册代码可以提炼出三个关键行为:
disabled由参数驱动:只有当parameters.docs.codePanel为真值时面板才会出现,否则标签页整体隐藏——这正是为什么上面所有配置示例都在"开启"这一个布尔开关上做文章。match限定viewMode === 'story':Code Panel 只出现在 Canvas(story)视图,Docs 页面里想展示源码则应使用 Source 块(Autodocs 场景),两者定位不同。- 源码来自频道事件
SNIPPET_RENDERED:渲染函数通过api.getChannel()读取SNIPPET_RENDERED事件携带的{ id, source, format, warning }(见 manager.tsx 的载荷类型定义),面板组件据此拿到去 Storybook 渲染端抽取、已经过转换的源码字符串。
面板组件 CodePanel 本身还做了两件对体验很重要的事(manager.tsx):
- 防串台:频道上监听
SNIPPET_RENDERED时,会比对事件中的id与当前选中的currentStoryId。若用户在源码抽取完成前切换了 Story,迟到的旧事件会被丢弃,避免慢速抽取覆盖掉新选中 Story 的源码。 - 支持自定义覆盖与暗色主题:展示时优先使用
parameters.docs.source.code手工指定的代码,否则回退到事件抽取结果;面板配色则跟随当前 Storybook UI 主题(theme.base非 light 即视为暗色),保证截图、教学素材与整体 UI 观感一致。
面板内容可定制:复用 Source 块参数体系
Code Panel 展示的代码片段与 Source 文档块(Autodocs 页面也在用同一套渲染管线)完全同源,因此也可以复用 Source 的 parameters.docs.source.* 配置来定制输出。docs 侧的类型定义中,codePanel 与 source、canvas 等一并挂在 parameters.docs 命名空间下(见 types.ts),这意味着它们天然可以互相配合。常用可定制项包括:
code:直接提供自定义源码字符串,面板将原样渲染这段代码,并忽略事件抽取出的 warning;适合展示"伪代码"或需要抹掉敏感实现细节的场景。language/dark:控制高亮语言与明暗模式(默认值分别来自parameters.docs.source.language与parameters.docs.source.dark)。transform:异步转换函数,可基于原始源码与 Story 上下文动态改写后再展示(例如全局用 Prettier 统一格式化所有代码片段,示例见 parameters-docs-source-transform-in-preview.md)。excludeDecorators:决定源码片段是否包含装饰器注入的包裹代码。type:auto/code/dynamic,其中dynamic表示"渲染带当前 arg 值的动态源码"——这正是 Code Panel 在 Canvas 中随控件参数实时更新源码的内在支撑。
在实际渲染优先级上,面板组件先取 parameters.docs.source.code 的手工值,其次才是频道事件刚推送的抽取结果(manager.tsx)。因此,如果你在某个 Story 上写了一段 source.code,它会完全覆盖自动抽取的片段,例如官方模板中的演示 Story 就把面板内容覆盖为一句自定义 JSX。
仓库内验证:模板示例与端到端测试
仓库已经内置了 Code Panel 的演示与验证设施,非常适合用来对照理解上述行为:
- 示例组件故事位于 code/addons/docs/template/stories/codePanel/index.stories.tsx。其中
Default在 Meta 层开启了codePanel: true并配合canvas.sourceState: 'shown';CustomCode通过docs.source.code覆盖展示<button>Custom code</button>;WithoutPanel则在 Story 层用codePanel: false把面板关掉——正好一一对应本文讲解的"启用 / 覆盖 / 豁免"三种用法。该文件的注释还指出它同时服务于code/e2e-internal/story-docs.spec.ts这条端到端测试。 - 想在实际组件库里快速复现,只需按上节示例修改你的
.storybook/preview.*与任意.stories.*文件,然后重新启动 dev server,选中相应 Story,观察工具栏下方是否多出一个 Code 标签页。
从 Storysource 迁移到 Code Panel
对于还在使用旧插件的老项目,仓库根目录 MIGRATION.md("Storysource Addon removed" 一节)给出了清晰的迁移路径:
- 从项目依赖中移除旧插件及 loader(
@storybook/addon-storysource与@storybook/source-loader在 Storybook 9 中已不再提供),例如通过 Storybook CLI 的 addon 管理命令npx storybook remove @storybook/addon-storysource完成卸载。 - 在
.storybook/preview.js(或对应 TS 文件)中开启 Code Panel,即本文第一节的parameters: { docs: { codePanel: true } }配置。 - 若之前仅在部分组件上使用 Storysource,可改为在对应 Meta 或 Story 层配置开关,做到等价且更细粒度的控制。
由于 Code Panel 直接复用了 Docs 的 Source 渲染管线,迁移后通常不需要再维护独立的源码加载器与高亮配置,行为一致性也更好——这是迁移相比继续维护旧插件更省心的主要原因。
小结
一句话概括 Code Panel 的使用模型:先在 .storybook/preview.* 用 parameters.docs.codePanel: true 全局打开,再按组件或 Story 覆盖关闭,最后用 parameters.docs.source.* 微调每个片段的内容与样式。 它只出现在 story 视图,把"源码即参数态"的查看体验收编进 Canvas,配合 Source 块在 Docs 页面的存在,共同构成 Storybook 9 及以后版本中围绕组件源码的完整展示闭环。
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 StartedRust0624
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
