Storybook Code Panel 按组件(Meta)与按 Story 细粒度启用全指南:`parameters.docs.codePanel` 配置详解
2026/9/18 2:23:06 网站建设 项目流程

Storybook Code Panel 按组件(Meta)与按 Story 细粒度启用全指南:parameters.docs.codePanel配置详解

本指南围绕 Storybook 的 Code Panel(代码面板)功能展开,重点讲解如何通过parameters.docs.codePanel参数在组件级(Meta)与单个 Story 级分别控制面板的显隐,覆盖 CSF 3、CSF Next(实验性)与 Svelte CSF 三种写法,以及 React、Vue 3、Angular、Web Components、Svelte 等框架的差异。读完本文,你将能精确到“某个文件开启、某个 Story 关闭”地管理代码面板,并理解该面板底层由哪些源码与通道事件驱动。

Code Panel 是什么:在画布中直接阅读 Story 的真实源码

Code Panel 是 Storybook Docs 提供的“故事源码预览面板”:当你在画布(Canvas)中查看某个 Story 时,切换到Code标签页即可看到该 Story 的源码,并且Story 中定义的 args 会被替换成其实际传入值,因此你看到的是与当前渲染结果严格一致的“可运行源码”,而非模板占位符。

按当前仓库文档 docs/writing-docs/code-panel.mdx 的说明,Code Panel 是Storysource 插件的替代方案(该插件在 Storybook 9 中被移除)。仓库中对应提供了自动化迁移修复addon-storysource-code-panel(见 code/lib/cli-storybook/src/automigrate/fixes/addon-storysource-code-panel.ts),负责移除@storybook/addon-storysource并在预览配置中写入parameters.docs.codePanel: true,我们将在后文展开。

从实现看,该面板是注册在 manager 端(UI)的一个 Addon Panel。仓库 code/addons/docs/src/manager.tsx 中通过addons.add注册了标题为Code的面板,并声明了两条关键规则:

  • disabled: (parameters) => !parameters?.docs?.codePanel—— 面板的“禁用”状态完全取决于当前渲染上下文合并后的parameters.docs.codePanel
  • match: ({ viewMode }) => viewMode === 'story'—— 面板仅在 story 视图(画布)中出现,而不出现在 docs 页面。

换言之,只要不显式设置codePanel: true,面板标签就不会出现;而开启后,默认面板始终对当前 Story 生效。

三层配置作用域与优先级:全局预览、组件(Meta)、单个 Story

docs.codePanel是一个布尔参数,理论上可以放在 Storybook 参数体系中的任何一层,实际使用中遵循 Storybook 的 parameters 合并规则:Story 渲染时会按preview → meta(组件)→ story的顺序合并各级parameters,下级对上级进行覆盖。因此你可以非常灵活地组合:

配置位置配置方式影响范围
全局.storybook/preview.*parameters.docs.codePanel: true项目内所有 Story 都显示 Code Panel
组件级metaparameters.docs.codePanel: true / false.stories文件内所有 Story 生效
Story 级parametersparameters.docs.codePanel: true / false仅覆盖该 Story,粒度最细

官方推荐的默认做法是在.storybook/preview.*中全局开启(见 docs/_snippets/code-panel-enable-in-preview.md),这样所有 Story 默认都展示源码面板;如果个别组件或 Story 需要例外,再用后两层做局部覆盖。

实际常见用法是在 meta 层开启、在某个 Story 层单独关闭(或在全局开启后局部关闭)。这正是本文重点讲解的“Meta 与 Story”两级控制:

  • meta 中codePanel: true→ 该文件内每个 Story 都默认显示 Code 标签页;
  • 某个 Story 中codePanel: false→ 仅该 Story 不显示面板,文件内其他 Story 不受影响。

在 Meta 与 Story 中配置的完整代码示例(多框架)

由于 Code Panel 属于 docs 参数体系,任何使用 Storybook Docs 的框架写法一致——把codePanel放进docs参数即可。下面按写法形态分组给出可直接复制运行的完整示例。

形态一:标准 CSF 3 + TypeScript(React 示例)

Button.stories.tsx

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, }, }, };

要点说明:

  • codePanel必须嵌套在parameters.docs内,与docs.pagedocs.canvasdocs.source同级;
  • 上面的Primary没有写任何codePanel,继承 meta 的true,因此会显示 Code 面板;
  • Secondary在自身parameters.docs中把codePanel覆盖为false,因此不显示面板。

