Storybook Docs for Ember:为 Ember 组件自动生成分类文档、Props 表格与 MDX 长文文档
本篇技术指南基于 Storybook 官方文档 Storybook Docs for Ember,系统讲解如何在 Ember 项目中接入 @storybook/addon-docs,并覆盖文档中全部四个实战环节:安装与 main.js 注册、DocsPage 自动生成文档、基于 ember-cli-storybook 的 Props 表格(docgen JSON 注入链路)以及 MDX 长文文档与 IFrame 高度配置。结合仓库源码可以看到,Ember 的 docgen JSON 通过 setJSONDoc 挂载到全局变量,再由 Ember 渲染层的 preview 配置消费;读完本篇你将掌握一套在 Ember 项目中完整落地 Storybook Docs 的可复制方案。
一、Storybook Docs 在 Ember 中的能力范围
Storybook Docs 是 Storybook 的文档 Addon,它能把 Storybook 中的 stories 转换成结构化的组件文档。针对 Ember,官方文档明确支持两类能力:
- DocsPage(自动生成的文档页):每个 story 在 Storybook UI 的
Docs标签页中获得自动生成的文档; - MDX(长文文档):用 Markdown 描述组件,并内嵌 stories、Props 表格等文档组件。
其中 DocsPage 属于"装上即得"的基础能力,而 Props 表格需要额外打通 docgen 数据链路(后文详述)。通用概念可参考 Docs 总览文档、DocsPage 参考 与 MDX 参考。
说明:原文档顶部注明该页描述的是 Storybook 5.3.0 引入的新版配置方式;如需从旧格式迁移,可参考仓库根目录的 MIGRATION.md。
二、安装:注册 @storybook/addon-docs
2.1 添加依赖
首先安装 Addon 包,并确保项目中所有 @storybook/* 包的版本保持一致:
yarn add -D @storybook/addon-docs
从当前仓库的 code/addons/docs/package.json 可以看到,@storybook/addon-docs 的 storybook 元信息中声明了 "displayName": "Docs",且 unsupportedFrameworks 仅排除了 react-native——Ember 属于其支持的框架范围。
2.2 在 .storybook/main.js 中注册
将 Addon 加入 addons 数组:
export default {
addons: ['@storybook/addon-docs'],
};
三、DocsPage:自动生成的组件文档页
完成上面的安装后,所有 story 都会自动获得基础版 DocsPage 文档,无需额外代码即可在 Storybook UI 的 Docs 标签页中查看。DocsPage 会自动聚合该 story 的描述、Controls、故事画布等区块,是 Ember 项目落地组件文档的最低成本路径。
四、Props 表格:打通 docgen JSON 数据链路
要为组件生成 Props 表格(ArgsTable),比基础 DocsPage 多几步配置。核心思路是:用 ember-cli 构建过程生成一份 docgen JSON,再把它注入 preview 运行时。
4.1 启用 ember-cli-storybook 的文档集成
Docs for Ember 依赖 @storybook/ember-cli-storybook 这个 ember Addon 从组件源文件中提取文档注释。如果项目已用 Storybook 跑 Ember,该 Addon 通常已安装,只需在 ember-cli-build.js 中打开开关:
let app = new EmberApp(defaults, {
'ember-cli-storybook': {
enableAddonDocsIntegration: true,
},
});
4.2 构建产物:/storybook-docgen/index.json
开启后,运行 ember-cli 服务会在 /storybook-docgen/index.json 生成分类 JSON 文档文件。由于生成逻辑挂在 ember-cli 构建流程上,每次保存组件文件都会重新生成该文件,因此文档与源码注释始终保持同步。组件文档注释的写法(如 @class、参数说明等 yuidoc 风格标签)可参照 ember-cli-addon-docs-yuidoc 提供的文档示例。
4.3 用 setJSONDoc 把 JSON 注入 preview
在 .storybook/preview.js 中加载生成的 JSON 文件:
import { setJSONDoc } from '@storybook/addon-docs/ember';
import docJson from '../dist/storybook-docgen/index.json';
setJSONDoc(docJson);
从源码看这条链路非常简洁,且能解释"为什么叫 set":
- code/addons/docs/src/ember/index.ts 中,
setJSONDoc的实现只有一行——把传入的 JSON 挂到全局变量:globalThis.__EMBER_GENERATED_DOC_JSON__ = jsondoc; - Ember 渲染层在 code/frameworks/ember/src/client/preview/jsondoc.ts 中通过
return global.__EMBER_GENERATED_DOC_JSON__;读回该值,用于在运行时按组件名查表渲染 Props 表格; - 对应的类型声明见 code/frameworks/ember/src/types.ts(
var __EMBER_GENERATED_DOC_JSON__: any;)。
也就是说,setJSONDoc 是 preview 构建期写入、渲染期读取的一个全局桥梁,这也是为什么 preview.js 必须在预览构建中被执行、且 import 的是构建后产物路径(../dist/storybook-docgen/index.json)。
4.4 在 story 元数据中填写 component 字段
最后一步,在 story 元数据中填写 component 字段,其值必须是字符串,且要与源码注释中使用的 @class 名称一致:
export default {
title: 'App Component',
component: 'AppComponent',
};
这个字符串就是 docgen JSON 中的组件索引键:Docs 按 component 名称从 __EMBER_GENERATED_DOC_JSON__ 中查找对应条目并渲染表格,名称不匹配时表格会为空。
五、MDX:以 Markdown 写长文文档并内嵌文档组件
MDX 是用 Markdown 描述组件文档、并内嵌 story 与 Props 表格等文档组件的方式。在 Ember 中使用需注意以下三点。
5.1 补充 react 依赖
Docs Addon 存在对 react 的 peer 依赖(MDX 文档组件在渲染层使用 React 运行时)。若要写 MDX 文档,可能需要额外添加:
yarn add -D react
这一点与仓库事实相符:code/addons/docs/package.json 中 @storybook/addon-docs 声明了 react / react-dom 的依赖区间(^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0),peerDependencies 中也包含 @types/react(可选)。
5.2 让 main.js 的 stories 匹配到 MDX 文件
更新 .storybook/main.js,确保 stories 的 glob 能收集到 MDX 文件:
export default {
stories: ['../src/stories/**/*.stories.@(js|mdx)'],
};
5.3 一个完整的 Ember MDX 文档示例
import { Meta, Story, ArgsTable } from '@storybook/addon-docs';
import { hbs } from 'ember-cli-htmlbars';
<Meta title='App Component' component='AppComponent' />
# App Component
Some **markdown** description, or whatever you want.
<Story name='basic' height='400px'>{{
template: hbs`<AppComponent @title={{title}} />`,
context: { title: "Title" },
}}</Story>
## ArgsTable
<ArgsTable of='AppComponent' />
两个来自原文档的实战注意事项:
component需要声明两次:<Meta>上一次、组件名又一次。原文档指出这是已知冗余,等待后续版本简化(对应 Storybook 侧的 issue #8673),在落地时按现状写即可,不要试图省略其中一处。Props文档块依赖 docgen 配置:要使用ArgsTable/Props区块,必须先完成第四节的全部 docgen 链路(enableAddonDocsIntegration+setJSONDoc+component字段),否则表格无法渲染。
六、IFrame 高度:全局、单 story 与 MDX 三级配置
Storybook Docs 在 Ember 中把 story 渲染在 iframe 内,默认高度为 60px。可在三个层面调整:
6.1 全局默认(.storybook/preview.js)
export const parameters = { docs: { story: { iframeHeight: '400px' } } };
6.2 DocsPage:单 story 局部覆盖
在 story 上直接设置 parameters:
export const basic = () => ...
basic.parameters = {
docs: { story: { iframeHeight: '400px' } }
}
6.3 MDX:作为 Story 元素属性
<Story name='basic' height='400px'>{...}</Story>
6.4 源码中的取值优先级
从 code/addons/docs/src/blocks/blocks/Story.tsx 的实现可以看到,故事区块的高度解析存在一条明确的回退链:
props.height ?? storyParameters.height ?? storyParameters.iframeHeight ?? '100px'
即 MDX 的 height 属性 > story 参数中的 height > story 参数中的 iframeHeight > 兜底值,这与上面临"MDX 属性、单 story 参数、preview 全局参数"三级配置的描述一一对应:外层(更具体)的声明会覆盖全局默认。此外,仓库中 Ember 渲染层的 preview 配置 code/frameworks/ember/src/client/preview/config.ts 也内置了 story: { iframeHeight: '80px' } 的默认值,作为渲染端兜底。
6.5 仓库内的真实用法
仓库自带的 Ember 测试 Storybook 中就有实际用例:test-storybooks/ember-cli/stories/welcome-banner.stories.js 中通过 docs: { story: { iframeHeight: '200px' } } 调整了 story 的 iframe 高度,可作为参照实现。
七、相关文档与延伸阅读
原文档"More resources"部分列出的仓库内参考文档,转换为本仓库的全局路径如下:
结合本仓库源码还可以进一步深入:@storybook/addon-docs 的文档区块组件位于 code/addons/docs/src/blocks/(ArgsTable、Story、Source、Controls 等),Ember 渲染端实现位于 code/frameworks/ember/(含 src/client/preview/jsondoc.ts 的 docgen JSON 消费逻辑),可用于验证上文中每一处配置行为。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00