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

Next.js 14 App Router中MDX元数据无法在布局组件获取的问题

解决Next.js 14 App Router中Layout无法获取MDX页面Meta数据的方案

方法1:拆分Meta到单独文件(无额外依赖,推荐)

将每个组件的Meta数据单独维护在meta.ts文件中,同时供MDX页面和Layout复用,避免重复编写。

  1. 创建组件Meta文件
    在每个组件文档文件夹下新建meta.ts,导出统一格式的Meta数据:
// components/Button/meta.ts
export const meta = {
  title: "Button 按钮",
  description: "用于触发操作的按钮组件",
  category: "基础组件"
};
  1. MDX页面复用Meta
    在page.mdx中导入Meta并导出为页面元数据,同时在内容中复用:
import { meta } from "./meta";

// 导出给Next.js的页面元数据
export const metadata = meta;

# {meta.title}

{meta.description}

// 组件文档内容...
  1. Layout动态获取Meta
    在组件文档的Layout中,通过路由参数动态导入对应组件的meta.ts:
// app/components/[component]/layout.tsx
type Props = {
  params: { component: string };
  children: React.ReactNode;
};

export default async function ComponentLayout({ params, children }: Props) {
  // 动态导入对应组件的Meta文件
  const { meta } = await import(`../../components/${params.component}/meta.ts`);

  return (
    <div className="component-docs-layout">
      <aside>
        <h2>{meta.category}</h2>
        <h3>{meta.title}</h3>
      </aside>
      <main>{children}</main>
    </div>
  );
}

方法2:使用Contentlayer统一管理MDX文档

通过Contentlayer在构建阶段提取MDX的Frontmatter或导出变量,让Layout可以直接查询文档数据。

  1. 安装依赖
npm install contentlayer next-contentlayer
  1. 配置Contentlayer
    在项目根目录创建contentlayer.config.ts,定义文档类型和提取规则:
// contentlayer.config.ts
import { defineDocumentType, makeSource } from "contentlayer/source-files";

export const ComponentDoc = defineDocumentType(() => ({
  name: "ComponentDoc",
  filePathPattern: "components/**/page.mdx",
  // 定义需要提取的Meta字段
  fields: {
    title: { type: "string", required: true },
    description: { type: "string", required: true },
    category: { type: "string", required: true }
  },
  // 生成用于匹配路由的slug
  computedFields: {
    slug: {
      type: "string",
      resolve: (doc) => doc._raw.flattenedPath.split("/").at(-2)!
    }
  }
}));

export default makeSource({
  contentDirPath: ".",
  documentTypes: [ComponentDoc]
});
  1. 配置Next.js
    修改next.config.js集成Contentlayer:
// next.config.js
const { withContentlayer } = require("next-contentlayer");

const nextConfig = {};

module.exports = withContentlayer(nextConfig);
  1. Layout中查询Meta数据
    在组件文档Layout中,通过路由参数匹配对应的文档并获取Meta:
// app/components/[component]/layout.tsx
import { allComponentDocs } from "contentlayer/generated";

type Props = {
  params: { component: string };
  children: React.ReactNode;
};

export default function ComponentLayout({ params, children }: Props) {
  const componentDoc = allComponentDocs.find(doc => doc.slug === params.component);
  if (!componentDoc) throw new Error("组件文档未找到");

  return (
    <div className="component-docs-layout">
      <aside>
        <h2>{componentDoc.category}</h2>
        <h3>{componentDoc.title}</h3>
      </aside>
      <main>{children}</main>
    </div>
  );
}
  1. MDX页面中定义Meta
    在page.mdx顶部通过Frontmatter定义Meta:
---
title: "Button 按钮"
description: "用于触发操作的按钮组件"
category: "基础组件"
---

# Button 按钮

// 组件文档内容...

方法3:使用React Context传递Meta(客户端组件方案)

通过React Context将MDX页面的Meta传递给父级Layout,适合需要客户端交互的场景。

  1. 创建Meta Context
// app/components/ComponentMetaContext.tsx
"use client";

import { createContext, useContext } from "react";

type ComponentMeta = {
  title: string;
  description: string;
  category: string;
};

const ComponentMetaContext = createContext<ComponentMeta | null>(null);

export function ComponentMetaProvider({ children, meta }: { children: React.ReactNode; meta: ComponentMeta }) {
  return (
    <ComponentMetaContext.Provider value={meta}>
      {children}
    </ComponentMetaContext.Provider>
  );
}

export function useComponentMeta() {
  const context = useContext(ComponentMetaContext);
  if (!context) throw new Error("useComponentMeta必须在ComponentMetaProvider内使用");
  return context;
}
  1. MDX页面注入Context
    在page.mdx中导出Meta并包裹Context Provider:
import { ComponentMetaProvider } from "../ComponentMetaContext";

export const meta = {
  title: "Button 按钮",
  description: "用于触发操作的按钮组件",
  category: "基础组件"
};

# {meta.title}

{meta.description}

// 组件文档内容...

export default function Page(props) {
  return (
    <ComponentMetaProvider meta={meta}>
      <main {...props} />
    </ComponentMetaProvider>
  );
}
  1. Layout中读取Context
    将Layout改为客户端组件,通过Hook获取Meta:
// app/components/[component]/layout.tsx
"use client";

import { useComponentMeta } from "../ComponentMetaContext";

export default function ComponentLayout({ children }: { children: React.ReactNode }) {
  const meta = useComponentMeta();

  return (
    <div className="component-docs-layout">
      <aside>
        <h2>{meta.category}</h2>
        <h3>{meta.title}</h3>
      </aside>
      {children}
    </div>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 04:35:32