Итак, я использую плагин gatsby-mdx для создания сайта из файлов MDX. Я хочу создать связь между объектом SitePage и объектом Mdx, чтобы я мог выполнить один запрос graphQL к краям SitePage для построения навигации по сайту.
Большая часть моего кода написана на TypeScript, поэтому игнорируйте любые аннотации типов, если вам интересно WTF.
Вещи, которые я пробовал
Использование полей
Моей первой мыслью было использование API onCreateNode
, захват узла MDX и добавление его в SitePage с помощью действия createNodeField
. Все это прекрасно работает, НО плагин gatsby-mdx добавляет кучу другой информации к их узлу позже, используя setFieldsOnGraphQLNodeType
API (который происходит после onCreateNode
API). Я хочу, чтобы эти поля (например, frontmatter и tableOfContents) были доступны в последующих запросах graphql, но они не используют этот метод.
Реализация моей собственной setFieldsOnGraphQLNodeType
Я подумал, что могу просто расширить объект SitePage так же, как gatsby-mdx расширяет узел Mdx.
Ключевая проблема, с которой я столкнулся, заключалась в том, что я не мог понять, как создать тип узла 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 {}
}
Я также пытался просто передать тип как String ('Mdx'), но это тоже не удалось.
Использование ссылок родитель-потомок
Этот плагин создает родительско-дочернюю ссылку между узлом File и проанализированным MDX-узлом в onCreateNode
API, используя действие createParentChildLink ( source ).
Я пытался реализовать это ...
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})
}
}
}
Сначала это кажется успешным, но свойство tableOfContents
, которое gatsby-mdx добавляет к узлу Mdx, все еще недоступно в запросе 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 и сравнение строк), я не думаю, что это будет работать для моего варианта использования.