形态二:CSF 3 在 Angular、Vue 3、Web Components 中的差异点

本文件对应的原始代码片段 docs/_snippets/code-panel-in-meta-and-story.md 按渲染器给出了 angular、react、svelte、vue、web-components 五个渲染器、每种含 TS/JS 与 CSF 3/CSF Next 的完整变体。除导入路径与类型书写略有差异外,结构与上面的 React 示例完全一致,差异点如下:

  • Angular(TS)import type { Meta, StoryObj } from '@storybook/angular';,组件为类组件Button from './button.component',写法同 CSF 3。
  • Vue 3(TS)import type { Meta, StoryObj } from '@storybook/vue3-vite';,组件为import Button from './Button.vue'
  • Web Components(TS):最特殊——meta不再使用组件类,而是自定义元素标签名
import type { Meta, StoryObj } from '@storybook/web-components-vite'; const meta: Meta = { component: 'demo-button', // 👈 自定义元素标签名,而非组件对象 parameters: { docs: { // 👇 Enable Code panel for all stories in this file codePanel: true, }, }, }; export default meta; type Story = StoryObj; // 👇 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, }, }, };
  • JS 变体:去掉import typesatisfies Meta<typeof Button>类型标注,改用export default { component: Button, ... }的对象字面量形式,逻辑完全相同。

形态三:CSF Next(🧪 实验性)的preview.meta/preview.story写法

CSF Next 是仓库文档中标注为实验性(🧪)的新写法,它不再使用export default meta,而是从.storybook/preview导入preview对象,再调用preview.meta({ ... })preview.story({ ... })构造。codePanel参数本身与 CSF 3 没有区别,例如 React TS 变体:

import preview from '../.storybook/preview'; import { Button } from './Button'; const meta = preview.meta({ 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 = meta.story({ args: { children: 'Button', }, }); export const Secondary = meta.story({ args: { children: 'Button', variant: 'secondary', }, parameters: { docs: { // 👇 Disable Code panel for this specific story codePanel: false, }, }, });

CSF Next 同样覆盖 Angular(definePreview/preview.meta来自@storybook/angular)、Vue 3(@storybook/vue3-vite)、Web Components(@storybook/web-components-vite)与 React(@storybook/your-framework),TS/JS 差异同样只在于类型标注。

形态四:Svelte CSF(addon-svelte-csf)的.stories.svelte写法

Svelte 额外支持把 Story 写在.svelte单文件里,通过<script module>中的defineMeta定义 meta,用<Story>组件声明各 Story。注意此时Story 级覆盖通过<Story parameters={{ ... }}>属性传入

<script module> import { defineMeta } from '@storybook/addon-svelte-csf'; import Button from './Button.svelte'; const { Story } = defineMeta({ component: Button, parameters: { docs: { // 👇 Enable Code panel for all stories in this file codePanel: true, }, }, }); </script> <Story name="Primary" args={{ children: 'Button', }} /> <Story name="Secondary" args={{ children: 'Button', variant: 'secondary', }} parameters={{ docs: { // 👇 Disable Code panel for this specific story codePanel: false, }, }} />

若你使用普通 Svelte CSF 3 写法(.stories.ts文件),则与 React/TypeScript 的 CSF 3 形态一致,导入MetaStoryObj时按注释把@storybook/your-framework替换为实际使用的svelte-vitesveltekit即可。

面板内容由谁决定:源码级原理

理解“在哪里开启”之后,再理解“面板到底渲染什么”能让配置更可控。仓库 code/addons/docs/src/manager.tsx 的CodePanel组件揭示了内容来源,其取值优先级为:

  1. parameter.source?.code—— 即docs.source.code参数中硬编码的源码,优先级最高;
  2. codeSnippet.source—— 渲染管线通过SNIPPET_RENDERED通道事件推送过来的、针对当前 Story 生成的代码片段;
  3. parameter.source?.originalSource—— 兜底使用参数的原始源码。

关于第 2 点,manager 端通过useChannel监听SNIPPET_RENDERED事件,并校验事件中的id必须等于currentStoryId,避免“上一次选中 Story 的异步片段生成完成后覆盖当前面板”的竞态问题;随后用主题感知的Source组件(支持暗色主题)把代码渲染进AddonPanel

而参数类型的权威定义在 code/addons/docs/src/types.ts 的DocsParameters接口中:

export interface DocsParameters { docs?: { /** * Enable the Code panel. * * @see https://storybook.js.org/docs/writing-docs/code-panel */ codePanel?: boolean; // ... source?: Partial<SourceBlockParameters>; // ... }; }

可以看到,codePanel是布尔可选值,未设置即视为关闭;它与docs.sourcedocs.canvas等参数同属 docs 命名空间,因此设置docs.codePanel时不要误写成parameters.codePanel

docs.source参数自定义 Code Panel 的内容

如 docs/writing-docs/code-panel.mdx 所述,Code Panel 渲染的正是 Source 文档块(Doc Block Source)使用的同一条代码片段,因此它复用 Source 的全部配置参数。也就是说:与其在 meta/Story 层反复开关codePanel,不如进一步用docs.source微调展示内容。仓库中的模板 Story code/addons/docs/template/stories/codePanel/index.stories.tsx 就演示了这三种典型用法:

export default { component: globalThis.__TEMPLATE_COMPONENTS__.Button, tags: ['autodocs'], parameters: { chromatic: { disableSnapshot: true }, docs: { codePanel: true, // 整个文件开启 Code Panel }, }, }; /** 展示 Code panel 的默认 Story,同时强制画布中源码区可见 */ export const Default = { args: { label: 'e2eStoryDocsBefore' }, parameters: { docs: { canvas: { sourceState: 'shown', }, }, }, }; /** 用 docs.source.code 硬编码自定义源码 */ export const CustomCode = { args: { label: 'Custom code' }, parameters: { docs: { source: { code: '<button>Custom code</button>', }, }, }, }; /** Story 级关闭 Code Panel */ export const WithoutPanel = { args: { label: 'Without panel' }, parameters: { docs: { codePanel: false, }, }, };

这个模板文件本身被仓库的端到端测试 code/e2e-internal/story-docs.spec.ts 复用:测试会打开标题为Code的标签页并断言面板文本内容,例如“在不发生导航的情况下修改 Story args 后,Code Panel 与 Autodocs 源码随之热更新”,从而验证了“Code 面板显示的源码会随 args 实时同步”这一行为。

从 Storysource 迁移到 Code Panel(自动化修复)

如果你此前使用@storybook/addon-storysource,升级到新版本后可通过 automigrate 一键迁移。仓库中 code/lib/cli-storybook/src/automigrate/fixes/addon-storysource-code-panel.ts 定义了 id 为addon-storysource-code-panel的修复项,其核心流程为:

  • 检查项目 addons 中是否包含@storybook/addon-storysource
  • 命中后提示“将移除 @storybook/addon-storysource 并改用 Code Panel”;
  • 从 addons 中移除该插件,并自动在预览配置文件里写入parameters.docs.codePanel: true(通过previewConfig.setFieldValue(['parameters', 'docs', 'codePanel'], true))。

因此,旧版依赖 Storysource 显示源码的用户,在新版中应直接改用本文的codePanel参数——对绝大多数项目,全局在.storybook/preview.*中开启一次即可,之后仅在个别组件(meta)或个别 Story 中做精确的true/false覆盖。

最佳实践小结

  • 默认全局开启:在.storybook/preview.*(TS 版可参考 docs/_snippets/code-panel-enable-in-preview.md)中写docs: { codePanel: true },让所有 Story 获得一致的“可复制源码”体验;
  • 文件级批量控制放 meta:某些示例文件不希望暴露实现细节时,可在该metaparameters.docs中设codePanel: false,或对个别演示 Story 单独覆盖;
  • Story 级精细覆盖:在需要隐藏源码、展示“无代码”形态(例如截图基线、无障碍对比)的 Story 上设codePanel: false,互不影响;
  • 结合docs.source使用:面板与 Source 块共享渲染管线,自动生成的代码不理想时,可用source.code直接指定展示内容;
  • 注意参数路径:务必写全parameters.docs.codePanel,且布尔值不要写成字符串;未设置时面板默认隐藏,这与 manager 端disabled: (parameters) => !parameters?.docs?.codePanel的实现完全对应。

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询