在 Next.js 中开始使用 Markdoc
Stripe 正在开源Markdoc,这是一款基于 Markdown 的创作系统,为Stripe 文档网站提供支持。无论是简单的静态网站、创作工具,还是功能齐全的文档网站,Markdoc 都能与您共同成长,无论您的文档规模多大、多复杂,都能打造引人入胜的体验。让我们来看看如何开始使用。本教程的其余部分使用 Next.js 中的create-next-app
实现。
安装
要开始使用 Markdoc,首先需要使用以下命令安装它:
npm install @markdoc/markdoc --save
或者
yarn add @markdoc/markdoc –-save
由于此示例应用程序使用 Next.js,因此您还需要安装 Next.js 插件:
npm install @markdoc/next.js --save
最后,将以下行添加到 next.config.js 文件:
const withMarkdoc = require("@markdoc/next.js");
module.exports = withMarkdoc()({
pageExtensions: ["js", "md", "mdoc"],
});
这些行允许您使用.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)
Markdoc 具有可扩展性,因此您还可以使用变量、函数以及创建自定义标签。为此,您必须使用 JavaScript 定义内容,并使用Markdoc.transform()
和Markdoc.renderers.react()
来渲染所有内容。
让我们来看看如何做到这一点。
变量
变量在配置对象中定义,然后可以在你的内容中使用。下面是一个完整的代码示例,之后我们会对其进行分解并解释各个部分。
// config.js
export const config = {
variables: {
user: {
name: "Justice Ketanji Brown Jackson",
},
},
};
// 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;
例如,如果您想显示用户的姓名,您可以声明一个这样的配置对象:
const config = {
variables: {
user: {
name: 'Justice Ketanji Brown Jackson'
}
}
};
在 Markdoc 中,要引用配置中的变量,请在变量名前面添加 $dollarSign。例如,你可以像这样引用用户的名称:
const content = `
Hello {% $user.name %}
`;
不要忘记在变量前面加上 $,否则它将被解释为标签。
然后,您需要传入这两个变量Markdoc.transform()
并使用 呈现您的内容Markdoc.renderers.react()
。
const content= Markdoc.transform(doc, config);
return <section>{Markdoc.renderers.react(content, React)}</section>;
使用变量是一项强大的功能,例如,当你想显示动态数据(例如用户的 API 密钥)时。你可以在Stripe 文档网站上找到此类功能的示例。
自定义样式
Markdoc 引入了注释的概念,允许您设置不同节点的样式,这些节点是 Markdoc 从 Markdown 继承的元素。
例如,您可以使用以下语法添加 ID 和类:
// index.md
# My title {% #custom-id %}
# Another title {% .custom-class-name-here %}
然后您可以在 CSS 中引用这些来应用样式。
// styles.css
#custom-id {
color: purple;
}
.custom-class-name-here {
color: darkblue;
}
这将生成以下 HTML:
<h1 id="custom-id">My title </h1>
<h1 class="custom-class-name-here">Another title </h1>
并渲染如下所示的内容:
一些与样式相关的属性也可以使用注释来应用:
Function {% width="25%" %}
Example {% align="right" %}
标签
Markdoc 自带四个标签,你也可以自定义标签。例如,你可以尝试一下if
支持条件渲染内容的标签。
const config = {
variables: {
tags: {
featureFlagEnabled: true,
},
},
};
const document = `
{% if $tags.featureFlagEnabled %}
Here's some secret content
{% /if %}
`;
您可以通过三个步骤构建自己的标签。让我们来看一个自定义横幅组件的示例。
首先,您需要创建要渲染的 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;
该组件将接受一个type
prop 来指示横幅是否应设置为警报、信息、警告横幅等样式。该children
prop 代表稍后将在 Markdown 文件中该标签内传递的内容。
为了能够将此组件用作 Markdown 文件中的标签,首先在 Next.js 应用程序的根目录下创建一个“markdoc”文件夹,并在其中创建一个“tags.js”文件,其中将包含所有自定义标签。
这个应用程序的架构最终看起来是这样的:
components/
|-- Banner.js
markdoc/
|-- tags.js
pages/
index.md
在你的自定义标签文件(此处tags.js
)中,你需要导入你的 React 组件,并导出一个包含你想要显示的组件的变量。你还需要添加任何你想要使用的属性。在本例中,是横幅广告的类型。
声明属性时,需要指定其数据类型。
// markdoc/tags.js
import Banner from "../components/Banner";
export const banner = {
Component: Banner,
attributes: {
type: {
type: String,
},
},
};
最后一步是在你的 Markdown 内容中使用此自定义标签,如下所示:
{% banner type="alert" %}
This is an alert banner
{% /banner %}
如果您创建不接受任何子标签的自定义标签,则可以将其写为自闭合标签:
{% banner/ %}
语法验证
此外,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
在这种情况下,返回的错误将如下所示。
功能
你可以通过编写自定义函数来扩展 Markdoc 的使用。例如,如果你想添加一种将内容转换为大写的方法,你需要先在markdoc
文件夹中创建一个文件,例如functions.js
。在此文件中,添加以下辅助函数:
// markdoc/functions.js
export const uppercase = {
transform(parameters) {
const string = parameters[0];
return typeof string === 'string' ? string.toUpperCase() : string;
}
};
然后在需要它的组件中导入此函数,并将其传递到您的配置对象中:
import { uppercase } from "../markdoc/functions";
const config = {
functions: {
uppercase
}
};
在标签内的内容中调用它{% %}
:
const document = `
{% uppercase("Hello, World") %}
`
最后,调用Markdoc.transform()
并使用 React 渲染器来渲染所有内容。
const doc = Markdoc.transform(document, config);
Markdoc.renderers.react(doc, React);
因此,小组件的完整语法如下所示:
// config.js
export const config = {
functions: { uppercase },
};
// functions.js
export const uppercase = {
transform(parameters) {
const string = parameters[0];
return typeof string === "string" ? string.toUpperCase() : string;
},
};
// 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;
有一些内置函数可用,例如equals
,如果两个变量相等则显示一些内容,在语句not/and/or
中用于if
执行布尔运算,default
如果第一个返回未定义则返回传递的第二个参数,并将debug
值序列化为 JSON 以帮助您进行调试。
资源
如果您想了解更多信息,这里有一些实用资源可供参考。如果您感兴趣,我们也欢迎您为代码库做出贡献!我们迫不及待地想看到您使用 Markdoc 构建的成果,欢迎随时告诉我们您的想法!
官方 Markdoc 文档
Markdoc 存储库
Markdoc Next.js 插件存储库
Markdoc 游乐场
Next.js 样板演示
保持联系
此外,您还可以通过以下几种方式了解 Stripe 的最新动态: 📣 在Twitter
上关注我们 💬 加入官方Discord 服务器 📺 订阅我们的YouTube 频道 📧 注册Dev Digest