Как автоматически добавить тег «slug» в файлы уценки с помощью NetlifyCMS и Gatsby?

Ссылка на Codesandbox здесь.

Каждый раз, когда я пытаюсь опубликовать новую запись в блоге с помощью NetlifyCMS, она сообщает, что публикуется. Однако моя сборка Netlify дает сбой и фактически не публикует сообщения в блоге.

Вот ошибка, которую я получаю:

12:44:22 PM: error Your site's "gatsby-node.js" must set the page path when creating a page.
12:44:22 PM: The page object passed to createPage:
12:44:22 PM: {
12:44:22 PM:     "path": null,
12:44:22 PM:     "component": "/opt/build/repo/src/templates/blogTemplate.js",
12:44:22 PM:     "context": {
12:44:22 PM:         "slug": null
12:44:22 PM:     }
12:44:22 PM: }
12:44:22 PM: See the documentation for the "createPage" action — https://www.gatsbyjs.org/docs/actions/#createPage
12:44:22 PM: not finished createPages - 0.042s

Причина, по которой я получаю эту ошибку, заключается в том, что при публикации новых сообщений в файл уценки нового сообщения в блоге не добавляется автоматически тег «slug». Пример:

---
title: 10 of the best SEO strategies for 2021
slug: /posts/10-best-seo-strategies-2021/ <-- I had to manually add this in the markdown file. This line is completely missing when pushing new blog posts live. This is causing the site build to fail.
date: 2021-03-26T23:53:24.128Z
excerpt: >-
  In this post, we go over 10 of the best SEO strategies for 2021. If you want
  more business, read more now!
---

Как только я вручную добавляю сообщение в блоге в виде файла уценки за пределами NetlifyCMS, добавляю тег slug и нажимаю на мастер, он успешно строится. Очевидно, я не хочу делать это каждый раз, я хочу, чтобы мой сайт нормально публиковался из NetlifyCMS.

gatsby-node.js:

exports.createPages = async ({ actions, graphql, reporter }) => {
  const { createPage } = actions
  const blogPostTemplate = require.resolve(`./src/templates/blogTemplate.js`)
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { order: DESC, fields: [frontmatter___date] }
        limit: 1000
      ) {
        edges {
          node {
            frontmatter {
              slug
            }
          }
        }
      }
    }
  `)
  // Handle errors
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.frontmatter.slug,
      component: blogPostTemplate,
      context: {
        // additional data can be passed via context
        slug: node.frontmatter.slug,
      },
    })
  })
}

GraphQL pageQuery в моем файле /src/pages/posts.js:

export const pageQuery = graphql`
  query {
    allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
      edges {
        node {
          id
          excerpt(pruneLength: 250)
          frontmatter {
            date(formatString: "MMMM DD, YYYY")
            slug
            title
          }
        }
      }
    }
  }
`

Конфиг.yml:

backend:
  name: github
  repo: my-repo

media_folder: uploads
public_folder: /uploads

collections:
  - name: "posts"
    label: "Posts"
    folder: "posts"
    create: true
    slug: "{{slug}}"
    fields:
      - { label: "Title", name: "title", widget: "string" }
      - { label: "Publish Date", name: "date", widget: "date" }
      - { label: "Excerpt", name: "excerpt", widget: "string" }
      - { label: "Body", name: "body", widget: "markdown" }

blogTemplate.js file:

export const pageQuery = graphql`
  query($slug: String!) {
    markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      html
      frontmatter {
        date(formatString: "MMMM DD, YYYY")
        slug
        title
        excerpt
      }
    }
  }
`

Любая идея, почему это может происходить?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
1 402
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Любая идея, почему это может происходить?

Что ж, вы пытаетесь запросить поле slug, а оно никогда не устанавливалось (по крайней мере, вначале). Ваш frontmatter имеет следующие поля:

  • Заголовок
  • Публиковать
  • Выдержка
  • Тело

Но не slug.

Стандартный способ — добавить его в свой config.yml:

- { name: slug, label: Slug, required: true, widget: string }

Добавив это, ваш запрос будет работать автоматически.

Другой метод — использовать встроенные прослушиватели и преобразователи (API-интерфейсы узлов) от Gatsby для создания slug на основе ранее установленного параметра, но вам нужно будет изменить свой запрос. В свой gatsby-node.js добавьте:

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions;

  if (node.internal.type === `MarkdownRemark`) {
    let value = createFilePath({ node, getNode });

    createNodeField({
      name: `slug`,
      node,
      value,
    });
  }
};

С помощью onCreateNode вы создаете новый узел на основе некоторых правил (подробнее). Это создаст новую коллекцию для запроса с именем fields и slug внутри. Поэтому вам нужно только адаптировать его, например:

exports.createPages = async ({ actions, graphql, reporter }) => {
  const { createPage } = actions
  const blogPostTemplate = require.resolve(`./src/templates/blogTemplate.js`)
  const result = await graphql(`
    {
      allMarkdownRemark(
        sort: { order: DESC, fields: [frontmatter___date] }
        limit: 1000
      ) {
        edges {
          node {
            fields{
              slug
            }
            frontmatter {
              slug // not needed now
            }
          }
        }
      }
    }
  `)
  // Handle errors
  if (result.errors) {
    reporter.panicOnBuild(`Error while running GraphQL query.`)
    return
  }
  result.data.allMarkdownRemark.edges.forEach(({ node }) => {
    createPage({
      path: node.fields.slug,
      component: blogPostTemplate,
      context: {
        // additional data can be passed via context
        slug: node.frontmatter.slug,
      },
    })
  })
}

Не существует «автоматического» способа добиться этого без погружения в дополнительные схемы Node. Вы только создаете файл уценки и запрашиваете его содержимое. Какова логика создания slug с нуля? slug поля всегда должны быть обязательными.

Вы можете попробовать изменить следующее:

createNodeField({
  name: `slug`,
  node,
  value,
});

Чтобы добавить пользовательский value на основе некоторой логики, если slug не определен.


Другое дело вне темы. Вы создаете дубликат excerpt:

  • Один в вашей уценке (из CMS Netlify):

    - { label: "Excerpt", name: "excerpt", widget: "string" }
    
  • Один создается автоматически в вашем запросе GraphQL. Файловая система GraphQL + Gatsby добавляет пользовательское поле excerpt, которое получается в результате разделения содержимого body с помощью фильтрации pruneLength вне frontmatter:

      export const pageQuery = graphql`
        query {
          allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }) {
            edges {
              node {
                id
                excerpt(pruneLength: 250)
                frontmatter {
                  date(formatString: "MMMM DD, YYYY")
                  slug
                  title
                }
              }
            }
          }
        }
      `
    

Я думаю, что вы смешиваете вещи здесь, я бы рекомендовал использовать только один из них, чтобы избежать недоразумений в вашем коде.

Добавление - {name: slug, label: Slug, required: true, widget: string} в мой config.yml сделало это. Спасибо Ферран!

JD Fill 15.12.2020 16:24

Другие вопросы по теме