在Next.js渲染Markdown竟然如此简单

2023-12-19 21:02:16

Next.js 作为一款开箱即用的 React 框架,因其优秀的服务器渲染能力和灵活的配置方式,已经吸引了大量的开发者。同时,Markdown 作为一种轻量级的标记语言,以其简洁的语法和强大的功能,已经成为了写作的首选工具。那么,如何在 Next.js 中渲染 Markdown 呢?这可能会让一些开发者感到困惑,但其实这个过程比你想象的要简单得多。在这篇文章中,我将会详细地解释如何在 Next.js 中渲染 Markdown,希望能为那些正在寻找解决方案的开发者提供一些参考和帮助。

什么是 Markdown

Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换为有效的 HTML 文档。它可以用来制作说明文档、网页内容、电子书等。它的设计目标是易读性和易写性,以及尽可能的兼容性。Markdown 的语法由一些简单的符号组成,如井号(#)、星号(*)和破折号(-)。

MDX 则是一种扩展 Markdown 的语言,它允许你在 Markdown 文档中直接编写 JSX,并通过组件来导入和使用。这意味着你可以在 Markdown 中使用 React 组件,或者在 JSX 中使用 Markdown。MDX 非常适合用于创建复杂的交互式文档、幻灯片、博客等。

开始

项目基于 create-next-app 搭建,安装了 TailwindCSS。

PS E:\> pnpm create create-next-app@latest
√ What is your project named? ... next-mdx
√ Would you like to use TypeScript? ... Yes
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... No

安装渲染 MDX 所需要的包:

pnpm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx

在根目录创建一个 mdx-components.tsx 文件:

import type { MDXComponents } from 'mdx/types'
 
export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
  }
}

这里解构的 components 可以是 HTML 标签,也可以是我们的 jsx/tsx 文件,比如我新建 components/button.tsx 文件:

const Button = ({ children }: { children: React.ReactNode }) => {
  return (
    <button className="test-xs px-4 py-2 bg-zinc-950 text-white rounded-md">
      {children}
    </button>
  );
};

export default Button;

修改 mdx-components.tsx 文件:

import type { MDXComponents } from "mdx/types";
import Button from "@/components/button";

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
    h1: (props) => <h1 className="text-3xl font-bold">{props.children}</h1>,
    Button,
  };
}

上面代码给 h1 标签添加了两个 class:text-3xl font-bold 设置一级标题字体大小与加粗,并且导入了 Button 组件。

修改根目录中的 next.config.js 文件:

const withMDX = require("@next/mdx")();

/** @type {import('next').NextConfig} */
const nextConfig = {
  pageExtensions: ["js", "jsx", "mdx", "ts", "tsx"],
};

module.exports = withMDX(nextConfig);

然后就可以在项目中愉快的渲染 .mdx 文件了。

新建 src/mdx/page.mdx

export const metadata = {
  title: 'mdx'
}

# mdx-remote

- 1
- 2
- 3

<Button>button</Button>

由于我们前面在 mdx-components.tsx 中添加了 Button 组件,于是可以直接在 mdx 中使用。

export const metadata 用于设置页面元数据,这些元数据对于SEO(搜索引擎优化)非常重要。

访问 /mdx 页面,你将会看到以下页面,并且网页的标题也被修改为了 mdx

2023-12-19_14-44-34.png

Remote MDX

如果 Markdown 或 MDX 文件或内容位于其他位置,比如本地文件夹、远程 URL、数据库等,则需要在服务器上动态获取它。

有两个常用的库,一个是 next-mdx-remote 一个是 contentlayer,接下来我将演示如何在 Next.js 中使用 next-mdx-remote来渲染 mdx 文件。

安装 next-mdx-remote

pnpm install next-mdx-remote

新建 components/mdx-components.tsx 文件:

"use client";

import { MDXRemote, MDXRemoteProps } from "next-mdx-remote";
import Button from "./button";

export default function Mdx(props: MDXRemoteProps) {
  return (
    <MDXRemote
      {...props}
      components={{
        h1: (props) => {
          return <h1 className="text-3xl font-bold">{props.children}</h1>;
        },
        Button,
      }}
    />
  );
}

创建文件 app/[slug]/page.tsx 文件:

import { MDXRemote } from "next-mdx-remote";
import { serialize } from "next-mdx-remote/serialize";
import fs from "fs";
import Mdx from "@/components/mdx-components";
import { notFound } from "next/navigation";

interface PostProps {
  params: {
    slug: string;
  };
}

const PostsPage = async ({ params: { slug } }: PostProps) => {
  try {
    const postFile = fs.readFileSync(`posts/${slug}.mdx`);

    const source = await serialize(postFile, { parseFrontmatter: true });
    return (
      <div>
        <Mdx {...source} />
      </div>
    );
  } catch {
    notFound();
  }
};

export default PostsPage;

async function getPostBySlug(slug: string) {
  const postFile = fs.readFileSync(`posts/${slug}.mdx`);

  const source = await serialize(postFile, { parseFrontmatter: true });

  return source;
}

export async function generateMetadata({ params }: PostProps) {
  const { frontmatter } = await getPostBySlug(params.slug);
  return frontmatter;
}
  1. 读取指定的MDX文件:通过网页的 URL 参数,使用 Node.js 的文件系统模块 fs 来读取 MDX 文件。
  2. 解析 MDX 文件:使用 serialize 函数将读取到的 MDX 文件内容进行解析和转化,可以将 MDX 格式的文件转化为可以在 React 中直接使用的 JSX 格式。
  3. 处理错误:如果在读取或解析文件的过程中出现错误(例如文件不存在),则会调用 notFound 函数进入 404 页面。
  4. 渲染 MDX 内容:使用自定义的 Mdx 组件将解析后的 MDX 内容进行渲染,展示在页面上。
  5. 提取MDX文件的元数据:generateMetadata 函数会提取 MDX 文件的 frontmatter 元数据,这些元数据通常用于存储一些关于文档的信息,如作者、创建日期等。
  6. generateMetadata函数导出,便可以在页面中渲染元数据。

新建 posts/mdx-remote.mdx 文件:

---
title: mdx-remote
description: description
data: 2023-12-19
authro: 远小帅
---

# mdx-remote

- 1
- 2
- 3

<Button>button</Button>

在文件开头我使用了三个破折号包括了一段数据,这被称为 Frontmatter,采用 YAML 格式,用来描述文档的元数据。

此时访问 /mdx-remote 页面,便可以看到和刚才图片相同的页面。

总结

在这篇文章中,我详细介绍了如何在 Next.js 中渲染 Markdown 和 MDX 文件。希望这篇文章能够帮助你更好地理解和使用 Markdown 和 MDX 在 Next.js 中的应用,为你的开发工作带来便利。

下一篇文章我将开发一个具有 SEO 优化的博客实战项目,使用 MDX 渲染,有感兴趣的小伙伴可以关注一下。

文章来源:https://blog.csdn.net/qq_44600038/article/details/135086360
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。