为什么我的 mdx 文件不显示简单的 Markdown 语法(如列表和标题)?(Next.js,mdx-bundler)

Lia*_*ock 0 markdown typescript reactjs next.js

我正在尝试在 Next.js 打字稿博客入门示例中使用Kent C Dodds mdx-bundler。它似乎可以正常渲染 JSX 和某些 Markdown,但大多数简单的 Markdown 语法(例如列表和添加空格来创建段落)不起作用。我完全不知道为什么要这样做!

这是我用来测试的示例 mdx 文件:

---
title: "My first post"
description: "testing mdx"
publishedAt: "2021-12-23"
---

Skeleton component:

import {Skeleton} from '../components/Skeleton'

<Skeleton />

# Heading 1
## Heading 2

Heading
============

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 

Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 

Unordered list:

- a
- b

Ordered list:

1. one
2. two  

**bold** and *italic* and ***bold italic***
~~strikethrough~~

Horizontal rule:

*******

Blockquote:

> Lorem ipsum dolor sit amet, consectetur adipiscing elit
>
>> Lorem ipsum dolor sit amet, consectetur adipiscing elit

indented code block:

    return false;


backtick code block:

\``` (escaped here for stackoverflow)
return true;
\```

Image:

![alt](https://picsum.photos/200)
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出:

my-first-post.mdx 输出的图像

这是api.ts读取我的 mdx 内容的文件:

import fs from 'fs'
import { format, parseISO } from "date-fns"
import matter from 'gray-matter'
import path from "path"
import glob from 'glob'
import gfmPlugin from 'remark-gfm'
import remarkBreaks from 'remark-breaks'
import { bundleMDX } from "mdx-bundler"
import { PostMeta } from '../types/post'

const ROOT_PATH = process.cwd()
export const POSTS_PATH = path.join(ROOT_PATH, "posts")

export const getAllPostsMeta = () => {
  const PATH = path.join(POSTS_PATH)

  // Get all file paths in the posts folder (that end with .mdx)
  const paths = glob.sync(`${PATH}/**/*.mdx`)
  return (
    paths
      .map((filePath): PostMeta => {
        // Get the content of the file
        const source = fs.readFileSync(path.join(filePath), "utf8")
        // Get the file name without .mdx
        const slug = path.basename(filePath).replace(".mdx", "")
        // Use gray-matter to extract the post meta from post content
        const data = matter(source).data as PostMeta

        const publishedAtFormatted = format(
          parseISO(data.publishedAt),
          "dd MMMM, yyyy",
        )

        return {
          ...data,
          slug,
          publishedAtFormatted,
        }
      })

      // Sort posts by published date
      .sort(
        (a, b) =>
          Number(new Date(b.publishedAt)) - Number(new Date(a.publishedAt)),
      )
  )
}

// Get content of specific post
export const getPostBySlug = async (slug: string) => {
  // Get the content of the file
  const source = fs.readFileSync(path.join(POSTS_PATH, `${slug}.mdx`), "utf8")

  const { code, frontmatter } = await bundleMDX({
    source,
    xdmOptions(options) {
      options.remarkPlugins = [
        ...(options?.remarkPlugins ?? []),
        gfmPlugin,
        remarkBreaks,
      ]

      return options
    },
    esbuildOptions(options) {
      options.target = "esnext"
      return options
    },
  })

  const publishedAtFormatted = format(
    parseISO(frontmatter.publishedAt),
    "dd MMMM, yyyy",
  )

  const meta = {
    ...frontmatter,
    publishedAtFormatted,
    slug,
  } as PostMeta

  return {
    meta,
    code,
  }
}
Run Code Online (Sandbox Code Playgroud)

这是[slug].tsx用于渲染所选帖子的文件:

import React from 'react';
import Container from '../../components/container'
import Header from '../../components/header'
import PostHeader from '../../components/post-header'
import Layout from '../../components/layout'
import { format, parseISO } from "date-fns"
import { getMDXComponent } from "mdx-bundler/client"
import { GetStaticProps } from 'next';
import { getPostBySlug, getAllPostsMeta } from '../../lib/api'
import Head from 'next/head'
import type { Post } from "../../types/post"
import SectionSeparator from '../../components/section-separator'
import { WEBSITE_SHORT_URL } from '../../lib/constants';

export const getStaticPaths = () => {
  const posts = getAllPostsMeta()
  const paths = posts.map(({ slug }) => ({ params: { slug } }))

  return {
    paths: paths,
    // Return 404 page if path is not returned by getStaticPaths
    fallback: false,
  }
}

export const getStaticProps: GetStaticProps<Post> = async (context) => {
  const slug = context.params?.slug as string
  const post = await getPostBySlug(slug)

  return {
    props: {
      ...post,
      publishedAtFormatted: format(
        parseISO(post.meta.publishedAt),
        "dd MMMM, yyyy",
      ),
    },
  }
}

export default function PostPage({ meta, code }: Post) {
  const Component = React.useMemo(() => getMDXComponent(code), [code]);

  return (
    <Layout>
      <Container>
        <Header />
        <article className="mb-32">
          <Head>
            <title>
              {meta.title} | {WEBSITE_SHORT_URL}
            </title>
          </Head>
          <PostHeader
            title={meta.title}
            coverImage={meta.coverImage}
            date={meta.publishedAt}
          />
          <div className="max-w-4xl mx-auto">
            <Component
              components={{
                SectionSeparator
              }}
            />
          </div>
        </article>
      </Container>
    </Layout>
  );
}
Run Code Online (Sandbox Code Playgroud)

其他可能有用的东西...

我的 Next.js 文件夹结构:

+-- next/
+-- @types/
+-- components/
+-- lib
|   +-- api.ts
+-- node_modules/
+-- pages
|   +-- posts
|   |   +-- [slug].tsx
|   +-- _app.tsx
|   +-- _document.tsx
|   +-- index.tsx
+-- posts
|   +-- my-first-post.mdx
+-- public/
+-- styles/
+-- types/
+-- .gitignore
+-- next-env.d.ts
+-- package-lock.json
+-- package.json
+-- postcss.config.js
+-- tailwind.config.js
+-- tsconfig.json
Run Code Online (Sandbox Code Playgroud)

包.json:

{
  "private": true,
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start",
    "typecheck": "tsc"
  },
  "dependencies": {
    "@headlessui/react": "^1.4.2",
    "@mdx-js/loader": "^1.6.22",
    "@next/mdx": "^12.0.7",
    "@reduxjs/toolkit": "^1.7.1",
    "axios": "^0.24.0",
    "classnames": "2.3.1",
    "clsx": "^1.1.1",
    "date-fns": "2.21.3",
    "esbuild": "^0.13.15",
    "glob": "^7.2.0",
    "gray-matter": "4.0.3",
    "mdx-bundler": "^8.0.0",
    "next": "latest",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-hook-form": "^7.22.1",
    "react-redux": "^7.2.6",
    "react-scroll": "^1.8.4",
    "react-use": "^17.3.1",
    "react-use-scroll-direction": "^0.1.0",
    "remark": "13.0.0",
    "remark-breaks": "^3.0.2",
    "remark-gfm": "^3.0.1",
    "remark-html": "~13.0.1",
    "typescript": "^4.2.4"
  },
  "devDependencies": {
    "@types/glob": "^7.2.0",
    "@types/jest": "^26.0.23",
    "@types/node": "^15.6.0",
    "@types/react": "^17.0.6",
    "@types/react-dom": "^17.0.5",
    "@types/react-scroll": "^1.8.3",
    "autoprefixer": "^10.2.5",
    "postcss": "^8.3.0",
    "tailwindcss": "^2.1.2"
  }
}
Run Code Online (Sandbox Code Playgroud)

小智 5

我遇到了同样的问题,我可以使用一个名为 @tailwindcss/typography 的包来修复它。所以首先安装该包。

npm install @tailwindcss/typography
Run Code Online (Sandbox Code Playgroud)

之后,您需要将其作为插件添加到 tailwind 配置文件中

plugins: [
  require('@tailwindcss/typography')
],
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,这个博客绝对对我有帮助。这是链接