首页
/ Storybook 文档风格规范:docs-review Skill 的 storybook-style.md 规则与自动校验实现全解

Storybook 文档风格规范:docs-review Skill 的 storybook-style.md 规则与自动校验实现全解

2026-09-05 19:29:51作者:董宙帆

本文深入讲解 Storybook 仓库中 docs-review Agent Skill 的核心参考文件 storybook-style.md。该文件定义了 Storybook 官方文档(/docs 目录下的 MDX 页面)的编辑语气、标题、链接、MDX 自定义组件、frontmatter 与块级 JSX 排版规则。读完后,你将掌握这套文档风格规范的每一条规则与正反示例,并能理解规则中标注 [auto] 的检查项是如何被 check-docs.ts 逐条实现、通过 yarn docs:check 自动校验的。

这套风格指南在整个 Skill 体系中的位置

storybook-style.mdSKILL.md 定义的 docs-review 文档审查技能下的四个参考文件之一,它"拥有"(owns)Storybook 特有的编辑、MDX 组件、frontmatter 与校验规则,但不拥有文档类型识别、模式路由或干预逻辑——那些属于 docs-strategy.md。按 SKILL.md 的加载表:

参考文件 负责内容 加载时机
docs-principles.md 北极星目标、质量维度、双读者要求 总是最先读取
docs-strategy.md 模式、文档类型、干预阈值、页面形态指导 总是第二读取
docs-antipatterns.md 诊断模式与纠正手段 诊断薄弱或混乱草稿时
storybook-style.md 编辑、MDX 组件、frontmatter、格式、校验规则 maintenance 模式,或各编辑模式的最后收尾

所有权规则(Ownership Rules)明确划界:策略类参考文件不拥有格式或组件规则,storybook-style.md 不拥有文档类型或干预逻辑,SKILL.md 本身只拥有工作流与交接。对应地,在 SKILL.md 的工作流中,第 6 步"应用 Storybook 风格"永远位于结构性、编辑性工作之后——"这一步永远不是第一遍"。

语气与文风(Voice and Tone)

人称(Point of View)

  • 第二人称("you")——面向读者的默认形式。
  • 第一人称复数("we")——代表 Storybook 团队发言时使用(如 "We recommend…"),或表示"我们一起看看"(如 "Let's take a look…")。
  • 禁用第一人称单数("I")和以第三人称称呼读者("the user")。

语气(Tone)

  • 专业但口语化——像给同事讲解,而非写教科书。
  • 鼓励但不夸张——偶尔一句 "That's great!" 可以,避免过度热情的表达。
  • 解决方案导向——强调读者做什么,而非限制。
  • 直接且自信——清晰给出建议("We recommend…"),不做不必要的含糊。

句式(Sentence Structure)

  • 优先主动语态:写 "Storybook renders the component",而不是 "The component is rendered by Storybook"。
  • 用短而直接的句子做强调和引入。
  • 解释复杂关系时允许长句,但避免冗长的连缀句(run-ons)。
  • 以目的开头——章节开篇先说清"这是什么、为什么重要",而不是铺陈背景。

指令措辞(Instructions)

  • 分步指令用祈使句:"Run this command"、"Add the following"、"Create a new file"。
  • 可选或替代方案用建议式措辞:"You can also…"、"You might want to…"。
  • 引入代码示例时用陈述句带上下文:"To define the args of a single story, use the args CSF story key:"。

缩写(Contractions)

  • 自然地使用缩写(don't, can't, won't, you'll, it's, we're)——它们强化口语化语气。
  • 在 callout 警告等需要精确表达的严肃/警示语境中避免缩写。

技术术语(Technical Terms)

  • 关键术语首次出现时给出定义,之后可自由使用(例如先写 "Component Story Format (CSF)",之后直接用 "CSF")。
  • 链接到相关概念,而不是在正文中重复解释。
  • 假定读者具备基础 Web 开发知识(HTML、CSS、JavaScript、组件),不过度解释 fundamentals。
  • 所有代码性质的术语使用反引号包裹(对应下文"行内格式"一节)。

措辞的确定性(Hedging)

  • 表达能力用 "can",表达可能结果用 "may" 或 "might"。
  • 表达建议用 "should",表达硬性要求用 "must"。
  • 描述存在例外的常见模式时用 "typically" 或 "generally"。
  • 陈述本身直接时不要加缓冲——写 "This adds…" 而不是 "This should add…"。

选词(Word Choice)

  • 避免弱化语("simply"、"just"、"easily"、"obviously")——对一位读者简单的事,对另一位读者未必如此。
  • "powerful"、"useful"、"great" 要节制使用,且仅在确实成立时使用。
  • 具体优于模糊——写 "renders in under 2 seconds" 而不是 "renders quickly"。

