问题
My Gatsby Site need 2 blog templates:
- stories-template.js
- products.template.js
I have the stories-template running for my stories, but I am unsure how to tweak and change my existing codes in gatsby-node + products.template.js to make a second (different) template for my products.
I've tried all the solutions and past questions but no luck.
my code in gatsby-node.js:
const path = require('path');
exports.createPages = ({actions, graphql}) => {
const { createPage } = actions
const postTemplate = path.resolve('src/components/stories-template.js');
return graphql(`
{
allMarkdownRemark {
edges {
node {
html
id
frontmatter {
path
title
author
date
}
}
}
}
}
`).then(res => {
if(res.errors) {
return Promise.reject(res.errors)
}
res.data.allMarkdownRemark.edges.forEach(({ node }) => {
createPage({
path: node.frontmatter.path,
component: postTemplate,
})
})
})
}
my code in stories-template.js:
import React from 'react'
import Layout from '../components/layout'
export default function Template({data}) {
const post = data.markdownRemark
return(<Layout>
<div>
<p>Stories</p>
<br />
<p>{post.frontmatter.title}</p>
<div dangerouslySetInnerHTML={{__html: post.html}} />
</div>
</Layout>
)
}
export const postQuery = graphql`
query BlogPostByPath($path: String!) {
markdownRemark(frontmatter: { path: {eq:$path}}){
html
frontmatter{
path
title
date
author
}
}
}
`
This works but now I want to create a different template for products in a products-template.js. Right now my products-template is basically just copied and pasted from my stories-template.
I for the life of me can't seem to figure this out.
回答1:
Like the first comment mentioned, more context might be necessary here, but I’ll give this a go. I think the problem is that regardless of the page, you’re telling the createPage
function to use the postTemplate
template component.
Gatsby doesn’t automatically read the templates in the template directory or anything like that, you need to add the logic for this yourself.
First, you’ll need to require your other template, for example:
const postTemplate = path.resolve('src/components/stories-template.js');
const productsTemplate = path.resolve('src/components/products-template.js');
Then, you need to decide when to use productsTemplate
instead of postTemplate
here:
createPage({
path: node.frontmatter.path,
component: postTemplate,
})
For example, maybe in each Markdown file, you have template
YAML frontmatter:
createPage({
path: node.frontmatter.path,
component: node.frontmatter.template === 'product' ? productTemplate : postTemplate,
})
Here’s how I try and approach it in a slightly more generic way on my own site. The URL structure determines the template: if it’s at /journal
, it gets the Journal template component. If it’s at /shop
, it gets the Shop template component.
This might not be quite enough to drop into your existing site, but hopefully it gets you closer:
const path = require('path')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
// I created an object to hold multiple templates.
// In this case, my blog posts are at /journal and my
// products are at /shop, so those are the keys I used here.
// You might have a different system for determining what files
// should use what template.
const templates = {
journal: path.resolve('src/templates/stories-template.js'),
shop: path.resolve('src/templates/products-template.js'),
}
// Query for all Markdown “nodes”
// Note I’m using a different GraphQL query, so you’ll need to replace this
// with yours, or see if something with only the minimum requirements like
// this works for you.
return graphql(`
{
allMarkdownRemark {
edges {
node {
fields {
slug
}
}
}
}
}
`).then(result => {
if (result.errors) {
console.log(result.errors)
reject(result.errors)
}
// Create pages from Markdown files
result.data.allMarkdownRemark.edges.forEach(edge => {
let slug = edge.node.fields.slug
// Get the part of the slug we want, ex. journal
let slugKey = slug.split('/')[1]
// If the slug matches a template, use that, otherwise
// fallback to the default journal template.
// You could use your own logic here.
let template = templates[slugKey] || templates['journal']
createPage({
path: slug, // required
component: template,
context: { slug: slug },
})
})
})
}
I’m sure something with how I use promises could be improved, but otherwise this is working well for me, and gives you a decent way to add in more templates.
回答2:
@kennethormandy's answer is correct and will help you add a new blog template!
I just want to add a little bit to it: If you have already organized markdown contents for each template into different directories, it'll feel redundant to add a template
props to the frontmatter of every content.
Each MarkdownRemark node has a fileAbsolutePath
field, which allows you to filter based on where the content comes from.
For example:
exports.createPages = async ({ actions, graphql }) => {
const { createPage } = actions
const results = await graphql(`
{
allMarkdownRemark {
edges {
node {
fileAbsolutePath
}
// ...other useful fields
}
}
}
`)
if (results.errors) throw results.errors
results.data.allMarkdownRemark.edges.forEach(({ node }) => {
let template
if (node.fileAbsolutePath.includes('/blogs/')) template = path.resolve('path/to/blog/template')
createPage({ ... }) // ...etc
})
}
来源:https://stackoverflow.com/questions/54637465/how-to-create-a-second-blog-template-to-my-gatsby-site