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
相关产品推荐
相关产品推荐

