可复用片段
创建带有变量的可复用内容片段,在文档页面间保持一致性并减少 MDX 文件中的重复内容。
软件开发的核心原则之一是 DRY(Don’t Repeat Yourself,避免重复),这同样适用于文档。如果你发现在多个位置重复相同的内容,可以为该内容创建一个自定义片段。片段包含的内容可以导入到其他文件中复用,你可以控制片段在页面上的具体展示位置。如果之后需要更新内容,只需编辑片段本身,而不必修改所有使用该片段的文件。
Web 编辑器目前不支持片段。若要使用片段,请通过 CLI 在本地编辑 MDX 文件,或将片段导入直接推送到你的仓库。
片段是被导入到其他文件中的任意 .mdx、.md、.js 或 .jsx 文件。你可以将片段文件放在项目中的任意位置。
当你在另一个文件中导入片段时,该片段只会在你导入它的地方出现,并不会渲染为独立页面。/snippets/ 文件夹中的任何文件始终被视为片段,即使它没有被导入到其他文件中。
创建一个文件,写入你想要复用的内容。片段可以包含 Mintlify 支持的所有内容类型,也可以导入其他片段。请参阅嵌套片段以了解在嵌套时应在何处声明导入。
使用绝对路径或相对路径将代码片段导入到页面中。
- 绝对导入:从项目根目录导入时,以
/开头。 - 相对导入:使用
./或../从当前文件所在位置相对导入代码片段。
将导入的代码片段渲染为 JSX 标签时,使用的名称应以大写字母开头,例如 MySnippet。MDX 会将 <mySnippet /> 之类以小写字母开头的标签视为 HTML 元素或自定义元素的字面名称,而不是对导入代码片段的引用。按照惯例,代码片段名称应使用 PascalCase。
相对导入支持 IDE 导航。在编辑器中按住 Cmd 并单击代码片段名称即可直接跳转到该代码片段的定义。
-
在代码片段文件中添加需要复用的内容。
shared/my-snippet.mdx Hello world! This is my content I want to reuse across pages. -
使用绝对路径或相对路径,将该片段导入目标文件中。
--- title: "An example page" description: "This is an example page that imports a snippet." --- import MySnippet from "/shared/my-snippet.mdx"; The snippet content displays beneath this sentence. <MySnippet />
片段可以导入其他片段。请在使用嵌套片段的父级片段文件中声明该导入,而不是在导入父级片段的页面中声明。
每个文件解析各自的导入。在页面中声明的导入不会应用于该页面导入的片段。依赖页面级导入的嵌套片段可能会渲染为空内容。
-
在父级片段文件中导入嵌套片段。请在需要使用嵌套片段的位置声明导入。
shared/parent-snippet.mdx import ChildSnippet from "/shared/child-snippet.mdx"; 此片段会在这句话下方渲染另一个片段。 <ChildSnippet /> -
在目标文件中只导入父级片段。你无需导入嵌套片段。
destination-file.mdx --- title: "An example page" description: "This is an example page that imports a snippet containing a nested snippet." --- import ParentSnippet from "/shared/parent-snippet.mdx"; <ParentSnippet />
在页面中引用代码片段(snippet)中的变量。
-
从代码片段(snippet)文件中导出变量。
shared/custom-variables.mdx export const myName = "Ronan"; export const myObject = { fruit: "strawberries" }; ; -
从目标文件中导入该代码片段并使用该变量。
destination-file.mdx --- title: "示例页面" description: "这是一个导入带有变量的代码片段的示例页面。" --- import { myName, myObject } from "/shared/custom-variables.mdx"; 你好,我的名字是 {myName},我喜欢 {myObject.fruit}。
浏览器会对 MDX 表达式求值,例如像 {myName} 这样的导入变量和像 {1 + 1} 这样的内联表达式。它们的值不会出现在页面的初始 HTML 或离线导出中,因此不运行 JavaScript 的爬虫、LLM 和其他工具只能看到它们周围的文本。如果这些值必须在上述场景中可见,请以纯文本形式书写。
在导入代码片段时,可使用变量向其传递数据。
-
在代码片段中添加变量,并在导入时通过属性传入值。在此示例中,变量是
{word}。shared/my-snippet.mdx 我今天的关键词是 {word}。 -
使用该变量将代码片段导入目标文件。传入的属性会替换代码片段定义中的变量。
destination-file.mdx --- title: "示例页面" description: "这是一个导入带有变量的代码片段的示例页面。" --- import MySnippet from "/shared/my-snippet.mdx"; <MySnippet word="bananas" />
变量也可以在围栏代码块内插值。这对于包含安装命令或其他因包名、版本或环境而异的代码示例的代码片段非常有用。
export const InstallSnippet = ({ packageName }) => <></>;
安装包:
```bash
npm install {packageName}
```import InstallSnippet from "/shared/install-snippet.mdx";
<InstallSnippet packageName="@myorg/sdk" />-
创建一个包含 JSX 组件的代码片段。有关更多信息,请参见 React 组件。
components/my-jsx-snippet.jsx export const MyJSXSnippet = () => { return ( <div> <h1>你好,世界!</h1> </div> ); };
创建 JSX 代码片段时,请使用箭头函数语法(=>),而不要使用函数声明。在代码片段中不支持使用 function 关键字。
-
导入该代码片段。
destination-file.mdx --- title: "示例页面" description: "这是一个导入包含 React 组件的代码片段的示例页面。" --- import { MyJSXSnippet } from "/components/my-jsx-snippet.jsx"; <MyJSXSnippet />
将 SDK 组件列表、支持矩阵或套餐集合等数据集中存放在一个代码片段中,并在多个页面上渲染。当你修改这些数据时,基于它构建的每个表格、列表或卡片都会随之更新。
将数据以纯 JSON 对象的形式存储在带有命名导出的 .js 代码片段中。然后编写一个 .jsx 代码片段,将数据转换为标记内容。
代码片段必须是 .mdx、.md、.js 或 .jsx 文件。你无法直接导入 .json 或 .yaml 文件。请将数据存放在 .js 代码片段中,或者从你的 JSON 或 YAML 源文件生成一个。
从代码片段中导出数据
export const sdkComponents = [
{ "name": "CardForm", "version": "2.4.0", "status": "Stable", "docs": "/components/card-form" },
{ "name": "PinReveal", "version": "1.9.2", "status": "Beta", "docs": "/components/pin-reveal" }
];创建一个用于渲染数据的代码片段
使用 map() 遍历数据,并返回 HTML 元素或 Mintlify 组件。
export const ComponentsTable = ({ rows }) => (
<table>
<thead>
<tr>
<th>组件</th>
<th>版本</th>
<th>状态</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.name}>
<td><a href={row.docs}>{row.name}</a></td>
<td><code>{row.version}</code></td>
<td>{row.status}</td>
</tr>
))}
</tbody>
</table>
);导入两个代码片段并以属性方式传入数据
在页面中筛选或排序数据,即可在不重复数据的情况下展示其子集。
---
title: "SDK 组件"
description: "SDK 中的每个组件,及其当前版本与状态。"
---
import { sdkComponents } from "/snippets/sdk-components.js";
import { ComponentsTable } from "/snippets/components-table.jsx";
该 SDK 包含 {sdkComponents.length} 个组件。
<ComponentsTable rows={sdkComponents} />
## 稳定组件
<ComponentsTable rows={sdkComponents.filter((row) => row.status === "Stable")} />如果你将数据存储在 JSON 或 YAML 文件中,可从该源数据生成代码片段。使用脚本生成数据代码片段,为每个条目生成一个页面,并创建对应的导航分组。每当源文件发生变更时,在 CI 中运行该脚本,并将生成结果提交。
编写生成脚本
该脚本读取 sdk-components.yaml,写入上一个示例中的代码片段,为每个组件创建一个页面,并替换 docs.json 中名为 “Components” 的导航分组下的页面。
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { parse } from "yaml";
const components = parse(readFileSync("sdk-components.yaml", "utf8"));
const slug = (name) => name.toLowerCase().replace(/[^a-z0-9]+/g, "-");
// One snippet with all the data, for tables and lists anywhere in the docs.
writeFileSync("snippets/sdk-components.js", `export const sdkComponents = ${JSON.stringify(components, null, 2)};\n`);
// One page per component.
mkdirSync("components", { recursive: true });
for (const component of components) {
const page = `---
title: ${JSON.stringify(component.name)}
description: ${JSON.stringify(component.description)}
---
{/* Generated from sdk-components.yaml by scripts/generate-docs.mjs. Edit the YAML, not this file. */}
| Field | Value |
| --- | --- |
| Version | \`${component.version}\` |
| Status | ${component.status} |
`;
writeFileSync(`components/${slug(component.name)}.mdx`, page);
}
// Keep the navigation in sync: replace the pages of the group named "Components", wherever it sits.
const docs = JSON.parse(readFileSync("docs.json", "utf8"));
const findGroup = (node) => (Array.isArray(node) ? node.map(findGroup).find(Boolean) : node && typeof node === "object" ? (node.group === "Components" ? node : findGroup(Object.values(node))) : undefined);
const group = findGroup(docs.navigation);
if (group) {
group.pages = components.map((component) => `components/${slug(component.name)}`);
writeFileSync("docs.json", `${JSON.stringify(docs, null, 2)}\n`);
}对于 JSON 源文件,将 parse() 替换为 JSON.parse(),并省略 yaml 依赖。多次运行该脚本会生成完全相同的文件,因此可以放心地在每次推送时运行。
在 GitHub Action 中运行
当源文件或脚本发生变更时,该工作流会触发运行,然后将脚本生成的任何内容提交。默认的 GITHUB_TOKEN 在推送时不会触发其他工作流,因此该任务不会形成循环。Mintlify 会像处理其他 commit 一样部署该次推送。
name: Generate docs from YAML
on:
push:
paths:
- sdk-components.yaml
- scripts/generate-docs.mjs
workflow_dispatch:
permissions:
contents: write
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install yaml
- run: node scripts/generate-docs.mjs
- name: Commit generated files
run: |
git add -A
if git diff --cached --quiet; then
echo "Nothing changed."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git commit -m "docs: regenerate from sdk-components.yaml"
git push如果你将源文件存储在另一个仓库中,请改在该仓库中运行工作流。使用一个能够向文档仓库推送的令牌检出文档仓库,运行脚本并提交。