如何在Gatsby中定义node type 实现不同MDX内容的自定义集合路由
问题原因
gatsby-source-filesystem配置的name参数只会给对应生成的File节点添加sourceInstanceName标识,不会自动生成自定义节点类型,因此无法直接作为集合路由中的nodeType使用,需要手动创建自定义节点类型来实现需求。
实现步骤
1. 拆分数据源配置(按目录区分内容类型时需要)
如果不同类型的MDX文件存放在独立目录下,先给每个目录单独配置gatsby-source-filesystem,添加对应类型标识:
// gatsby-config.js module.exports = { plugins: [ { resolve: "gatsby-source-filesystem", options: { path: `${__dirname}/blog`, name: "article", } }, { resolve: "gatsby-source-filesystem", options: { path: `${__dirname}/projects`, name: "project", } }, { resolve: "gatsby-source-filesystem", options: { path: `${__dirname}/tags`, name: "tag", } }, "gatsby-plugin-mdx", // 其他插件 ] }
2. 手动创建自定义节点类型
在gatsby-node.js中通过onCreateNode钩子,根据MDX文件的归属类型生成对应自定义节点:
// gatsby-node.js exports.onCreateNode = ({ node, actions, createNodeId, createContentDigest }) => { const { createNode, createParentChildLink } = actions // 仅处理MDX类型节点 if (node.internal.type !== "Mdx") return // 按目录区分类型的场景:从父File节点取sourceInstanceName标识 const sourceType = node.parent?.sourceInstanceName // 按frontmatter区分类型的场景:替换为 const sourceType = node.frontmatter.type let customType, fields switch(sourceType) { case "article": customType = "Article" fields = { slug: node.frontmatter.slug || node.slug } break case "project": customType = "Project" fields = { slug: node.frontmatter.slug || node.slug } break case "tag": customType = "Tag" fields = { id: node.frontmatter.id || node.slug } break default: return } // 生成自定义类型节点 const customNode = { ...fields, mdx: node, // 关联原MDX节点,方便查询内容 id: createNodeId(`${customType}-${node.id}`), parent: node.id, internal: { type: customType, contentDigest: createContentDigest(node), } } createNode(customNode) createParentChildLink({ parent: node, child: customNode }) }
3. 按自定义类型创建集合路由
直接使用上面定义的节点类型创建对应路由文件,结构和你需要的完全匹配:
src/pages/ ├── index.tsx ├── blog/ │ └── {Article.slug}.tsx ├── projects/ │ └── {Project.slug}.tsx └── tags/ └── {Tag.id}.tsx
4. 路由页面数据查询示例
以blog/{Article.slug}.tsx为例,查询对应内容的写法:
import * as React from "react" import { graphql } from "gatsby" export default function ArticlePage({ data }) { const article = data.article return ( <div> <h1>{article.mdx.frontmatter.title}</h1> <div>{article.mdx.body}</div> </div> ) } export const query = graphql` query($id: String!) { article(id: { eq: $id }) { slug mdx { frontmatter { title date } body } } } `
内容的提问来源于stack exchange,提问作者imrok
相关产品推荐
相关产品推荐

