在 Next.js 中开始使用 Markdoc

2025-06-07

在 Next.js 中开始使用 Markdoc

Stripe 正在开源Markdoc,这是一款基于 Markdown 的创作系统,为Stripe 文档网站提供支持。无论是简单的静态网站、创作工具,还是功能齐全的文档网站,Markdoc 都能与您共同成长,无论您的文档规模多大、多复杂,都能打造引人入胜的体验。让我们来看看如何开始使用。本教程的其余部分使用 Next.js 中的create-next-app
实现

安装

要开始使用 Markdoc,首先需要使用以下命令安装它:

npm install @markdoc/markdoc --save
Enter fullscreen mode Exit fullscreen mode

或者

yarn add @markdoc/markdoc –-save
Enter fullscreen mode Exit fullscreen mode

由于此示例应用程序使用 Next.js,因此您还需要安装 Next.js 插件:

npm install @markdoc/next.js --save
Enter fullscreen mode Exit fullscreen mode

最后,将以下行添加到 next.config.js 文件:

const withMarkdoc = require("@markdoc/next.js");
module.exports = withMarkdoc()({
 pageExtensions: ["js", "md", "mdoc"],
});
Enter fullscreen mode Exit fullscreen mode

这些行允许您使用.js.md.mdoc文件。

配置文件中的这些新增功能使您可以使用 JavaScript 或 Markdown 文件格式编写文档。如果您想在 Next.js 以外的其他框架中使用 Markdown 文件,则需要使用插件。

现在您已完成所有设置,让我们来编写一些内容。

使用 Markdoc

首先,找到pages启动 Next.js 应用程序时自动生成的文件夹,然后在其中create-next-app创建一个新文件。index.md

Markdoc 语法是 Markdown 的超集,具体来说是CommonMark 规范,因此,在这个文件中,你可以使用这种语法编写内容。

# Some title
## A subtitle
This is a paragraph with a [link to your awesome website](https://your-awesome-website.com)
Enter fullscreen mode Exit fullscreen mode

Markdoc 具有可扩展性,因此您还可以使用变量、函数以及创建自定义标签。为此,您必须使用 JavaScript 定义内容,并使用Markdoc.transform()Markdoc.renderers.react()来渲染所有内容。
让我们来看看如何做到这一点。

变量

变量在配置对象中定义,然后可以在你的内容中使用。下面是一个完整的代码示例,之后我们会对其进行分解并解释各个部分。

// config.js
export const config = {
 variables: {
   user: {
     name: "Justice Ketanji Brown Jackson",
   },
 },
};
Enter fullscreen mode Exit fullscreen mode
// Page.js
import React from "react";
import Markdoc from "@markdoc/markdoc";
import { config } from "./config.js";

const Page = () => {
 const doc = `
 Hello {% $user.name %}
 `;

 const content= Markdoc.transform(doc, config);

 return <section>{Markdoc.renderers.react(content, React)}</section>;
};

export default Page;
Enter fullscreen mode Exit fullscreen mode

例如,如果您想显示用户的姓名,您可以声明一个这样的配置对象:

 const config = {
   variables: {
     user: {
       name: 'Justice Ketanji Brown Jackson'
     }
   }
 };
Enter fullscreen mode Exit fullscreen mode

在 Markdoc 中,要引用配置中的变量,请在变量名前面添加 $dollarSign。例如,你可以像这样引用用户的名称:

const content = `
Hello {% $user.name %}
`;
Enter fullscreen mode Exit fullscreen mode

不要忘记在变量前面加上 $,否则它将被解释为标签。

然后,您需要传入这两个变量Markdoc.transform()并使用 呈现您的内容Markdoc.renderers.react()

const content= Markdoc.transform(doc, config);

return <section>{Markdoc.renderers.react(content, React)}</section>;
Enter fullscreen mode Exit fullscreen mode

使用变量是一项强大的功能,例如,当你想显示动态数据(例如用户的 API 密钥)时。你可以在Stripe 文档网站上找到此类功能的示例。

自定义样式

Markdoc 引入了注释的概念,允许您设置不同节点的样式,这些节点是 Markdoc 从 Markdown 继承的元素。

例如,您可以使用以下语法添加 ID 和类:

// index.md
# My title {% #custom-id %}
# Another title {% .custom-class-name-here %}
Enter fullscreen mode Exit fullscreen mode

然后您可以在 CSS 中引用这些来应用样式。

// styles.css
#custom-id {
 color: purple;
}
.custom-class-name-here {
 color: darkblue;
}
Enter fullscreen mode Exit fullscreen mode

这将生成以下 HTML:

<h1 id="custom-id">My title </h1>
<h1 class="custom-class-name-here">Another title </h1>
Enter fullscreen mode Exit fullscreen mode

并渲染如下所示的内容:

紫色标题下方为深蓝色标题的屏幕截图

一些与样式相关的属性也可以使用注释来应用:

Function {% width="25%" %}
Example  {% align="right" %}
Enter fullscreen mode Exit fullscreen mode

标签

Markdoc 自带四个标签,你也可以自定义标签。例如,你可以尝试一下if支持条件渲染内容的标签。

const config = {
 variables: {
   tags: {
     featureFlagEnabled: true,
   },
 },
};

const document = `
{% if $tags.featureFlagEnabled %}

Here's some secret content

{% /if %}
`;
Enter fullscreen mode Exit fullscreen mode

您可以通过三个步骤构建自己的标签。让我们来看一个自定义横幅组件的示例。
首先,您需要创建要渲染的 React 组件。小型横幅组件的代码可能如下所示:

// Banner.js
const Banner = ({ type, children }) => {
 return (
   <section className={`banner ${type}`}>
     {children}
     <style jsx>{`
       .alert {
         border: 1px solid red;
       }
     `}</style>
   </section>
 );
};

export default Banner;
Enter fullscreen mode Exit fullscreen mode

该组件将接受一个typeprop 来指示横幅是否应设置为警报、信息、警告横幅等样式。该childrenprop 代表稍后将在 Markdown 文件中该标签内传递的内容。

为了能够将此组件用作 Markdown 文件中的标签,首先在 Next.js 应用程序的根目录下创建一个“markdoc”文件夹,并在其中创建一个“tags.js”文件,其中将包含所有自定义标签。

这个应用程序的架构最终看起来是这样的:

components/
|-- Banner.js
markdoc/
|-- tags.js
pages/
   index.md
Enter fullscreen mode Exit fullscreen mode

在你的自定义标签文件(此处tags.js)中,你需要导入你的 React 组件,并导出一个包含你想要显示的组件的变量。你还需要添加任何你想要使用的属性。在本例中,是横幅广告的类型。

声明属性时,需要指定其数据类型。

// markdoc/tags.js
import Banner from "../components/Banner";

export const banner = {
 Component: Banner,
 attributes: {
   type: {
     type: String,
   },
 },
};
Enter fullscreen mode Exit fullscreen mode

最后一步是在你的 Markdown 内容中使用此自定义标签,如下所示:

{% banner type="alert" %}
This is an alert banner
{% /banner %}
Enter fullscreen mode Exit fullscreen mode

如果您创建不接受任何子标签的自定义标签,则可以将其写为自闭合标签:

{% banner/ %}
Enter fullscreen mode Exit fullscreen mode

语法验证

此外,Markdoc 还允许您验证渲染前生成的抽象语法树 (AST)。如果您考虑Banner上面写的组件,则可以在使用 JavaScript 编写内容时将其用作标签,并在渲染前检查是否存在任何语法错误。

例如,如果横幅标签中没有type必需的属性,您可以实现一些错误处理,以避免渲染不完整内容。
此语法验证只需一行代码即可实现,即使用Markdoc.validate()

 const config = {
   tags: {
     banner,
   },
 };

 const content = `
 {% banner %}
 Example banner with a syntax error
 {% /banner %}
`;

 const ast = Markdoc.parse(content);
 const errors = Markdoc.validate(ast, config);
 // Handle errors
Enter fullscreen mode Exit fullscreen mode

在这种情况下,返回的错误将如下所示。

浏览器开发工具中的错误截图,显示一条消息

功能

你可以通过编写自定义函数来扩展 Markdoc 的使用。例如,如果你想添加一种将内容转换为大写的方法,你需要先在markdoc文件夹中创建一个文件,例如functions.js。在此文件中,添加以下辅助函数:

// markdoc/functions.js

export const uppercase = {
 transform(parameters) {
   const string = parameters[0];
   return typeof string === 'string' ? string.toUpperCase() : string;
 }
};
Enter fullscreen mode Exit fullscreen mode

然后在需要它的组件中导入此函数,并将其传递到您的配置对象中:

import { uppercase } from "../markdoc/functions";

const config = {
 functions: {
   uppercase
 }
};
Enter fullscreen mode Exit fullscreen mode

在标签内的内容中调用它{% %}

const document = `
 {% uppercase("Hello, World") %}
`
Enter fullscreen mode Exit fullscreen mode

最后,调用Markdoc.transform()并使用 React 渲染器来渲染所有内容。

const doc = Markdoc.transform(document, config);
Markdoc.renderers.react(doc, React);
Enter fullscreen mode Exit fullscreen mode

因此,小组件的完整语法如下所示:

// config.js
export const config = {
 functions: { uppercase },
};
Enter fullscreen mode Exit fullscreen mode
// functions.js
export const uppercase = {
   transform(parameters) {
     const string = parameters[0];
     return typeof string === "string" ? string.toUpperCase() : string;
   },
 };
Enter fullscreen mode Exit fullscreen mode
// Page.js
import Markdoc from "@markdoc/markdoc";
import { config } from "./config.js";
import { uppercase } from "./functions.js";

const Page = () => {
 const document = `
 {% uppercase("Hello, World") %}
 `;

 const doc = Markdoc.transform(document, config);

 return <section>{Markdoc.renderers.react(doc, React)}</section>;
};

export default Page;
Enter fullscreen mode Exit fullscreen mode

有一些内置函数可用,例如equals,如果两个变量相等则显示一些内容,在语句not/and/or中用于if执行布尔运算,default如果第一个返回未定义则返回传递的第二个参数,并将debug值序列化为 JSON 以帮助您进行调试。

资源

如果您想了解更多信息,这里有一些实用资源可供参考。如果您感兴趣,我们也欢迎您为代码库做出贡献!我们迫不及待地想看到您使用 Markdoc 构建的成果,欢迎随时告诉我们您的想法!

官方 Markdoc 文档
Markdoc 存储库
Markdoc Next.js 插件存储库
Markdoc 游乐场
Next.js 样板演示

保持联系

此外,您还可以通过以下几种方式了解 Stripe 的最新动态: 📣 在Twitter
上关注我们 💬 加入官方Discord 服务器 📺 订阅我们的YouTube 频道 📧 注册Dev Digest


文章来源:https://dev.to/stripe/getting-started-with-markdoc-in-nextjs-ioj
PREV
使用 Next.js、TypeScript 和 Stripe 实现类型安全支付
NEXT
速度提示:在 Gatsby 中使用 Typefaces.js 本地托管字体