Впервые в Gatsby, но не в React. Я настраиваю g atsby-theme-blog-remix , который использует gatsby-plugin-mdx под капотом. По умолчанию все файлы .md и .mdx из content/posts/
преобразуются в сообщения блога. Я хотел бы расширить его, добавив раздел, содержащий сообщения о любых моих рабочих проектах, в папке content/work/
.
Гэтсби делает много магов c под капотом, что делает настройка и настройка довольно сложны для понимания. Например, при изучении файла main layout. js кажется, что все сообщения передаются как props.children, и я не уверен, как они передаются.
Вот что я m пытается достичь:
- Анализировать все файлы .md и .mdx в
content/work/
(в дополнение к content/posts/
) - Быть в состоянии легко определить, какие элементы в
props.children
сообщения в блогах и рабочие сообщения.
Вот мой gatsby- node.js:
const fs = require(`fs`);
const path = require(`path`);
const mkdirp = require(`mkdirp`);
const crypto = require(`crypto`);
const Debug = require(`debug`);
const debug = Debug(`gatsby-theme-blog`);
/**
* all of this code is taken directly from the gatsby-theme-blog
*/
// These are customizable theme options we only need to check once
let basePath;
let contentPath;
let assetPath;
// These templates are simply data-fetching wrappers that import components
const PostTemplate = require.resolve(`./src/templates/post`);
const PostsTemplate = require.resolve(`./src/templates/posts`);
// Ensure that content directories exist at site-level
exports.onPreBootstrap = ({ store }, themeOptions) => {
const { program } = store.getState();
basePath = themeOptions.basePath || `/`;
contentPath = themeOptions.contentPath || `content/posts`;
assetPath = themeOptions.assetPath || `content/assets`;
const dirs = [
path.join(program.directory, contentPath),
path.join(program.directory, assetPath),
];
dirs.forEach(dir => {
debug(`Initializing ${dir} directory`);
if (!fs.existsSync(dir)) {
mkdirp.sync(dir);
}
});
const componentsDir = path.join(
program.directory,
`./src/@joshkennedy00/gatsby-theme-blog-remix/components`
);
debug(`Initializing ${componentsDir} directory`);
if (!fs.existsSync(componentsDir)) {
mkdirp.sync(componentsDir);
}
};
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, {
fieldName,
});
return result;
};
exports.sourceNodes = ({ actions, schema }) => {
const { createTypes } = actions;
createTypes(
schema.buildObjectType({
name: `BlogPost`,
fields: {
id: { type: `ID!` },
title: {
type: `String!`,
},
slug: {
type: `String!`,
},
date: { type: `Date`, extensions: { dateformat: {} } },
tags: { type: `[String]!` },
keywords: { type: `[String]!` },
excerpt: {
type: `String!`,
args: {
pruneLength: {
type: `Int`,
defaultValue: 140,
},
},
resolve: mdxResolverPassthrough(`excerpt`),
},
body: {
type: `String!`,
resolve: mdxResolverPassthrough(`body`),
},
},
interfaces: [`Node`],
})
);
};
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions;
const result = await graphql(`
{
site {
siteMetadata {
title
social {
name
url
}
}
}
mdxPages: allBlogPost(
sort: { fields: [date, title], order: DESC }
limit: 1000
) {
edges {
node {
id
excerpt
slug
title
date(formatString: "MMMM DD, YYYY")
}
}
}
}
`);
if (result.errors) {
reporter.panic(result.errors);
}
// Create Posts and Post pages.
const {
mdxPages,
site: { siteMetadata },
} = result.data;
const posts = mdxPages.edges;
const { title: siteTitle, social: socialLinks } = siteMetadata;
// Create a page for each Post
posts.forEach(({ node: post }, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1];
const next = index === 0 ? null : posts[index - 1];
const { slug } = post;
createPage({
path: slug,
component: PostTemplate,
context: {
...post,
siteTitle,
socialLinks,
previous,
next,
},
});
});
// // Create the Posts page
createPage({
path: basePath,
component: PostsTemplate,
context: {
posts,
siteTitle,
socialLinks,
},
});
};
// Create fields for post slugs and source
// This will change with schema customization with work
exports.onCreateNode = ({ node, actions, getNode, createNodeId }) => {
const { createNode, createParentChildLink } = actions;
const toPostPath = node => {
const { dir } = path.parse(node.relativePath);
return path.join(basePath, dir, node.name);
};
// Make sure it's an MDX node
if (node.internal.type !== `Mdx`) {
return;
}
// Create source field (according to contentPath)
const fileNode = getNode(node.parent);
const source = fileNode.sourceInstanceName;
if (node.internal.type === `Mdx` && source === contentPath) {
const slug = toPostPath(fileNode);
const fieldData = {
title: node.frontmatter.title,
tags: node.frontmatter.tags || [],
slug,
date: node.frontmatter.date,
};
createNode({
...fieldData,
// Required fields.
id: createNodeId(`${node.id} >>> BlogPost`),
parent: node.id,
children: [],
internal: {
type: `BlogPost`,
contentDigest: crypto
.createHash(`md5`)
.update(JSON.stringify(fieldData))
.digest(`hex`),
content: JSON.stringify(fieldData),
description: `Blog Posts`,
},
});
createParentChildLink({ parent: fileNode, child: node });
}
};
Буду очень признателен за любую помощь здесь.