引入示例(Introducing Examples)

  • 先交代 为什么,再展示 怎么做——代码块之前给一句简短的上下文。
  • 常用句式:"Here's how you could…"、"For example, if you…"、"To do X, use Y:"。
  • 当代码块紧随其后时,引导句以冒号结尾。

章节开头(Section Openings)

  • 用 1–2 句总结本章讲什么、为什么重要。
  • 快速进入正题,把铺垫压到最小。
  • 第一句应当能独立成立,本身就是一个定义或价值陈述。

段落长度(Paragraph Length)

  • 段落保持 2–4 句,保证可扫读性。
  • 引导段应为 1–2 句。
  • 较长的解释用标题、列表或 callout 切分。

标题、链接、列表与行内格式

标题(Headings)

  • H1 只能来自 frontmatter 的 title;正文中绝不使用 # Heading[auto]
  • H2/H3 使用句子式大小写(sentence case,仅首字母和专有名词大写)。
  • 不得跳级使用标题(例如 H2 后直接 H4)。[auto]

链接(Links)

  • 内部链接:指向 .mdx 文件的相对路径,例如 text[auto]
  • 外部链接:完整 URL,必须始终包裹在 Markdown 链接语法中(正文中不允许裸 URL)。[auto]

列表(Lists)

  • 无序列表使用 -(不要用 *+)。[oxfmt]

行内格式(Inline Formatting)

  • 文件路径、函数名、变量名、组件名、CLI 命令、配置键、类型名一律用反引号。
  • UI 标签和强调用粗体;斜体节制使用。

自定义 MDX 组件

