javascript - 连接两个 gatsby 节点
问题描述
因此,我使用gatsby-mdx插件从 MDX 文件创建站点。我想在 SitePage 对象和 Mdx 对象之间创建关联,以便我可以对 SitePage 边缘进行一次 graphQL 查询,以构建站点导航。
我的大部分代码都在 TypeScript 中,所以如果你想知道 WTF 那些是,请忽略任何类型注释。
我尝试过的事情
使用字段
我的第一个想法是使用onCreateNode
API,获取 MDX 节点,然后使用操作将其添加到 SitePage createNodeField
。这一切都很好,但是 gatsby-mdx 插件稍后使用API(发生在API 之后)向他们的节点添加了一堆其他信息。我希望这些字段(例如 frontmatter 和 tableOfContents)在以后的 graphql 查询中可用,但它们没有使用这种方法。setFieldsOnGraphQLNodeType
onCreateNode
实现我自己的setFieldsOnGraphQLNodeType
我想我可以像 gatsby-mdx 扩展 Mdx 节点一样扩展 SitePage 对象。
我在这里遇到的关键问题是我无法弄清楚如何创建 Mdx GraphQL 节点类型。
export const setFieldsOnGraphQLNodeType = ({type, actions, getNodes}: any, pluginOptions: any) => {
if (type.name === "SitePage") {
const {createParentChildLink} = actions
return new Promise((resolve) => {
return resolve({
"childMdx": {
type: new GraphQLObjectType({
name: 'Mdx'
}),
async resolve(sitePageNode: any) {
const allNodes = getNodes()
if (sitePageNode.component &&
(sitePageNode.component.endsWith(".mdx") || sitePageNode.component === DefaultLayout)
) {
const associatedMdx = allNodes.find((mdxNode: any) =>
mdxNode.internal.type === 'Mdx' && mdxNode.fileAbsolutePath === sitePageNode.component
)
if (associatedMdx) {
console.log("Found associated MDX node", associatedMdx.id)
console.log("Adding it to the sitepage node", sitePageNode.id)
return associatedMdx
}
}
}
}
})
})
}
return {}
}
我也尝试简单地将类型作为字符串('Mdx')传递,但这也失败了。
使用父子链接
该插件使用createParentChildLink操作 ( source )在onCreateNode
API中的 File 节点和已解析的 MDX 节点之间创建父子链接。
我尝试实施...
export const onCreateNode = ({node, actions, getNodes}: OnCreateNodeArgument) => {
const {createParentChildLink} = actions
const allNodes = getNodes()
if (node.internal && node.internal.type === 'SitePage' && node.component &&
(node.component.endsWith(".mdx") || node.component === DefaultLayout)
) {
const associatedMdx = allNodes.find((mdxNode: any) =>
mdxNode && mdxNode.internal && mdxNode.internal.type === 'Mdx' &&
(mdxNode.fileAbsolutePath === node.component || mdxNode.fileAbsolutePath === node.context.fileAbsolutePath)
)
if (associatedMdx) {
console.log("Found associated MDX node", associatedMdx.id)
console.log("Adding it to the sitepage node as a child", node.id)
createParentChildLink({parent: node, child: associatedMdx})
}
}
}
起初,这似乎成功了,但是 gatsby-mdx 添加到 Mdx 节点的tableOfContents
属性在 graphQL 查询中仍然不可用,例如:
{
allSitePage(filter: {fields: {childMdx: {id: {ne: null}}}}) {
edges {
node {
path
fields{
childMdx {
tableOfContents
fileAbsolutePath
frontmatter {
title
}
}
}
context {
roughFilePath
id
}
}
}
}
}
其他(可能不相关的)信息
我正在gatsby-node.js 中以编程方式创建一些页面。
我已经看到了关于使用节点类型映射的类似用例的建议,但是由于我在 SitePage 和 MDX 对象之间的映射需要一些技巧(特别是从 siteMetadata 读取一些内容并进行字符串比较),所以我不'认为这不适用于我的用例。
解决方案
所以我终于找到了一个更好的解决方案(比我之前的尝试,它涉及将 mdx 节点泵入 page's context
)。
Gatsby 有一种未记录的方法将节点相互链接:
是的,您可以使用带有尚未记录的 ___NODE 语法的 createNodeField 来创建节点之间的链接。
所以,步骤是这样的:
- 在
createPage
中,将 Mdx 节点的存储id
到 SitePage 节点。 - 在
onCreateNode
中,如果节点是,则SitePage
使用as 字段名称和 Mdx 节点的 id 作为值。createNodeField
Mdx___NODE
我的gatsby-node.js
:
const path = require("path")
const { createFilePath } = require("gatsby-source-filesystem")
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === "SitePage" && node.context && node.context.id) {
createNodeField({
name: "Mdx___NODE",
value: node.context.id,
node,
})
}
if (node.internal.type === "Mdx") {
const value = createFilePath({ node, getNode })
createNodeField({
// 1) this is the name of the field you are adding,
name: "slug",
// 2) this node refers to each individual MDX
node,
value: `/blog${value}`
})
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions;
const { data, errors } = await graphql(`
{
allMdx {
edges {
node {
id
fields {
slug
}
}
}
}
}
`)
if (errors) throw errors
data.allMdx.edges.forEach(({ node }) => {
createPage({
path: node.fields.slug,
component: path.resolve(`./src/components/posts-page-layout.js`),
context: { id: node.id }
});
});
};
结果:
希望能帮助到你!
推荐阅读
- python-3.x - 无法让分页爬虫工作 Python3
- python - 如果未在 Setupui 中启动,如何在菜单命令中显示 tablewidget
- c# - Xamarin.Android:如何将 WebView 登录凭据传递到 HttpWebRequest?
- python-asyncio - 异步任务与协程
- python - 推送到 Heroku 更改未修改文件的修改日期
- powershell - 在 PowerShell 中,我必须将 AzureStack Powershell 模块版本值存储为变量
- python - authlib 中的 Mongodb 支持
- python - 已解决:如何在 jupyter 笔记本中导入 scikit-learn?
- javascript - 在 Chrome 中关闭标签时如何切换到正在运行的程序
- kubernetes - 如何在 Kubernetes 上制作可靠、可扩展的 redis