gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.27k stars 10.31k forks source link

Building multiple page categories with MarkdownRemark fails #38704

Open stekhn opened 11 months ago

stekhn commented 11 months ago

Preliminary Checks

Description

I'm trying to create multiple pages from Markdown files which fall into two categories: blog posts and project pages. The Markdown files get sourced from two different folders using the gatsby-source-filesystem plugin. The gatsby-config.ts looks like this:

{
  plugins: [
    {
      resolve: `gatsby-transformer-remark`,
    },
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "projects",
        path: `${__dirname}/src/content/projects/`,
      },
    },
    {
      resolve: "gatsby-source-filesystem",
      options: {
        name: "blog",
        path: `${__dirname}/src/content/blog-posts/`,
      },
    },
  ],
}

The pages get generated using gatsby-transformer-remark. Im using two page templates, if you can call them that:

Each page template has a slightly different page query that relies on the file path to distinguish between blog posts and project pages:

export const pageQuery = graphql`
  query ($id: String!) {
    blogPost: markdownRemark(
      id: { eq: $id }
      fileAbsolutePath: { regex: "/blog-posts/" }
    ) {
      html
      frontmatter {
        slug
        title
        author
      }
    }
  }
`;
export const pageQuery = graphql`
  query ($id: String!) {
    project: markdownRemark(
      id: { eq: $id }
      fileAbsolutePath: { regex: "/projects/" }
    ) {
      html
      frontmatter {
        slug
        title
        category
      }
    }
  }
`;

When running gatsby develop, everything is fine. My page overview (index.tsx) works fine and I can navigate to the individual pages and back. But when I run gatsby build the static page generation fails with this error:

success Writing page-data.json and slice-data.json files to public directory - 0.019s - 8/8 420.69/s

 ERROR  UNKNOWN

Truncated page data information for the failed page "/projects/blog-post-3/": {
  "errors": {},
  "path": "/projects/blog-post-3/",
  "slicesMap": {},
  "pageContext": {
    "id": "96b411bb-428a-57a2-bf95-a4e5ca6a9222",
    "frontmatter__slug": "blog-post-3",
    "__params": {
      "frontmatter__slug": "blog-post-3"
    }
  }
}

failed Building static HTML for pages - 1.429s

 ERROR #95313  HTML.COMPILATION

Building static HTML failed for path "/projects/blog-post-3/"

See our docs page for more info on this error: https://gatsby.dev/debug-html

   7 | }) => {
   8 |   const { project } = data;
>  9 |   const { frontmatter, html } = project;
     |           ^
  10 |   const { slug, title, category } = frontmatter;
  11 |
  12 |   return (

  WebpackError: TypeError: Cannot destructure property 'frontmatter' of 'project' as it is null.

  - {MarkdownRemark.frontmatter__slug}.tsx:9 
    gatsby-starter-minimal/src/pages/projects/{MarkdownRemark.frontmatter__slug}.tsx:9:11

To me it seems like the filters on the GraphQL query get ignored resulting in Gatsby trying to build pages that simply do not exist like /projects/blog-post-1/ or /blog/project-1/.

Reproduction Link

https://github.com/stekhn/gatsby-multiple-md-pages

Steps to Reproduce

  1. Clone the repository: git clone https://github.com/stekhn/gatsby-multiple-md-pages
  2. Navigate to the repository: cd gatsby-multiple-md-pages
  3. Install dependencies: npm install
  4. Run the build: npm run build

Expected Result

gatsby build should pass and the following pages are to be created:

This is a logical outcome, since the respective templates {MarkdownRemark.frontmatter__slug}.tsx have a GraphQL query that each filters for category based on the filepath:

Actual Result

gatsby build fails as Gatsby tries to create the following pages:

This is behaviour seems weird, as if the filters on the GraphQL queries within the {MarkdownRemark.frontmatter__slug}.tsx templates get ignored.

Environment

System:
  OS: macOS 13.5.2
  CPU: (10) arm64 Apple M1 Pro
  Shell: 5.9 - /bin/zsh
Binaries:
  Node: 18.16.0 - /opt/homebrew/opt/node@18/bin/node
  Yarn: 1.22.19 - /opt/homebrew/bin/yarn
  npm: 9.5.1 - /opt/homebrew/opt/node@18/bin/npm
Languages:
  Python: 2.7.18 - /Library/Frameworks/Python.framework/Versions/2.7/bin/python
Browsers:
  Chrome: 119.0.6045.159
  Safari: 16.6
npmPackages:
  gatsby: ^5.12.4 => 5.12.4
  gatsby-source-filesystem: ^5.12.1 => 5.12.1
  gatsby-transformer-remark: ^6.12.3 => 6.12.3
npmGlobalPackages:
  gatsby-cli: 5.12.4

Config Flags

No response

enriquedecote commented 7 months ago

@stekhn have you found a workaround for this error?

stekhn commented 7 months ago

@enriquedecote Unfortunately, no. I refactored the whole project to use the Gatsby Node API, which gives me the flexibility I need without the bugs.

TapiwaCh commented 2 months ago

@stekhn I am having a similar issue are you able to share your refactored code?

stekhn commented 2 months ago

@TapiwaCh: Yeah, sure this how I generate my project and blog post pages with the Gatsby Node API:

import { resolve } from 'path';
import { GatsbyNode } from 'gatsby';

import { IMarkdown } from './src/types/markdown';
import { IProject } from './src/types/projects';

export const createPages: GatsbyNode['createPages'] = async ({
  graphql,
  actions,
  reporter,
}) => {
  const { createPage } = actions;

  // Create project pages
  const projectPagesData: {
    errors?: any;
    data?: IMarkdown<IProject>;
  } = await graphql(`
    {
      allMarkdownRemark(
        filter: { fileAbsolutePath: { regex: "/projects/" } }
        sort: { frontmatter: { date: DESC } }
      ) {
        nodes {
          frontmatter {
            slug
            title
            description
            date
          }
        }
      }
    }
  `);

  if (projectPagesData.errors) {
    reporter.panicOnBuild(projectPagesData.errors);
  }

  const projects = projectPagesData.data!.allMarkdownRemark.nodes;
  const projectPageTemplate = resolve('./src/templates/ProjectPage.tsx');

  projects.forEach(({ frontmatter }) => {
    createPage({
      path: `/projects/${frontmatter.slug}/`,
      component: projectPageTemplate,
      context: { ...frontmatter },
    });
  });

  reporter.info(`Project pages created: ${projects.length}`);

  // Create blog posts pages
  const blogPostData: {
    errors?: any;
    data?: IMarkdown<IProject>;
  } = await graphql(`
    {
      allMarkdownRemark(
        filter: { fileAbsolutePath: { regex: "/blog/" } }
        sort: { frontmatter: { date: DESC } }
      ) {
        nodes {
          html
          frontmatter {
            slug  
            title
            description
            date
          }
        }
      }
    }
  `);

  if (blogPostData.errors) {
    reporter.panicOnBuild(blogPostData.errors);
  }

  const blogPosts = blogPostData.data!.allMarkdownRemark.nodes;
  const blogPostTemplate = resolve('./src/templates/BlogPost.tsx');

  blogPosts.forEach(({ frontmatter, html }) => {
    createPage({
      path: `/blog/${frontmatter.slug}/`,
      component: blogPostTemplate,
      context: { ...frontmatter, html },
    });
  });

  reporter.info(`Blog posts created: ${blogPosts.length}`);
};