react-styleguidist 组件示例文档(Readme.md)编写完全指南:从 Markdown 到交互式 Playground
【免费下载链接】react-styleguidistIsolated React component development environment with a living style guide项目地址: https://gitcode.com/gh_mirrors/re/react-styleguidist
导读
在 react-styleguidist 中,组件文件夹下的Readme.md(或ComponentName.md)不仅是一份文字说明,更是驱动样式指南(living style guide)中交互式 Playground的核心载体:文档里的js/jsx/javascript代码块会被编译成可实时编辑、即时预览的 React 示例。本文以仓库测试样例 test/components/Button/Readme.md 为骨架,结合examples/basic中的真实组件文档与src/loaders、src/client下的源码实现,系统讲解示例文档的语法、代码块修饰符(modifier)、组件作用域与状态管理机制,并深入源码解释其底层解析与运行时原理。读完本文,你将掌握编写高质量组件示例文档的完整方法,并能理解样式指南前端是如何把一段 Markdown 变成可运行的 React 组件。
一、一份最小可用的组件示例文档
在 react-styleguidist 中,示例文档的默认文件名由 getExampleFilename 配置项决定(默认是Readme.md)。Styleguidist 会在组件所在目录中查找Readme.md或ComponentName.md并将其渲染到样式指南页面中。文档中的普通 Markdown 会原样渲染(支持强调、链接、列表等),而带语言标识的围栏代码块则会按语言类型做不同处理。
以仓库测试样例 test/components/Button/Readme.md 为例,这是一份最小可用文档:
Basic button: <Button>Push Me</Button> Big pink button: <Button size="large" color="deeppink">Click Me</Button> And you _can_ **use** `any` [Markdown](http://daringfireball.net/projects/markdown/) here.import React from 'react'这段样例至少展示了三件事:
- 无语言标识的代码块(缩进代码块):为了向后兼容,不写语言标签的代码块也会被当作 React 示例渲染成 Playground。官方文档 docs/Documenting.md 明确建议新文档中始终使用规范的语言标签,因此实际项目中更推荐写成
```jsx围栏代码块。 - 当前组件自动可见:示例代码里直接使用
<Button>,不需要import,因为当前组件在示例作用域内是隐式可用的。 - 任意 Markdown 语法混排:文字描述与示例代码可以自由交错,形成"说明 + 演示"的阅读节奏。
二、代码块的三种去向:Playground、高亮源码、普通代码
文档正文里出现的围栏代码块会被 src/loaders/utils/chunkify.ts 统一处理。它遍历 Markdown 的 AST,对每个code节点调用parseExample解析语言与修饰符,然后按以下规则分流(源码见chunkify.ts第 45-61 行):
| 代码块语言 | 处理结果 |
|---|---|
js/jsx/javascript(及ts/tsx/typescript,见PLAYGROUND_LANGS常量) | 渲染为交互式 Playground(除非带static修饰符) |
| 无语言标签的缩进代码块 | 向后兼容,同样渲染为 Playground |
其他语言(如html) | 仅渲染为高亮源码,不运行 |
对应到examples/basic/src/components/Button/Readme.md中的示例:```html <h1>Hello world</h1>会被highlightCode高亮展示,而```jsx代码块则进入 Playground 管线。
底层实现:parseExample 与 modifiers 解析
代码块头部"语言 + 修饰符"的解析由 src/loaders/utils/parseExample.ts 完成:
- 修饰符可以是空格分隔的单词串(如
```jsx padded),会被拆分成{ padded: true }这样的设置对象; - 也可以是JSON 对象(如
```js { "props": { "className": "checks" } }),会直接JSON.parse成设置; - 解析得到的设置键名会被统一转为小写(
lowercaseKeys),因此showCode与showcode等价; - 若 JSON 无法解析,
parseExample会返回错误对象,提示信息会引导用户查看文档,相关行为由 parseExample.spec.ts 中的测试用例覆盖。
三、代码块修饰符(Modifier)全解
examples/basic/src/components/Button/Readme.md系统地演示了所有内置修饰符,本节逐一展开,并结合 Playground.tsx 说明其运行时行为。
3.1padded:给预览加内边距
<Button>Push Me</Button> <Button>Click Me</Button> <Button>Tap Me</Button>在 Playground 的render()中,settings.padded会作为paddedprop 传给PlaygroundRenderer,从而给预览区域添加内边距类名(见 Playground.tsx 第 88 行与 PlaygroundRenderer.tsx 第 67 行)。当一个代码块里连续放置多个示例组件、彼此紧贴显得拥挤时,padded能改善视觉间隔。
3.2noeditor:隐藏代码编辑器,只留预览
<Button>Push Me</Button>noeditor用于只展示运行效果、不让读者改代码的场景。Playground 渲染时:
const isEditorHidden = settings.noeditor || isExampleHidden;noeditor为真时直接渲染<Para>{preview}</Para>,不渲染编辑器与工具栏(Playground.tsx 第 79-83 行)。相关行为在 Playground.spec.tsx 第 62-65 行有专门测试。
3.3static:只展示高亮源码,不运行
import React from 'react'static修饰符适用于你希望读者看到一段 JavaScript 代码、但又不希望它被当作可运行组件的情形。在chunkify.ts的判断条件中,即使语言属于 Playground 语言,只要设置了static就不会进入 Playground 分支,而是走highlightCode高亮路径(chunkify.ts第 47-61 行)。官方文档特别提示:需要展示纯 JS 代码时,推荐使用带语言标签的js static写法,见 docs/Documenting.md。
3.4 JSON 修饰符:给预览外层套 props
<Button>I’m transparent!</Button>以 JSON 形式书写的修饰符会被解析进settings,其中props会被透传给预览容器:previewProps={settings.props || {}}(Playground.tsx 第 90 行)。这常被用来给示例外层包裹自定义类名或样式。
3.5showcode:默认展开代码编辑器
虽然examples文档中未直接出现,但源码中同样支持showcode修饰符:settings.showcode !== undefined ? settings.showcode : expandCode决定了代码编辑器标签页初始是否展开(Playground.tsx 第 63-66 行)。showcode的优先级高于配置项exampleMode,并有 Playground.spec.tsx 第 72-109 行的测试覆盖。
3.6updateExample:自定义修饰符的入口
如果你需要引入自己的修饰符,可以通过配置项 updateExample 钩子改写每个示例对象的content、lang、settings。在 examples-loader.ts 第 30-32 行中,updateExample会被包装并传入chunkify,由parseExample在解析后调用。
四、示例中的组件作用域与 import 规则
4.1 当前组件与 React 隐式可用
在Button的示例文档中,<Button>无需导入即可使用。这一机制的实现在 examples-loader.ts 第 51-60 行:
const fullContext = { ...config.context, // Append React, because it’s required for JSX React: 'react', // Append the current component module to make it accessible in examples ...(displayName ? { [displayName]: file } : {}), };构建期会把React与当前组件模块预先require进运行时上下文,因此在示例代码中写 JSX 不需要自己import React。
4.2 其他组件必须显式导入
如果示例要用到别的组件,必须显式导入:
import Placeholder from '../Placeholder' ;<Button> <Placeholder /> </Button>或者显式导入所有依赖,让示例代码可以直接复制到业务代码中使用:
import React from 'react' import Button from 'rsg-example/components/Button' import Placeholder from 'rsg-example/components/Placeholder' ;<Button> <Placeholder /> </Button>注意:
rsg-example是配置文件里 moduleAliases 定义的别名,见examples/basic/styleguide.config.js对应的配置;实际项目中请替换为真实的模块别名或相对路径。
examples-loader会扫描示例代码中的所有import语句(getImports.ts),把它们预编译进 webpack 的 require 映射,运行期再通过requireInRuntime与evalInContext执行(examples-loader.ts 第 95-101 行)。另外,import只能在 Markdown 文件中编辑,不能通过浏览器里的示例编辑器输入(参见 docs/Documenting.md 的 Caution 提示)。
五、示例即函数组件:用 useState 管理状态
每个代码示例在运行期都会被编译成一个函数组件,因此可以直接使用 React Hooks。examples/basic/src/components/Button/Readme.md给出了两个状态示例:
const [isOpen, setisOpen] = React.useState(false) ;<div> <Button size="small" onClick={() => setisOpen(true)} disabled={isOpen} > Show Me </Button> {isOpen && ( <Button size="small" onClick={() => setisOpen(false)}> Hide Me </Button> )} </div>以及自定义初始状态:
const [count, setCount] = React.useState(42) ;<Button onClick={() => setCount(count + 1)}>{count}</Button>运行时链路如下:ReactExample.tsx 先通过compileCode(底层使用 Bublé 编译 ES6+JSX)处理示例代码,再用evalInContext执行并取最后一个顶层表达式作为组件,最后包上Wrapper渲染进预览区。由于每个示例都是独立函数组件,示例之间的状态互不影响。如果示例要消费 React Context,需要在示例内或自定义Wrapper中提供 Provider(参考examples/sections/src/components/ThemeButton的写法)。
六、示例文档的进阶组织方式
6.1 外部示例文件:@example doclet
除了Readme.md,还可以通过 JSDoc 的@exampledoclet 标签关联额外的示例文件:
/** * Component is described here. * * @example ./extra.examples.md */ export default class Button extends React.Component { // ... }需要说明的是:当配置项 skipComponentsWithoutExample 为true时,组件仍需要一个常规示例文件(如Readme.md)才能被收录(见 docs/Documenting.md)。示例文件的查找与加载逻辑见 getExamples.ts:它优先加载存在的示例文件,否则回退到默认示例模板templates/DefaultExample.md。
6.2 大段复杂示例:抽取独立文件再导入
官方建议:如果某个演示过于复杂,最好在独立的 JavaScript 文件中定义,再在 Markdown 中import引入(见 docs/Documenting.md)。这样既保持了文档的可读性,也便于复用与测试。
6.3 示例的解析链路回顾
一个示例文档从 Markdown 到页面渲染,核心调用链为:
styleguide-loader通过 getExamples.ts 定位示例文件,交给examples-loader;examples-loader调用 chunkify.ts 用 remark 解析 Markdown,把代码块分流为code与markdown两种 chunk,并收集所有 import;- 构建产物在客户端由 ReactExample.tsx 编译、求值并渲染,最终包裹在 Playground.tsx 的编辑器中供读者实时修改预览。
七、编写高质量示例文档的实践建议
综合test/components/Button/Readme.md与examples/basic/src/components/Button/Readme.md的写法,以及 docs/Documenting.md 的规范,整理出以下 checklist:
- 始终使用语言标签:
js、jsx、javascript会变成 Playground,其他语言只高亮,避免使用无标签缩进代码块。 - 先文字后示例:每个代码块前用一句 Markdown 说明意图,形成"说明 + 演示 + 说明"的叙事节奏。
- 善用修饰符:批量示例用
padded留白、纯展示用noeditor、纯代码展示用static、需要给预览容器传类名时用 JSON 修饰符{ "props": { "className": "..." } }。 - 显式导入依赖:当前组件可直接用,其他组件显式
import,需要复制到业务代码的示例建议全部显式导入并配合moduleAliases。 - 用 useState 演示交互:把按钮点击、开关切换等状态逻辑直接写进示例,读者在浏览器里即可体验真实交互。
- 复杂演示抽文件:超过十几行的示例放入独立 JS 文件再导入,保持 Markdown 简洁。
按照上述方法,你写出的组件文档将不仅是静态说明,而是可运行、可编辑、可复制的活文档,这正是 react-styleguidist "living style guide" 的核心价值所在。
【免费下载链接】react-styleguidistIsolated React component development environment with a living style guide项目地址: https://gitcode.com/gh_mirrors/re/react-styleguidist
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考