Files
jcutmirror/gatsby-node.js
2024-05-15 18:46:34 +08:00

208 lines
5.3 KiB
JavaScript

const { match, compile } = require("path-to-regexp");
const { createFilePath } = require(`gatsby-source-filesystem`)
const { createContentDigest } = require(`gatsby-core-utils`)
const config = require('./config');
const path = require("path");
const mdxResolverPassthrough = (fieldName) => async (
source,
args,
context,
info
) => {
const type = info.schema.getType(`Mdx`);
const mdxNode = context.nodeModel.getNodeById({
id: source.parent,
});
const resolver = type.getFields()[fieldName].resolve;
const result = await resolver(mdxNode, args, context, info);
return result;
}
exports.createSchemaCustomization = ({ actions, schema }) => {
const { createTypes } = actions;
// interface for all kinds of documents
createTypes(`interface Document implements Node {
id: ID!
title: String
source: String!
body: String!
html: String!
slug: String!
date: Date @dateformat
tags: [String]!
tableOfContents: JSON
frontmatter: JSON
locale: String!
}`);
// MDX document implements Document interface
createTypes(
schema.buildObjectType({
name: `MdxDocument`,
fields: {
id: { type: `ID!` },
title: {
type: `String`,
},
source: {
type: `String!`,
},
slug: {
type: `String!`,
},
date: { type: `Date`, extensions: { dateformat: {} } },
tags: { type: `[String]!` },
tableOfContents: {
type: `JSON`,
resolve: mdxResolverPassthrough(`tableOfContents`),
},
body: {
type: `String!`,
resolve: mdxResolverPassthrough(`body`),
},
html: {
type: `String!`,
resolve: mdxResolverPassthrough(`html`),
},
frontmatter: {
type: `JSON`,
resolve: mdxResolverPassthrough(`frontmatter`),
},
locale: {
type: `String!`,
},
},
interfaces: [`Node`, `Document`],
extensions: {
infer: false,
},
})
);
}
// create fields for documents slugs and sources
exports.onCreateNode = async (
{ node, actions, getNode, createNodeId, store, cache, reporter },
) => {
const { createNode, createParentChildLink } = actions;
if (node.internal.type !== `Mdx`) return;
// create source field according to source name passed to gatsby-source-filesystem
const fileNode = getNode(node.parent);
const source = fileNode.sourceInstanceName;
const docConfig = config.documentSources[source];
if (!docConfig) reporter.panic(`Unknown source of documents ${source}`);
const { folder: folderLayout, path: pathTemplate } = docConfig;
let slug, locale;
if (node.frontmatter.slug) {
// a relative slug gets turned into a sub path
slug = node.frontmatter.slug;
locale = match(pathTemplate)(path)?.params?.lang;
} else {
// otherwise use the filepath function from gatsby-source-filesystem
const path = createFilePath({
node: fileNode,
getNode,
});
const pathMatch = match(folderLayout)(path);
if (!pathMatch) reporter.panic(`Path ${path} does not match the layout ${folderLayout}`);
const params = pathMatch.params;
locale = params.lang;
// remove default language from slug
if (params.lang === config.defaultLanguage) params.lang = undefined;
slug = compile(pathTemplate)(params);
}
// normalize use of trailing slash
slug = slug.replace(/\/*$/, `/`);
const fieldData = {
title: node.frontmatter.title,
tags: node.frontmatter.tags || [],
slug,
source,
locale,
date: node.frontmatter.date
};
const id = createNodeId(`${node.id} >>> MdxDocument`);
await createNode({
...fieldData,
// required fields
id,
parent: node.id,
children: [],
internal: {
type: `MdxDocument`,
contentDigest: createContentDigest(fieldData),
contentFilePath: node.internal.contentFilePath,
content: JSON.stringify(fieldData),
description: `Mdx implementation of the Document interface`,
},
});
createParentChildLink({ parent: node, child: getNode(id) });
}
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions;
const result = await graphql(`
{
allDocument {
nodes {
id
slug
source
frontmatter
internal {
contentFilePath
}
}
}
}
`);
if (result.errors) {
reporter.panic(result.errors);
}
const { allDocument } = result.data;
const docs = allDocument.nodes;
// create pages for documents
docs.forEach((doc, index) => {
const previous = index === docs.length - 1 ? null : docs[index + 1];
const next = index === 0 ? null : docs[index - 1];
const { slug, frontmatter } = doc;
createPage({
path: slug,
component: `${require.resolve(
config.documentSources[doc.source]?.template
)}?__contentFilePath=${doc.internal.contentFilePath}`,
context: {
id: doc.id,
previousId: previous ? previous.id : undefined,
nextId: next ? next.id : undefined,
frontmatter
},
});
})
}
exports.onCreateWebpackConfig = ({ actions }) => {
actions.setWebpackConfig({
resolve: {
alias: {
'~': path.resolve(__dirname, 'src'),
},
},
});
};