Callout 组件

  • 必须指定 variant"info""warning");裸写 <Callout> 不允许。
  • 图标使用有标准化映射:
    • 💡——技巧与有用信息(variant="info"
    • 🧪——实验性/预览功能(variant="info"variant="warning"
    • ℹ️——补充背景(variant="info"
    • 📣——公告,需配合 title 属性(variant="info"
    • ♿——可访问性(无障碍)专用(variant="info"
    • ⚠️——必须配 variant="warning",不得配 variant="info"[auto]
    • 图标本身是可选的;若使用,必须遵循上述映射。
  • variant="positive" 是非标准写法,应改用 variant="info"[auto]

其他组件

  • <If renderer={[...]}> / <If notRenderer={[...]}>——按渲染器条件渲染(替代已废弃的 <IfRenderer>)。
  • <CodeSnippets path="..." />——path 必须真实存在于 docs/_snippets/ 目录。[auto]
  • <Video src="..." />——嵌入视频。
  • <YouTubeCallout id="..." title="..." />——YouTube 嵌入。

Frontmatter 规则

  • 值不加引号,除非值包含需要加引号的特殊字符(如 &|:、逗号)。[auto]
  • 需要加引号时使用单引号
  • 仅当 sidebar.titletitle 不同时才写 sidebar.title;两者相同则省略。[auto]

正例:

---
title: Component Story Format (CSF)
sidebar:
  title: CSF
  order: 2
---

反例:

---
title: "ArgTypes"
sidebar:
  title: "ArgTypes"
  order: 2
---

块级 JSX 元素的换行规则

块级 JSX 元素(如 <Callout><details><If>)遵循三条排版规则:

  • 元素前后要各空一行——除非前后紧邻的内容是注释,此时注释与元素之间不空行。
  • 元素内部内容的前后要各空一行——<summary> 是例外:<details> 开始标签与 <summary> 标签之间空行。
  • 内部内容不缩进——除非内容本身应当缩进(如嵌套列表项、代码块内部)。

正例:

<If renderer={['react']}>

Other content.

<Callout variant="info">

This is a callout.

- This is a list item inside the callout
  - This is a nested list item inside the callout

```json
{
  "key": "value"
}
```

</Callout>

More other content.

<details>
<summary>This is a summary</summary>

This is content inside the details element.

</details>

More other content.

</If>
{/* End supported renderers */}

反例(对比可见:元素前后未空行、<Callout> 缺少 variant<summary> 与内容之间未空行、注释前多空了一行等):

<If renderer={['react']}>
Other content.

<Callout>
This is a callout.

- This is a list item inside the callout
- This is a nested list item inside the callout

```json
{
  "key": "value"
}
```

</Callout>
More other content.
<details>

<summary>This is a summary</summary>
This is content inside the details element.

</details>
More other content.

</If>

{/* End supported renderers */}

校验:yarn docs:check[auto]/[oxfmt] 标记的实现

文档末尾声明:标记 [auto] 的条目由 yarn docs:check 检查(实现在 check-docs.ts),标记 [oxfmt] 的条目由 yarn fmt:write 处理。并强调这些是最终阶段的校验工具——应在结构性与编辑性工作完成后再运行,而不是第一步。

命令链路

根目录 package.json 中定义了根级入口:

  • "docs:check": "yarn --cwd scripts docs:check"——转发到 scripts 工作区;
  • scripts/package.json 中,"docs:check": "jiti ./docs/check-docs.ts",即通过 jiti 直接执行 TypeScript 校验脚本;
  • "fmt:check": "oxfmt --check .""fmt:write": "oxfmt ."——由 oxfmt 完成格式归一化(包括列表符号等 [oxfmt] 规则)。

check-docs.ts 的 CLI 入口会以仓库 docs/ 目录为目标运行 runAllChecks,汇总所有检查;发现任何错误即以退出码 1 结束,使检查可接入 CI。

[auto] 标记与代码实现的逐条对应

将文档中各 [auto] 标记与 check-docs.ts 导出的检查函数对照,可以看到规则与实现的一一映射:

规则(来自 storybook-style.md) 检查函数 实现要点
H1 仅来自 frontmatter title,正文禁用 # checkNoBodyH1 仅在 content 上下文中匹配 ^#\s+,代码块内不误报
不跳级使用标题 checkHeadingHierarchy 从 H1(frontmatter 标题)起跟踪 prevLevellevel > prevLevel + 1 即报错,同时识别 <h2> 等 HTML 标签
内部相对链接指向 .mdx 文件 checkRelativeLinks 校验目标文件存在,并进一步校验 #anchor 片段能否在目标文件标题 slug 中找到
外部链接必须包裹在链接语法中(无裸 URL) checkBareUrls 跳过 import/export、引用链接定义、表格行、反引号内、JSX 属性值等场景后,检测正文裸 http(s):// URL
无序列表用 -[oxfmt],非 auto) oxfmtyarn fmt:write)负责归一化
<CodeSnippets path="..." /> 路径必须存在于 docs/_snippets/ checkCodeSnippetPaths docs/_snippets/ 为基准解析 path,缺失即报 Missing snippet
<Callout> 不允许,必须带 variant checkCalloutVariant 收集可能跨多行的完整开标签,缺少 variant= 即报错
variant="positive" 非标准 checkCalloutVariantPositive 匹配 variant="positive" 并提示改用 variant="info"
⚠️ 图标不得配 variant="info" checkCalloutIconMismatch 同行同时出现 <Callout、⚠️ 与 variant="info" 即报错
frontmatter 值不必要的引号 checkFrontmatterQuotes 仅当 title不含 &、`
title 相同的 sidebar.title 应省略 checkRedundantSidebarTitle 解析 frontmatter 中 titlesidebar.title,去引号后相等即报冗余

此外,runAllChecks 还会执行一个文档正文未直接列出的检查 checkDeprecatedIfRenderer:检测到已废弃的 <IfRenderer> 用法即提示改用 <If>——这与"其他组件"一节推荐的 <If renderer={[...]}> 写法互为印证。

值得注意的源码实现细节

从源码结构看,有两处细节让校验更健壮:

  1. 跨版本链接豁免checkRelativeLinks 中定义了 crossVersionRegex = /^(?:\.\.\/)+release-[\w.-]+\//(见 check-docs.ts),指向其他发布分支(如 ../../../release-8-6/docs/...)的跨版本文档链接无法在本地验证,会被直接跳过。
  2. 行上下文感知:多个检查依赖 utils.ts 中的 getLineContextsgetLineContexts),它把每一行标注为 frontmattercodeblockcontent,因此"正文 H1"、"裸 URL"等检查不会误伤代码块与 frontmatter 内的内容;而 slugifyslugify)模拟了 rehype-slug 的标题 slug 行为,支撑锚点片段校验。

实践流程:规则如何落到一次文档编辑上

结合 SKILL.md 定义的工作流,storybook-style.md 的正确使用时机是:

  1. 先完成模式判定(maintenance/improve/rewrite/author/strategy)、主文档类型判定与草稿诊断(这些由 docs-strategy.mddocs-principles.md 指导);
  2. 完成结构性与编辑性修改后,加载 storybook-style.md,按本文"语气与文风 → 标题/链接/列表/行内格式 → 自定义组件 → frontmatter → 块级 JSX 换行"的顺序做风格收尾;
  3. 运行 yarn fmt:writeyarn docs:check,修复报告中的错误后再跑一次确认。注意:不要strategy 模式或没有编辑任何文件时运行校验。

这套"风格规则文件 + 自动校验脚本"的组合,让 Storybook 仓库中 docs/ 下数千个 MDX 页面与 docs/_snippets/ 下的代码片段示例保持统一语感、统一组件用法和可机器验证的链接/格式合规性——写文档(或为 Agent 编写文档审查规则)时,都值得借鉴这一"规则即代码"的做法。

登录后查看全文
热门项目推荐
相关项目推荐