You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS MDX博客:从Front Matter取Slug后,如何让getStaticProps生效?

解决Next.js中根据Front Matter的Slug匹配对应MDX文件的问题

你的核心问题是getStaticProps无法根据路由中的slug找到对应的MDX文件,因为你不想用文件名作为slug。下面提供两种可行的解决方案:

方案一:在getStaticProps中遍历文件匹配Slug

直接在getStaticProps里扫描所有MDX文件,读取每个文件的Front Matter,找到与当前路由slug匹配的文件:

import { serialize } from "next-mdx-remote/serialize";
import { MDXRemote } from "next-mdx-remote";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { sync } from "glob";

const PostPage = ({ frontMatter: { title, date }, mdxSource }: any): any => {
  return (
    <div className="mx-auto w-[50vw] mt-10">
      <div className="prose-xl">
        <h1>{title}</h1>
        <MDXRemote {...mdxSource} />
      </div>
    </div>
  );
};

const postsPath = path.join(process.cwd(), "posts");

const getStaticPaths = async () => {
  const files = sync(`${postsPath}/**/*.mdx`);

  const paths = files.map((file) => {
    const markdownWithMeta = fs.readFileSync(file, "utf-8");
    const { data: frontMatter } = matter(markdownWithMeta);

    return {
      params: {
        slug: frontMatter.slug,
      },
    };
  });

  return {
    paths,
    fallback: false,
  };
};

const getStaticProps = async ({ params: { slug } }: any) => {
  // 获取所有MDX文件路径
  const files = sync(`${postsPath}/**/*.mdx`);
  
  let targetFrontMatter;
  let targetContent;

  // 遍历文件找到匹配slug的项
  for (const file of files) {
    const markdownWithMeta = fs.readFileSync(file, "utf-8");
    const { data: frontMatter, content } = matter(markdownWithMeta);
    
    if (frontMatter.slug === slug) {
      targetFrontMatter = frontMatter;
      targetContent = content;
      break;
    }
  }

  // 处理slug不存在的情况,返回404
  if (!targetFrontMatter) {
    return { notFound: true };
  }

  const mdxSource = await serialize(targetContent);

  return {
    props: {
      frontMatter: targetFrontMatter,
      slug,
      mdxSource,
    },
  };
};

export { getStaticProps, getStaticPaths };
export default PostPage;

方案二:预存Slug与文件路径的映射(更高效)

在getStaticPaths运行时,提前建立slug到文件路径的映射,避免getStaticProps重复遍历所有文件:

import { serialize } from "next-mdx-remote/serialize";
import { MDXRemote } from "next-mdx-remote";
import fs from "fs";
import path from "path";
import matter from "gray-matter";
import { sync } from "glob";

const PostPage = ({ frontMatter: { title, date }, mdxSource }: any): any => {
  return (
    <div className="mx-auto w-[50vw] mt-10">
      <div className="prose-xl">
        <h1>{title}</h1>
        <MDXRemote {...mdxSource} />
      </div>
    </div>
  );
};

const postsPath = path.join(process.cwd(), "posts");
// 全局存储slug到文件路径的映射
let slugToFileMap: Record<string, string> = {};

const getStaticPaths = async () => {
  const files = sync(`${postsPath}/**/*.mdx`);

  const paths = files.map((file) => {
    const markdownWithMeta = fs.readFileSync(file, "utf-8");
    const { data: frontMatter } = matter(markdownWithMeta);
    
    // 填充映射关系
    slugToFileMap[frontMatter.slug] = file;

    return {
      params: {
        slug: frontMatter.slug,
      },
    };
  });

  return {
    paths,
    fallback: false,
  };
};

const getStaticProps = async ({ params: { slug } }: any) => {
  // 通过映射直接获取文件路径
  const targetFile = slugToFileMap[slug];
  
  if (!targetFile) {
    return { notFound: true };
  }

  const markdownWithMeta = fs.readFileSync(targetFile, "utf-8");
  const { data: frontMatter, content } = matter(markdownWithMeta);
  const mdxSource = await serialize(content);

  return {
    props: {
      frontMatter,
      slug,
      mdxSource,
    },
  };
};

export { getStaticProps, getStaticPaths };
export default PostPage;

注意事项

  • 确保所有MDX文件的Front Matter中slug字段唯一,否则会出现映射覆盖,导致部分路由无法找到正确文件。
  • 若使用fallback: 'blocking'或true,需调整映射逻辑(比如将映射存储到文件或使用缓存),但当前fallback: false的场景下上述代码可直接运行。
  • 添加notFound: true的处理,能在slug不存在时自动返回Next.js的404页面。

内容的提问来源于stack exchange,提问作者Aravind Sanjeev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:19:21