使用 Gatsby 构建 Living Styleguide:基于 react-docgen 与 react-live 的组件活体风格指南实战

发布时间:2026/9/20 22:32:08
使用 Gatsby 构建 Living Styleguide:基于 react-docgen 与 react-live 的组件活体风格指南实战
使用 Gatsby 构建 Living Styleguide基于 react-docgen 与 react-live 的组件活体风格指南实战【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby导读本文以 Gatsby 官方仓库中的 examples/styleguide 示例为骨架深入讲解如何用 Gatsby 搭建一个活体风格指南living styleguide组件文档不再是与代码脱节的静态页面而是直接从源码中的 JSDoc 注释、PropTypes 定义以及 Markdown 示例代码自动生成并且每个示例都可以在浏览器中实时编辑、实时预览。读完本文你将掌握gatsby-transformer-react-docgen提取组件元数据、gatsby-transformer-remark解析 Markdown 示例、gatsby-node.js编程式生成页面以及用react-live实现可交互代码演示的完整链路能够直接复制这套方案到自己的组件库项目中。一、什么是 Living Styleguide为什么用 Gatsby 实现Living styleguide活体风格指南是组件驱动开发中常见的一类文档系统它把组件的使用文档、属性说明和可运行示例与真实组件源码绑定在一起源码更新后文档随之更新示例始终展示真实渲染结果避免文档腐烂过期。该示例在 README 中的定位非常明确——A living styleguide proof-of-concept built using Gatsby并且其灵感来自 react-styleguidist见 examples/styleguide/README.md。选择 Gatsby 实现的核心原因可以归纳为三点数据层统一Gatsby 的 GraphQL 数据层可以把组件元数据来自 react-docgen和 Markdown 文档来自 remark两类异构数据拉到同一条查询里编程式建页通过createPagesAPI 可以为每个组件自动生成独立文档页面无需手写路由构建时静态化风格指南输出为纯静态站点可直接托管到任何静态服务同时示例代码通过react-live在客户端保持可交互。示例目录规模很小却完整覆盖了数据采集 → 页面生成 → 模板渲染 → 交互预览整条流水线是研究 Gatsby 数据流与建页机制的一份极佳参考。二、示例整体结构与数据流先看整个示例的目录结构关键文件examples/styleguide/ ├── gatsby-config.js # 插件与数据源配置 ├── gatsby-node.js # 编程式生成组件页与目录页 ├── package.json # 依赖与脚本 └── src/ ├── components/ │ └── Button/ │ ├── Button.js # 组件源码含 JSDoc 与 PropTypes │ ├── README.md # 组件文档内含 jsx 示例代码块 │ └── index.js # 导出入口 ├── pages/ │ └── index.js # 首页重定向到 /components/ └── templates/ ├── ComponentPage/ # 单个组件文档页模板 │ ├── ComponentPage.js │ └── components/ │ ├── ComponentPreview/ # react-live 实时预览 │ └── Example/ # html-to-react 示例解析 └── TOC/ # 组件目录页模板整个数据流可以概括为四个阶段gatsby-source-filesystem把src/components目录接入 Gatsby 数据层gatsby-transformer-react-docgen从每个组件源码中提取displayName、description、props等元数据生成allComponentMetadata节点gatsby-transformer-remark把同名README.md解析为 HTML生成allMarkdownRemark节点gatsby-node.js的createPages通过 GraphQL 同时查询两类节点按顺序一一对应同一目录下的组件文件与 README为每个组件创建/components/displayName/页面并额外创建/components/目录页页面模板读取pageContext中的数据渲染属性表格并把 Markdown 中的jsx代码块交给react-live变为可编辑、可运行的实时预览。三、数据源与转换插件配置gatsby-config.js 是整个流水线的起点全文如下const path require(path) module.exports { plugins: [ { resolve: gatsby-source-filesystem, options: { path: path.join(__dirname, src/components), name: components, }, }, { resolve: gatsby-transformer-react-docgen, }, { resolve: gatsby-transformer-remark, }, ], }三个插件各司其职gatsby-source-filesystem以src/components为数据源目录name: components只是给该源一个标识。所有组件源码与 README 都会作为 File 节点进入数据层。注意这里使用的是path.join(__dirname, ...)保证相对路径始终解析正确。gatsby-transformer-react-docgen这是实现活体的关键——它借助 react-docgen 分析组件源码中的 JSDoc 注释与propTypes/defaultProps把组件元数据暴露为allComponentMetadata查询。它的实现位于仓库的 packages/gatsby-transformer-react-docgen 包中通过对组件文件的解析输出displayName、description、props含 name、type、description、required等结构化字段可供页面模板直接渲染成文档表格。gatsby-transformer-remark负责把组件目录下的README.md解析成 HTML 节点提供allMarkdownRemark查询。文档中写入的jsx代码块会保留在生成的 HTML 里为后续的示例提取与实时预览提供原料。package.json中与之对应的依赖为gatsby-source-filesystem、gatsby-transformer-react-docgen、gatsby-transformer-remark运行脚本为标准三件套develop、build、startstart等价于npm run develop见 examples/styleguide/package.json。四、组件与文档的活体约定源码注释 README 示例活体的前提是约定每个组件目录下放一个组件文件含 JSDoc 注释与 PropTypes和一个README.md内含jsx代码块示例。以 src/components/Button/Button.js 为例/** * The Button is a foundational trigger component for capturing * and guiding user-interaction. */ const Button ({ backgroundColor, size, ...rest }) ( button className{styles({ backgroundColor, size })} {...rest} / ) Button.propTypes { /** The color to use as the background */ backgroundColor: PropTypes.oneOf(Object.keys(colors)), /** The size of the button */ size: PropTypes.oneOf(Object.keys(sizes)), } Button.defaultProps { backgroundColor: blue, size: md, }组件顶部的块级注释会被 react-docgen 提取为description每个 prop 上的行内注释会变成props[].description。这里backgroundColor的可选值来自colors对象的键blue/orange/greensize来自sizes对象的键sm/md/lgdefaultProps提供默认值。这套注释约定直接决定了风格指南页面上的描述文字与属性表格内容。配套的文档文件 src/components/Button/README.md 则包含多个jsx代码块例如The basic button. jsx ButtonGet Started/Button Colors are configurable. jsx div div Button backgroundColorblueGet Started/Button /div div Button backgroundColorgreenGet Started/Button /div div Button backgroundColororangeGet Started/Button /div /div 这些代码块会被 remark 渲染为pre标签随后由页面模板识别并注入到 react-live 中变成实时编辑器。五、编程式生成页面gatsby-node.js 的建页逻辑gatsby-node.js 是流水线的核心。它使用createPagesAPI内部通过Promise.all并发执行两个 GraphQL 查询graphql( { allComponentMetadata { edges { node { id displayName description { text } props { name type { value raw name } description { text } required } } } } } ), graphql( { allMarkdownRemark( filter: { fileAbsolutePath: { regex: /README.md/ } } ) { edges { node { fileAbsolutePath html } } } } )两个查询的编排逻辑是第一个拿到组件元数据列表第二个拿到所有README.md的 HTML随后按下标一一对应合并——即allComponentMetadata.edges[i]与allMarkdownRemark.edges[i]属于同一组件const allComponents docgenResult.data.allComponentMetadata.edges.map( (edge, i) Object.assign({}, edge.node, { filePath: /components/${edge.node.displayName}/, html: markdownResult.data.allMarkdownRemark.edges[i].node.html, }) )这是本示例中最值得注意的实现细节它假设两个查询返回顺序一致。在真实项目中更稳妥的做法是通过fileAbsolutePath或 id 做显式关联不过作为 proof-of-concept按下标合并已足够清晰。接下来是两步关键操作1. 生成组件导出桶文件.cache/components.js把每个组件的displayName与路径拼成 ES Module 导出语句写入.cache目录供react-live的scope使用const exportFileContents allComponents .reduce((accumulator, { displayName, filePath }) { const absolutePath path.resolve(path.join(src, filePath, displayName)) accumulator.push(export { default as ${displayName} } from ${absolutePath}) return accumulator }, []) .join(\n) \n fs.writeFileSync(path.join(appRootDir, .cache/components.js), exportFileContents)例如 Button 会生成export { default as Button } from .../src/components/Button/Button。因为组件展示名displayName就是目录名所以src/components/displayName/displayName的路径拼接成立。2. 为每个组件创建页面并创建目录页allComponents.forEach(data { const { filePath } data const context Object.assign({}, data, { allComponents }) createPage({ path: filePath, component: componentPageTemplate, context, }) }) createPage({ path: /components/, component: tableOfContentsTemplate, context: { allComponents }, })组件页的path形如/components/Button/模板指向src/templates/ComponentPage/index.js目录页path为/components/模板指向src/templates/TOC/index.js。context里注入了allComponents让每个组件页都能拿到全量组件列表。最后src/pages/index.js 把首页/重定向到/components/class Home extends React.Component { render() { return Redirect from/ to/components/ / } }六、模板层属性表格与示例渲染6.1 组件页模板ComponentPage.js 从pageContext中读取displayName、description、props、html渲染出组件名作为h1description.text作为引言一个Props/Methods表格列包含 Name、Description、Type、RequiredExample html{html} /渲染文档中的示例一个指向目录页的[index]链接。属性表格的渲染直接消费 react-docgen 的结构化输出{props.map(({ name, description, type, required }, index) ( tr key{index} td{name}/td td{description.text}/td td{type.name}/td td{String(Boolean(required))}/td /tr ))}6.2 TOC 目录页TOC.js 很简单遍历pageContext.allComponents用 Gatsby 的Link输出每个组件的目录链接形成Component styleguide清单页。6.3 Example把 Markdown 的 HTML 还原成组件Example.js 承担文档 HTML → React 组件的转换核心工具是html-to-react。它定义了两条处理指令命中pre节点即 Markdown 中的代码块时取出代码内容交给ComponentPreview其余节点走默认处理逻辑。const isCodeExample ({ name } {}) name pre const getHtmlCode children children[0].children[0].data const ExampleNodeProcessor ({ children }) React.createElement(ComponentPreview, { code: getHtmlCode(children) }) const processingInstructions [ { shouldProcessNode: isCodeExample, processNode: ExampleNodeProcessor, }, { shouldProcessNode: isValidNode, processNode: processNodeDefinitions.processDefaultNode, }, ]parser.parseWithInstructions(this.props.html, isValidNode, processingInstructions)逐节点解析最终把pre代码块替换为ComponentPreview code...。6.4 ComponentPreviewreact-live 实时编辑ComponentPreview.js 是活体体验的最后一环基于react-live的四个组件组装LiveProvider scope{components} code{this.props.code} mountStylesheet{false} theme{theme} LiveEditor style{editorStyles} / LiveError / LivePreview / /LiveProvider其中scope来自.cache/components.js的桶文件import * as components from ../../../../../.cache/components这使得示例代码块里可以直接书写Button、Button backgroundColorgreen等 JSX而不需要手动 import——所有组件都已注入到实时运行的作用域中。编辑器还配套了 prism-theme.css 与 editor.css 两个样式文件并内置了一套基于 Prism 主题配色的theme对象保证代码高亮与整体风格统一。LiveError会把示例中的运行时错误展示出来方便调试示例代码本身。七、运行与验证在examples/styleguide目录下运行npm install npm run develop打开本地开发服务器后访问/会自动重定向到/components/看到组件目录页点击Button进入/components/Button/页面包含组件描述、Props 表格以及多个可直接编辑运行的示例修改示例代码例如把ButtonGet Started/Button改成Button sizelgLarge/Button右侧LivePreview会立即重渲染。生产构建则执行npm run build此时 Gatsby 会完成所有 GraphQL 查询与页面生成输出静态站点所有组件文档页与示例预览均被预渲染。八、从示例到自有组件库落地要点把该示例移植到自己的组件库时需要注意以下几点均为从该示例实现中推断的经验目录即组件示例假设一个组件目录 一个组件文件 一个 README且displayName与目录名一致。多文件组件或目录名与导出名不一致时需要调整.cache/components.js的生成逻辑。查询顺序依赖示例按下标合并 docgen 与 remark 两个查询结果依赖两者的返回顺序一致。数据源更复杂时建议改用fileAbsolutePath等字段做显式匹配避免错位。作用域注入实时示例依赖把所有组件打包进.cache/components.js并注入LiveProvider的scope组件数量大时需关注该文件体积可考虑按组件页按需注入。样式方案解耦示例的 Button 使用 glamor 编写样式见 Button.js 中的css()调用但风格指南本身与具体 CSS-in-JS 方案无关react-live只负责执行示例 JSX因此可以无缝替换为任意组件库样式方案。文档约定jsx代码块是示例的唯一入口文档编写者只需遵守README 里写jsx代码块这一约定即可自动获得可交互示例。九、总结examples/styleguide用极少的代码量示范了一条完整的源码即文档流水线react-docgen 从源码注释提取组件元数据、remark 把 Markdown 示例转成 HTML、createPages在构建期编程式生成组件页与目录页、html-to-react把代码块还原为组件、react-live提供可编辑的实时预览。这套模式把组件文档从静态快照升级为与源码同源、可交互运行的活体文档对于维护组件库、设计系统或内部 UI 基建的团队来说是一份可以直接借鉴的高质量参考实现。【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考