Remark 和 rehype 无法在应用程序路由器的 nextjs 中正确转换 mdx

问题描述 投票:0回答:1

如果有人想克隆它,我已经在 github 中发布了我的代码。我也上传到了代码沙箱。

基本上我想用带有 md 或 mdx 的 nextjs 创建一个博客,所以我查看了 nextjs 文档。我在 blogposts 文件夹中保存了一些 mdx 文件,并尝试了两种方法在网站上呈现博客,如文档说:

  1. 使用基于文件的路由在应用程序文件夹的路由中创建 page.mdx 而不是 page.tsx。 (您可以在
    /example
    路线中进行测试)
  2. 从 blogposts 文件夹中动态读取所有 MDX 文件,并创建基于文件名(例如 /posts/test)呈现 MDX 内容的动态路由。

这是我观察到的行为:

在第一种方法(/示例)中,MDX 内容可以正确呈现,并且一些插件(例如 rehype-pretty-code)可以工作,但其他插件(例如 remark-toc)则不能。此外,自定义导入的 React 组件不起作用;仅渲染 Markdown。 在第二种方法(/posts/test)中,所有插件都无法正常运行,包括 rehype-pretty-code。

以下是我的代码设置的相关部分:

mdx-components.tsx

import type { MDXComponents } from "mdx/types";

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
  };
}

下一个.config.mjs

import createMDX from "@next/mdx";
import remarkRehype from "remark-rehype";
import remarkToc from "remark-toc";
import rehypeSanitize from "rehype-sanitize";
import rehypeStringify from "rehype-stringify";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeAutolinkHeadings from "rehype-autolink-headings";

const nextConfig = {
  pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
};

// Use dynamic import for rehype-highlight
const withMDX = async () => {
  return createMDX({
    options: {
      remarkPlugins: [remarkToc, remarkRehype],
      rehypePlugins: [
        rehypeSanitize,
        rehypeStringify,
        rehypeAutolinkHeadings,
        [
          rehypePrettyCode,
          {
            theme: "one-dark-pro",
          },
        ],
      ],
    },
  })(nextConfig);
};

export default withMDX();

应用程序/帖子/[slug]/page.tsx

import getFormattedDate from "@/lib/getFormattedDate";
import { getBlogPosts } from "@/lib/posts";
import Link from "next/link";
import { notFound } from "next/navigation";

export function generateStaticParams() {
  let posts = getBlogPosts();

  return posts.map(async (post) => ({
    slug: (await post).slug,
  }));
}

export default async function Post({ params }: { params: { slug: string } }) {
  let post = getBlogPosts().find(
    async (post) => (await post).slug === params.slug
  );

  if (!post) {
    notFound();
  }

  return (
    <>
      <main>
        <h1 className="title font-semibold text-2xl tracking-tighter">
          {(await post).metadata.title}
        </h1>
        <div className="flex justify-between items-center mt-2 mb-8 text-sm">
          <p className="text-sm text-neutral-600 dark:text-neutral-400">
            {getFormattedDate((await post).metadata.publishedAt)}
          </p>
        </div>

        <article
          className="prose prose-slate"
          dangerouslySetInnerHTML={{ __html: (await post).content }}
        ></article>
        <Link href="/">← Back to home</Link>
      </main>
    </>
  );
}

最后是用于读取博客文章 mdx 文件的代码:

/lib/posts.ts

import fs from "fs";
import path from "path";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import remarkFrontmatter from "remark-frontmatter";
import remarkToc from "remark-toc";
import rehypeSanitize from "rehype-sanitize";
import rehypeStringify from "rehype-stringify";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import html from "remark-html";
import matter from "gray-matter";

export function getBlogPosts() {
  const dir = path.join(process.cwd(), "blogposts");
  const mdxFiles = fs
    .readdirSync(dir)
    .filter((file) => path.extname(file) === ".mdx");

  const blogPosts = mdxFiles.map(async (file) => {
    const filePath = path.join(dir, file);
    const fileContents = fs.readFileSync(filePath, "utf-8");

    // Use gray-matter to parse the post metadata section
    const matterResult = matter(fileContents);

    const processedContent = await unified()
      .use(html)
      .use(remarkParse)
      .use(remarkFrontmatter)
      .use(remarkRehype)
      .use(rehypePrettyCode, {
        theme: "one-dark-pro",
      }) // Prettify code blocks
      .use(rehypeAutolinkHeadings) // Add anchor links to headings
      .use(remarkToc) // Generate table of contents
      .use(rehypeSanitize) // Sanitize HTML input
      .use(rehypeStringify)
      .process(matterResult.content);

    const content = processedContent.toString();

    let slug = path.basename(file, path.extname(file));

    return {
      metadata: matterResult.data,
      slug,
      content,
    };
  });

  return blogPosts;
}

有人遇到过类似的问题或知道如何解决这些场景中的插件和渲染问题吗?这是我第一次使用这些库,我对很多插件都不熟悉,如果你们认为很多插件没有必要,请告诉我:)。 另外,由于我计划通过数据库管理博客,是否可以将 getBlogPosts() 函数调整为从数据库获取而不是从文件中读取而不进行重大更改?

非常感谢您的帮助。

next.js app-router mdxjs remarkjs
1个回答
0
投票

我不确定这是否是根本问题,但

getBlogPosts
声明缺少
async
关键字。

© www.soinside.com 2019 - 2024. All rights reserved.