
Storybook Docs 配方实战指南CSF 与 MDX 组合模式、文档页定制与关键参数详解【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook本文基于 Storybook 仓库中 Docs 插件自带的官方配方文档 recipes.md系统讲解在 Storybook Docs 体系下如何组合 CSFComponent Story Format与 MDX 两种故事描述机制以及如何通过docs参数族docs.disable、docs.container、docs.source.transform、viewMode等定制文档页的呈现方式。读完本文你可以为项目选择合适的故事/文档组织模式并掌握文档页级别的描述提取、源码展示转换与容器覆盖等进阶配置。Docs 插件的两套基础机制Docs 插件 由两个基础机制构成DocsPage零配置自动生成文档页和 MDX用富文本语法书写文档与故事。核心问题在于它们各自适合什么场景又该如何组合官方配方文档给出的答案是——存在多种合法组合且每种组合有明确的适用边界。配方一CSF DocsPage推荐主用法Component Story Format 是一种便捷、可移植的故事写法而 DocsPage 是零配置即可为 CSF 故事生成富文档页面的机制。两者结合是 Storybook Docs 的首要使用场景你只需按标准 CSF 编写.stories.js文件文档页包含 Canvas、Args 表格、Source 代码块、故事列表即自动生成无需任何额外配置。如果你想在 Storybook 中穿插长篇文档例如在故事列表开头放置一页设计系统介绍和安装说明官方建议单独编写 Documentation-only 的 MDX 文件而不是硬塞进组件故事文件。配方二纯 MDX StoriesMDX 是 CSF 之外的另一种故事语法允许把故事和文档写在同一个文件里。配方文档明确指出凡是 CSF 能做的事MDX 都能做并且两者在构建层面暴露的是相同的模块接口文件可以互相替换。一些团队选择用 MDX 编写全部 Storybook 内容。组合模式CSF 故事 MDX 文档如果你希望故事逻辑用 CSF 写、文档用 MDX 写标准做法是让 MDX 文件成为该组件的真正“故事文件”。Button.stories.jsimport React from react; import { Button } from ./Button; // 注意不再有 default export因为 Button.stories.mdx 现在是 Button 的故事文件 // // export default { // title: Demo/Button, // component: Button, // }; export const basic () ButtonBasic/Button; basic.parameters { foo: bar, };Button.stories.mdximport { Meta, Story } from storybook/addon-docs; import * as stories from ./Button.stories.js; import { Button } from ./Button; import { SomeComponent } from path/to/SomeComponent; Meta titleDemo/Button component{Button} / # Button 我可以用从 CSF 导入的函数来定义故事 Story story{stories.basic} / 并且可以在这个文件中嵌入任意的 markdown 与 JSX。 SomeComponent prop1val1 /这套组合的工作机制如下故事定义在 CSF 文件中但由于同名的Button.stories.mdx存在CSF 文件不再被直接注册为独立的故事列表原文档以includeStories: []机制解释这一点故事实际经由 MDX 中的Story story{}块呈现CSF 中命名导出的故事保留其故事级 decorators、parameters、args 标注且Story story{}构造会尊重这些标注例如basic.parameters中定义的foo: bar仍然生效原本挂在Button.stories.jsdefault export 上的组件级 decorators、parameters 等不会自动继承如需要必须手动拷贝到 MDX 的Meta中。组合模式CSF 任意 MDX官方推荐上面的“CSF MDX Docs”作为标注 CSF 故事的最优方式但如果只是想引用任意 markdown 文件作为文档页还有第二种选择。Button.mdximport { Story } from storybook/addon-docs; import { SomeComponent } from somewhere; # Button 我可以嵌入一个已有的故事但不能定义新故事因为这个文件里不应该有 Meta Story idsome--id / 并且可以嵌入任意 markdown 与 JSX。 SomeComponent prop1val1 /Button.stories.jsimport React from react; import { Button } from ./Button; import mdx from ./Button.mdx; export default { title: Demo/Button, parameters: { docs: { page: mdx, }, }, component: Button, }; export const basic () ButtonBasic/Button;这里有一个与上文截然不同的关键点MDX 文件后缀是.mdx而非.stories.mdx。这个区别意味着该文件走的是默认 MDX loader而不是 Storybook 的 CSF loader由此带来三条约束文件中不应提供Meta声明只能引用已有故事Story id...不能定义新故事不能用Story name...文档以 MDX 的 default export 形式导出并通过docs.page参数挂载而不是像 CSF 那样作为 default export 参数的一部分。这一点在插件的类型定义中有直接印证docs.page被声明为“用你自己的组件替换 Storybook 默认文档模板”的选项类型为ComponentType见 types.ts。混合 storiesOf 与 CSF/MDX如果项目中还有一批使用storiesOf旧 API 的故事或者存在只能用storiesOf实现的故事例如动态生成的故事需要与 CSF/MDX 共存。configure的第一个参数可以是require.context返回的req、req数组或者一个 loader 函数loader 函数要么返回 null要么返回一个“全部包含 default export”的模块导出数组configure依据 default export 来识别并加载 CSF/MDX 文件。一个假设“storiesOf 文件都不含 default export”的朴素实现如下const loadFn () { const req require.context(../src, true, /\.stories\.js$/); return req .keys() .map((fname) req(fname)) .filter((exp) !!exp.default); }; configure(loadFn, module);官方说明他们可以把这个启发式逻辑内置进 Storybook但无法假设你的storiesOf文件没有 default export。如果确实有需要用别的方式比如按文件名过滤。若不过滤会看到显式报错Loader function passed to configure should return void or an array of module exports that all contain a default export官方特意让这个报错显式化以提醒你正在混合storiesOf与 CSF/MDX。从 notes/info 插件迁移自定义描述提取如果项目此前使用 notes/info 插件给每个组件挂了notes参数markdown 文本迁移到 Docs 插件时可以自定义docs.extractComponentDescription参数把notes内容提取到文档页顶部的 Description 区域。假设你希望notes显示在Description插槽顶部可以在.storybook/preview.js中加入import { addParameters } from storybook/preview-api; addParameters({ docs: { extractComponentDescription: (component, { notes }) { if (notes) { return typeof notes string ? notes : notes.markdown || notes.text; } return null; }, }, });从源码看Description 块的渲染逻辑正是调用这个可插拔函数在 Description.tsx 中组件描述和故事描述均通过parameters.docs?.extractComponentDescription?.(component, { ... })动态计算参数为可选链调用未提供时回退到默认行为。docs preset 的默认extractComponentDescription从组件源码中提取 JSDoc 注释作为描述并忽略第二个参数当前选中故事的故事 parameters而上例则相反——忽略注释、改用该故事的notes参数。仓库中自带的文档故事也演示了最简单的形式见 extract-description.stories.ts直接extractComponentDescription: () component description返回固定字符串。导出纯文档站点Storybook 的 UI 是“组件开发工作台”而 Docs 是“文档展示橱窗”。开发时两种模式并排查看很有用但导出静态站点时可能希望只保留文档页以减少冗余。为此 Storybook 提供了 CLI 标志yarn storybook build --docs注意原始配方文档写作于 Storybook 5.2 时期当时该标志被标记为实验特性5.3 中行为可能不受 semver 约束地变化。在当前仓库所处的版本线中它已成为 docs 构建的常规选项适用前提是你的文档页由 docs 插件DocsPage 或 MDX驱动。禁用文档中的故事docs.disable有两类场景需要把某些故事从文档页中排除。DocsPage 场景故事用 CSF 定义、用 DocsPage 渲染文档但希望排除部分故事以减少页面噪音export const foo () Buttonfoo/Button; foo.parameters { docs: { disable: true } };MDX 场景在单个 MDX 文件中并排写文档与故事希望故事出现在 Canvas 中但不进入文档页相当于“CSF stories with MDX docs”的纯 MDX 版本Story namefoo parameters{{ docs: { disable: true } }} Buttonfoo/Button /Story参数类型上docs.disable被声明为boolean语义是“移除该插件面板并禁用其行为”见 types.ts。控制故事的视图模式viewModeStorybook 默认的导航行为是保持当前视图模式用户处于 docs 模式时点击另一个故事仍以 docs 模式打开处于 story 模式UI 中的 canvas时则保持 story 模式例外docs-only 页面永远以 docs 模式显示。基于用户反馈可以用viewMode故事参数控制单个故事进入时强制切换的视图模式。以下示例保证导航到该故事时视图模式重置为 storyexport const Foo () Component /; Foo.parameters { // 用户导航到该故事时始终把视图模式重置为 story viewMode: story, };也可以在.storybook/preview.js中全局生效// 用户导航时始终把视图模式重置为 docs export const parameters { viewMode: docs, };调整 Docs 标签页顺序previewTabs用previewTabs故事参数可以配置 preview 区域的标签页顺序。把Docs标签排到最前面export const Foo () Component /; Foo.parameters { previewTabs: { storybook/docs/panel: { index: -1 } }, };同样可全局写在.storybook/preview.js中。定制源码展示docs.source.code 与 docs.source.transform从 SB 6.0 起定制 Docs 源码展示有两条互补的路径覆盖docs.source.codeSource 块直接渲染你提供的字符串适合故事级的精确控制const Example () Button /; Example.parameters { docs: { source: { code: some arbitrary string } }, };提供docs.source.transform函数适合全局格式化。以下示例全局剥掉“返回字符串的箭头函数”外壳() \...const SOURCE_REGEX /^\(\) (.*)$/; export const parameters { docs: { source: { transform: (src, storyContext) { const match SOURCE_REGEX.exec(src); return match ? match[1] : src; }, }, }, };插件的源类型定义明确了 transform 的签名(code: string, storyContext: any) string | Promisestring即允许同步或异步转换见 types.ts。同一配置块中还支持typeauto | code | dynamic默认auto、formattrue/dedent或任意 prettier parser 名、language等选项详见 types.ts。两种方法互补前者适合故事级覆盖后者适合全局格式化处理。覆盖文档容器docs.container当你想给 MDX 页面包一层 wrapper 或注入 React context例如styled-components的ThemeProvider时需要注意decorator 只作用于故事而 MDX 中Story块之外的任意 JSX 不受 decorator 影响此时必须使用docs.container参数。container是 Docs 体系中与 decorator 最接近的概念——一个包裹在被渲染页面外围的元素。官方示例给页面加一圈红色实线边框。它复用了 Storybook 默认的页面容器负责搭建各类 context 与内部机制然后在该容器与页面内容之间插入自定义逻辑import { Meta, DocsContainer } from storybook/addon-docs; Meta titleAddons/Docs/container-override parameters{{ docs: { container: ({ children, context }) ( DocsContainer context{context} div style{{ border: 5px solid red }}{children}/div /DocsContainer ), }, }} / # Title 文件的其余部分...styled-components主题场景下的典型用法import { Meta, DocsContainer } from storybook/addon-docs; import { ThemeProvider } from styled-components; import { theme } from ../path/to/theme; Meta titleAddons/Docs/container-override parameters{{ docs: { container: ({ children, context }) ( DocsContainer context{context} ThemeProvider theme{theme} {children} /ThemeProvider /DocsContainer ), }, }} / # Title 文件的其余部分...实现层面自定义容器的类型为ComponentTypeDocsContainerProps见 types.ts默认容器实现位于 DocsContainer.tsx。自定义container的推荐模式是包裹默认DocsContainer以保留其提供的上下文与内部逻辑而不是完全替换它。为单个故事添加描述docs.description.story在docs.description参数中加入story字段即可为单个故事添加描述支持 markdown 语法const Example () Button /; Example.parameters { docs: { description: { story: Individual story description, may contain markdown markup, }, }, };配方文档还提到存在第三方 webpack loaderstory-description-loader可从 JSDoc 注释中提取描述属于原文档时代的生态补充当前使用时需自行确认其对新版本 Storybook 的兼容性。延伸阅读参考文档本仓库内README / DocsPage / MDX / FAQ / Theming / Props 表格参数类型定义code/addons/docs/src/types.tsDocsParameters.docs全量字段argTypes、canvas、codePanel、controls、container、description、disable、page、source、story、stories、subtitle、lang、theme、title、toc默认描述提取与自定义示例Description.tsx / extract-description.stories.ts各框架的 Docs 文档见 code/renderers/react、code/renderers/vue3 等框架渲染器目录下的配套说明以上配方均直接取自仓库中的官方文档 code/addons/docs/docs/recipes.md其中的参数签名与行为可通过 code/addons/docs/src/types.ts 的类型定义和 code/addons/docs/src/blocks/blocks 下的块实现逐一验证。【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考