如何在 Gatsby.js 中创建多个模板
how to create multiple templates in Gatsby.js
我试图为我的项目详细信息和博客 post 页面制作两个模板,但由于我在 Graphql 和 Gatsby 方面的经验不足,我设法让它适用于我的项目、项目详细信息和博客 posts 但我有一个在我的博客 posts 文章模板上找不到的错误导致它无法正常工作??
这是我的 .md 封面
---
title: The Kimo-Coffee
stack: HTML & CSS
slug: the-kimo-coffee
date: 2022/01/03
key: projects
thumb: ../images/thumbs/coffee.png
featuredImg: ../images/featured/coffee-banner.png
---
这是我的博客页面代码(工作正常)
import { graphql, Link } from "gatsby"
import React from "react"
import Layout from "../../components/Layout"
import * as styles from "../../styles/blog.module.css"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const posts = ({ data }) => {
const posts = data.articles.nodes
return (
<Layout>
<div className={styles.blog}>
<h2>Blog Posts</h2>
{posts.map(post => (
<Link to={"/blog/" + post.frontmatter.slug} key={post.id}>
<div className={styles.posts}>
<GatsbyImage
image={getImage(post.frontmatter.thumb)}
alt={post.frontmatter.title}
/>
<h3 className={styles.title}>{post.frontmatter.title}</h3>
<p className={styles.date}>{post.frontmatter.date}</p>
<p className={styles.stack}>{post.frontmatter.stack}</p>
<p className={styles.description}>
{post.frontmatter.description}
</p>
</div>
</Link>
))}
</div>
</Layout>
)
}
export default posts
export const query = graphql`
query BlogPosts {
articles: allMdx(
filter: { frontmatter: { key: { eq: "article" } } }
sort: { fields: frontmatter___date, order: DESC }
) {
nodes {
excerpt
slug
frontmatter {
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
id
}
}
}
`
这是我的博客 post 详细信息(不起作用)
import React from "react"
import { graphql, Link } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import Layout from "../components/Layout"
import * as styles from "../styles/blog-details.module.css"
const blogPosts = ({ data, pageContext }) => {
const { body } = data.article
const { title, date, stack, featuredImg } = data.article.frontmatter
const { previous, next } = pageContext
return (
<Layout>
<div className={styles.details}>
<h2>{title}</h2>
<p>{date}</p>
<p>{stack}</p>
<div className={styles.featured}>
<GatsbyImage
image={getImage(featuredImg.childImageSharp.gatsbyImageData)}
alt={title}
/>
</div>
<article className={styles.body}>
<MDXRenderer>{body}</MDXRenderer>
</article>
<React.Fragment>
{previous && (
<Link to={previous.frontmatter.slug}>
<button>{previous.frontmatter.title}</button>
</Link>
)}
</React.Fragment>
<React.Fragment>
{next && (
<Link to={next.frontmatter.slug}>
<button>{next.frontmatter.title}</button>
</Link>
)}
</React.Fragment>
</div>
</Layout>
)
}
export default blogPosts
export const query = graphql`
query BlogDetails($slug: String) {
article: mdx(frontmatter: { slug: { eq: $slug }, key: { eq: "article" } }) {
body
frontmatter {
slug
key
title
date
stack
featuredImg {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
}
}
`
最后这是我的 gatsby 代码-node.js
const path = require("path")
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === `Mdx`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const results1 = await graphql(`
query content {
allMdx(filter: { frontmatter: { key: { eq: "projects" } } }) {
nodes {
frontmatter {
slug
title
}
}
}
}
`)
const results2 = await graphql(`
query content {
allMdx(filter: { frontmatter: { key: { eq: "article" } } }) {
nodes {
frontmatter {
slug
title
}
}
}
}
`)
const projectTemplate = path.resolve(`src/templates/project-details.js`)
const blogTemplate = path.resolve(`src/templates/blog-details.js`)
if (results1.errors || results2.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const posts = results2.data.allMdx.nodes
posts.forEach((post, index) => {
const previous = index === post.length - 1 ? null : post[index + 1]
const next = index === 0 ? null : posts[index - 1]
createPage({
path: `/blog/${post.frontmatter.slug}`,
component: blogTemplate,
context: {
slug: post.frontmatter.slug,
previous,
next,
},
})
})
results1.data.allMdx.nodes.forEach(node => {
createPage({
path: `/projects/${node.frontmatter.slug}`,
component: projectTemplate,
context: { slug: node.frontmatter.slug },
})
})
}
抱歉,如果我的代码很丑陋,我是编程的新手,我从 Gatsby 开始,因为它让我在学习 javascript 并做出反应后感到乐观 :)
你的代码中有一些奇怪的地方,尽管你说它可以工作,但它们不应该工作。
在 React 中,所有组件都必须大写,否则,React 会将它们解释为 HTML 元素,并且由于组件名称通常不匹配 HTML 标签,因此会中断,因为它不会存在。
在您的情况下,两个模板都必须重命名为:
const Posts = ({ data }) => {}
并且:
const BlogPosts = ({ data, pageContext }) => {}
提示错误:
"There's not a page or function yet at /blog/undefined"
这意味着模板无效,因为没有有效的函数模板。一旦大写,问题应该就消失了。
此外,double-check 降价以确保您在所有这些中都有一个 slug
字段。
您也可以输入 localhost:8000/404
,它正在开发中,显示所有生成页面的列表。您可以在那里检查是否正确创建了所有帖子。如果是这样,则问题出在您的模板中。否则,它在您的页面生成中。
您的问题出在 BlogPosts
的 GraphQL 查询中,其中文章的 link 设置不正确。您已定义如下查询:
query BlogPosts {
articles: allMdx(
filter: { frontmatter: { key: { eq: "article" } } }
sort: { fields: frontmatter___date, order: DESC }
) {
nodes {
excerpt
slug # <-- here's the issue
frontmatter {
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
id
}
}
}
其中 slug
直接位于 nodes
节点下。同时,您正在 linking 鼻涕虫,因为它是 frontmatter
的 child at:
<Link to={"/blog/" + post.frontmatter.slug} key={post.id}>
这导致 blog/undefined
路径。您可以检查悬停在 link 上的路径,看看它指向哪里。
根据您的数据结构,确保它应该是 slug 字段。我会说它应该在 frontmatter
:
内
frontmatter {
slug # <-- add it here
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
或者,只需更改 Link
结构,如:
<Link to={"/blog/" + post.slug} key={post.id}>
TL:DR
因为:
createNodeField({
node,
name: `slug`,
value: slug,
})
您正在根据文件名创建一个 slug
,它作为 node
child 插入,这就是查询有效但对它的引用无效的原因.
我试图为我的项目详细信息和博客 post 页面制作两个模板,但由于我在 Graphql 和 Gatsby 方面的经验不足,我设法让它适用于我的项目、项目详细信息和博客 posts 但我有一个在我的博客 posts 文章模板上找不到的错误导致它无法正常工作??
这是我的 .md 封面
---
title: The Kimo-Coffee
stack: HTML & CSS
slug: the-kimo-coffee
date: 2022/01/03
key: projects
thumb: ../images/thumbs/coffee.png
featuredImg: ../images/featured/coffee-banner.png
---
这是我的博客页面代码(工作正常)
import { graphql, Link } from "gatsby"
import React from "react"
import Layout from "../../components/Layout"
import * as styles from "../../styles/blog.module.css"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const posts = ({ data }) => {
const posts = data.articles.nodes
return (
<Layout>
<div className={styles.blog}>
<h2>Blog Posts</h2>
{posts.map(post => (
<Link to={"/blog/" + post.frontmatter.slug} key={post.id}>
<div className={styles.posts}>
<GatsbyImage
image={getImage(post.frontmatter.thumb)}
alt={post.frontmatter.title}
/>
<h3 className={styles.title}>{post.frontmatter.title}</h3>
<p className={styles.date}>{post.frontmatter.date}</p>
<p className={styles.stack}>{post.frontmatter.stack}</p>
<p className={styles.description}>
{post.frontmatter.description}
</p>
</div>
</Link>
))}
</div>
</Layout>
)
}
export default posts
export const query = graphql`
query BlogPosts {
articles: allMdx(
filter: { frontmatter: { key: { eq: "article" } } }
sort: { fields: frontmatter___date, order: DESC }
) {
nodes {
excerpt
slug
frontmatter {
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
id
}
}
}
`
这是我的博客 post 详细信息(不起作用)
import React from "react"
import { graphql, Link } from "gatsby"
import { MDXRenderer } from "gatsby-plugin-mdx"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import Layout from "../components/Layout"
import * as styles from "../styles/blog-details.module.css"
const blogPosts = ({ data, pageContext }) => {
const { body } = data.article
const { title, date, stack, featuredImg } = data.article.frontmatter
const { previous, next } = pageContext
return (
<Layout>
<div className={styles.details}>
<h2>{title}</h2>
<p>{date}</p>
<p>{stack}</p>
<div className={styles.featured}>
<GatsbyImage
image={getImage(featuredImg.childImageSharp.gatsbyImageData)}
alt={title}
/>
</div>
<article className={styles.body}>
<MDXRenderer>{body}</MDXRenderer>
</article>
<React.Fragment>
{previous && (
<Link to={previous.frontmatter.slug}>
<button>{previous.frontmatter.title}</button>
</Link>
)}
</React.Fragment>
<React.Fragment>
{next && (
<Link to={next.frontmatter.slug}>
<button>{next.frontmatter.title}</button>
</Link>
)}
</React.Fragment>
</div>
</Layout>
)
}
export default blogPosts
export const query = graphql`
query BlogDetails($slug: String) {
article: mdx(frontmatter: { slug: { eq: $slug }, key: { eq: "article" } }) {
body
frontmatter {
slug
key
title
date
stack
featuredImg {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
}
}
`
最后这是我的 gatsby 代码-node.js
const path = require("path")
const { createFilePath } = require(`gatsby-source-filesystem`)
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
if (node.internal.type === `Mdx`) {
const slug = createFilePath({ node, getNode, basePath: `pages` })
createNodeField({
node,
name: `slug`,
value: slug,
})
}
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const results1 = await graphql(`
query content {
allMdx(filter: { frontmatter: { key: { eq: "projects" } } }) {
nodes {
frontmatter {
slug
title
}
}
}
}
`)
const results2 = await graphql(`
query content {
allMdx(filter: { frontmatter: { key: { eq: "article" } } }) {
nodes {
frontmatter {
slug
title
}
}
}
}
`)
const projectTemplate = path.resolve(`src/templates/project-details.js`)
const blogTemplate = path.resolve(`src/templates/blog-details.js`)
if (results1.errors || results2.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
const posts = results2.data.allMdx.nodes
posts.forEach((post, index) => {
const previous = index === post.length - 1 ? null : post[index + 1]
const next = index === 0 ? null : posts[index - 1]
createPage({
path: `/blog/${post.frontmatter.slug}`,
component: blogTemplate,
context: {
slug: post.frontmatter.slug,
previous,
next,
},
})
})
results1.data.allMdx.nodes.forEach(node => {
createPage({
path: `/projects/${node.frontmatter.slug}`,
component: projectTemplate,
context: { slug: node.frontmatter.slug },
})
})
}
抱歉,如果我的代码很丑陋,我是编程的新手,我从 Gatsby 开始,因为它让我在学习 javascript 并做出反应后感到乐观 :)
你的代码中有一些奇怪的地方,尽管你说它可以工作,但它们不应该工作。
在 React 中,所有组件都必须大写,否则,React 会将它们解释为 HTML 元素,并且由于组件名称通常不匹配 HTML 标签,因此会中断,因为它不会存在。
在您的情况下,两个模板都必须重命名为:
const Posts = ({ data }) => {}
并且:
const BlogPosts = ({ data, pageContext }) => {}
提示错误:
"There's not a page or function yet at /blog/undefined"
这意味着模板无效,因为没有有效的函数模板。一旦大写,问题应该就消失了。
此外,double-check 降价以确保您在所有这些中都有一个 slug
字段。
您也可以输入 localhost:8000/404
,它正在开发中,显示所有生成页面的列表。您可以在那里检查是否正确创建了所有帖子。如果是这样,则问题出在您的模板中。否则,它在您的页面生成中。
您的问题出在 BlogPosts
的 GraphQL 查询中,其中文章的 link 设置不正确。您已定义如下查询:
query BlogPosts {
articles: allMdx(
filter: { frontmatter: { key: { eq: "article" } } }
sort: { fields: frontmatter___date, order: DESC }
) {
nodes {
excerpt
slug # <-- here's the issue
frontmatter {
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
id
}
}
}
其中 slug
直接位于 nodes
节点下。同时,您正在 linking 鼻涕虫,因为它是 frontmatter
的 child at:
<Link to={"/blog/" + post.frontmatter.slug} key={post.id}>
这导致 blog/undefined
路径。您可以检查悬停在 link 上的路径,看看它指向哪里。
根据您的数据结构,确保它应该是 slug 字段。我会说它应该在 frontmatter
:
frontmatter {
slug # <-- add it here
key
date
title
stack
description
thumb {
childImageSharp {
gatsbyImageData(placeholder: BLURRED, layout: FULL_WIDTH)
}
}
}
或者,只需更改 Link
结构,如:
<Link to={"/blog/" + post.slug} key={post.id}>
TL:DR
因为:
createNodeField({
node,
name: `slug`,
value: slug,
})
您正在根据文件名创建一个 slug
,它作为 node
child 插入,这就是查询有效但对它的引用无效的原因.