hasura / gatsby-gitbook-starter

Generate GitBook style modern docs/tutorial websites using Gatsby + MDX
https://hasura.io/learn/graphql/react/introduction/
MIT License
981 stars 382 forks source link

Last file in folder under content gets Runtime Error #147

Open emorrow38 opened 2 years ago

emorrow38 commented 2 years ago

I have started a new Gatsby-Gitbook-Starter site and I am having a strange problem: when I put markdown files in a folder under content, the last markdown file in the folder gets a Runtime Error even when displaying from the Contents at left. This happened in two folders exactly the same way. I will show one folder where this happens. Here is my first folder:

GGDLast 03 Folder 01

The last markdown file is ZReferenceLast01md. It is a very simple file (just a placeholder for now):

GGDLast 04 LastMD file 01

When I display the Gatsby site, I can see the files in the contents at left:

image

When I click on it I get:

image

The first idea is that there must be something wrong with ZReferenceLast01md. I can show the real problem is that the file is the last in the folder. My proof is simple: I will create a NEW last file called ZReferenceLast02.md in the same folder:

image

This new file is also very simple:

image

When I look at the website again, I can see there is an extra file. I click on the OLD last file: ZReferenceLast01md:

image

This time it displays - even though I made no changes to that file:

image

However, I now click on the NEW last file in that folder:

image

This file is almost identical to ZReferenceLast01 but it gets:

image

I find this very confusing - why does being the last file make a difference to the file displaying?

This happened in a second folder "Checklists".

To help someone work out what I need to fix here are some important files:

CONFIG.JS

const config = { gatsby: { pathPrefix: '/', siteUrl: 'https://github.genevaers.io', gaTrackingId: null, trailingSlash: false, }, header: { logo: '', logoLink: 'https://genevaers.org', title: '

GenevaERS General Documentation

', githubUrl: 'https://genevaers.org/', helpUrl: '', tweetText: '', social: `
  •         </a>
          </li>
            <li>
            <a href="https://discordapp.com/invite/hasura" target="_blank" rel="noopener">
              <div class="discordBtn">
                <img src='https://graphql-engine-cdn.hasura.io/learn-hasura/assets/homepage/discord-brands-block.svg' alt={'Discord'}/>
              </div>
            </a>
          </li>`,
    links: [{ text: '', link: '' }],
    search: {
      enabled: false,
      indexName: '',
      algoliaAppId: process.env.GATSBY_ALGOLIA_APP_ID,
      algoliaSearchKey: process.env.GATSBY_ALGOLIA_SEARCH_KEY,
      algoliaAdminKey: process.env.ALGOLIA_ADMIN_KEY,
    },

    }, sidebar: { forcedNavOrder: [ '/Home', 'Reference', '/Reference', 'Checklists', '/Checklists', 'HomePage2', 'HomePage3', ], collapsedNav: [ '/Reference', '/Checklists', ], links: [{ text: 'GenevaERS.org', link: 'https://genevaers.org' }], frontline: false, ignoreIndex: true, title: "An Open Mainframe Project" }, siteMetadata: { title: 'GenevaERS General Documentation', description: 'GenevaERS - the single-pass engine ', ogImage: null, docsLocation: '', favicon: '', }, pwa: { enabled: false, // disabling this will also remove the existing service worker. manifest: { name: 'Gatsby Gitbook Starter', short_name: 'GitbookStarter', start_url: '/', background_color: '#6b37bf', theme_color: '#6b37bf', display: 'standalone', crossOrigin: 'use-credentials', icons: [ { src: 'src/pwa-512.png', sizes: 512x512, type: image/png, }, ], }, }, };

    module.exports = config;

    GATSBY-CONFIG.JS

    require("dotenv").config(); const queries = require("./src/utils/algolia"); const config = require("./config"); const plugins = [ 'gatsby-plugin-sitemap', 'gatsby-plugin-sharp', gatsby-plugin-catch-links, { resolve: gatsby-plugin-layout, options: { component: require.resolve(./src/templates/docs.js) } }, 'gatsby-plugin-emotion', 'gatsby-plugin-react-helmet', { resolve: "gatsby-source-filesystem", options: { name: "docs", path: ${__dirname}/content/ } }, { resolve: 'gatsby-plugin-mdx', options: { gatsbyRemarkPlugins: [ { resolve: "gatsby-remark-images", options: { maxWidth: 1035, sizeByPixelDensity: true } }, { resolve: 'gatsby-remark-copy-linked-files' } ], extensions: [".mdx", ".md"] } }, { resolve: gatsby-plugin-gtag, options: { // your google analytics tracking id trackingId: config.gatsby.gaTrackingId, // Puts tracking script in the head instead of the body head: true, // enable ip anonymization anonymize: false, }, }, ]; // check and add algolia if (config.header.search && config.header.search.enabled && config.header.search.algoliaAppId && config.header.search.algoliaAdminKey) { plugins.push({ resolve: gatsby-plugin-algolia, options: { appId: config.header.search.algoliaAppId, // algolia application id apiKey: config.header.search.algoliaAdminKey, // algolia admin key to index queries, chunkSize: 10000, // default: 1000 }} ) } // check and add pwa functionality if (config.pwa && config.pwa.enabled && config.pwa.manifest) { plugins.push({ resolve: gatsby-plugin-manifest, options: {...config.pwa.manifest}, }); plugins.push({ resolve: 'gatsby-plugin-offline', options: { appendScript: require.resolve(./src/custom-sw-code.js), }, }); } else { plugins.push('gatsby-plugin-remove-serviceworker'); }

    // check and remove trailing slash if (config.gatsby && !config.gatsby.trailingSlash) { plugins.push('gatsby-plugin-remove-trailing-slashes'); }

    module.exports = { pathPrefix: config.gatsby.pathPrefix, siteMetadata: { title: config.siteMetadata.title, description: config.siteMetadata.description, docsLocation: config.siteMetadata.docsLocation, ogImage: config.siteMetadata.ogImage, favicon: config.siteMetadata.favicon, logo: { link: config.header.logoLink ? config.header.logoLink : '/', image: config.header.logo }, // backwards compatible headerTitle: config.header.title, githubUrl: config.header.githubUrl, helpUrl: config.header.helpUrl, tweetText: config.header.tweetText, headerLinks: config.header.links, siteUrl: config.gatsby.siteUrl, }, plugins: plugins, // flags: { // DEV_SSR: false, // FAST_DEV: false, // Enable all experiments aimed at improving develop server start time // PRESERVE_WEBPACK_CACHE: false, // (Umbrella Issue (https://gatsby.dev/cache-clearing-feedback)) · Use webpack's persistent caching and don't delete webpack's cache when changing gatsby-node.js & gatsby-config.js files. // PRESERVE_FILE_DOWNLOAD_CACHE: false, // (Umbrella Issue (https://gatsby.dev/cache-clearing-feedback)) · Don't delete the downloaded files cache when changing gatsby-node.js & gatsby-config.js files. // PARALLEL_SOURCING: false, // EXPERIMENTAL · (Umbrella Issue (https://gatsby.dev/parallel-sourcing-feedback)) · Run all source plugins at the same time instead of serially. For sites with multiple source plugins, this can speedup sourcing and transforming considerably. // FUNCTIONS: false // EXPERIMENTAL · (Umbrella Issue (https://gatsby.dev/functions-feedback)) · Compile Serverless functions in your Gatsby project and write them to disk, ready to deploy to Gatsby Cloud // } };

    GATSBY-NODE.JS

    const componentWithMDXScope = require('gatsby-plugin-mdx/component-with-mdx-scope');

    const path = require('path');

    const startCase = require('lodash.startcase');

    const config = require('./config');

    exports.createPages = ({ graphql, actions }) => { const { createPage } = actions;

    const { createRedirect } = actions

    createRedirect({ fromPath: /, isPermanent: true, redirectInBrowser: true, toPath: /Home, });

    createRedirect({ fromPath: `, isPermanent: true, redirectInBrowser: true, toPath:/Home`, });

    createRedirect({ fromPath: /index, isPermanent: true, redirectInBrowser: true, toPath: /Home, });

    return new Promise((resolve, reject) => { resolve( graphql( { allMdx { edges { node { fields { id } tableOfContents fields { slug } } } } } ).then(result => { if (result.errors) { console.log(result.errors); // eslint-disable-line no-console reject(result.errors); }

        // Create blog posts pages.
        result.data.allMdx.edges.forEach(({ node }) => {
          createPage({
            path: node.fields.slug ? node.fields.slug : '/',
            component: path.resolve('./src/templates/docs.js'),
            context: {
              id: node.fields.id,
            },
          });
        });
      })
    );

    }); };

    exports.onCreateWebpackConfig = ({ actions }) => { actions.setWebpackConfig({ resolve: { modules: [path.resolve(__dirname, 'src'), 'node_modules'], alias: { $components: path.resolve(__dirname, 'src/components'), buble: '@philpl/buble', // to reduce bundle size }, }, }); };

    exports.onCreateBabelConfig = ({ actions }) => { actions.setBabelPlugin({ name: '@babel/plugin-proposal-export-default-from', }); };

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

    if (node.internal.type === Mdx) { const parent = getNode(node.parent);

    let value = parent.relativePath.replace(parent.ext, '');
    
    if (value === 'index') {
      value = '';
    }
    
    if (config.gatsby && config.gatsby.trailingSlash) {
      createNodeField({
        name: `slug`,
        node,
        value: value === '' ? `/` : `/${value}/`,
      });
    } else {
      createNodeField({
        name: `slug`,
        node,
        value: `/${value}`,
      });
    }
    
    createNodeField({
      name: 'id',
      node,
      value: node.id,
    });
    
    createNodeField({
      name: 'title',
      node,
      value: node.frontmatter.title || startCase(parent.name),
    });

    } };

    =================================================================================

    HEADER.JS

    import * as React from 'react'; import styled from '@emotion/styled'; import { StaticQuery, graphql } from 'gatsby'; import GitHubButton from 'react-github-btn'; import Link from './link'; import Loadable from 'react-loadable'; import './styles.css'; import mylogo from './images/genevaers-color.svg'; import Sidebar from './sidebar'; import config from '../../config.js'; import LoadingProvider from './mdxComponents/loading'; import { DarkModeSwitch } from './DarkModeSwitch';

    const help = require('./images/help.svg');

    const isSearchEnabled = config.header.search && config.header.search.enabled ? true : false;

    let searchIndices = [];

    if (isSearchEnabled && config.header.search.indexName) { searchIndices.push({ name: ${config.header.search.indexName}, title: Results, hitComp: PageHit, }); }

    const LoadableComponent = Loadable({ loader: () => import('./search/index'), loading: LoadingProvider, });

    function myFunction() { var x = document.getElementById('navbar');

    if (x.className === 'topnav') { x.className += ' responsive'; } else { x.className = 'topnav'; } }

    const StyledBgDiv = styled('div')` height: 60px; box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.16); background-color: #f8f8f8; position: relative; display: none; background: ${(props) => (props.isDarkThemeActive ? '#001932' : undefined)};

    @media (max-width: 767px) { display: block; } `;

    const Header = ({ location, isDarkThemeActive, toggleActiveTheme }) => ( <StaticQuery query={graphql query headerTitleQuery { site { siteMetadata { headerTitle githubUrl helpUrl tweetText logo { link image } headerLinks { link text } } } } } render={(data) => { // const logoImg = require('./images/logo.svg');

      const twitter = require('./images/twitter.svg');
    
      const discordBrandsBlock = require('./images/discord-brands-block.svg');
    
      const twitterBrandsBlock = require('./images/twitter-brands-block.svg');
    
      const {
        site: {
          siteMetadata: { headerTitle, githubUrl, helpUrl, tweetText, logo, headerLinks },
        },
      } = data;
    
      const finalLogoLink = logo.link !== '' ? logo.link : 'https://genevaers.org/';
    
      return (
        <div className={'navBarWrapper'}>
          <nav className={'navBarDefault'}>
            <div className={'navBarHeader'}>
              <Link to={finalLogoLink} className={'navBarBrand'}>
                <img
                  className={'img-responsive displayInline'}
    //              src={logo.image !== '' ? logo.image : logoImg}
                    src={mylogo}
                  alt={'logo'}
                />
              </Link>
              <div
                className={'headerTitle displayInline'}
                dangerouslySetInnerHTML={{ __html: headerTitle }}
              />
            </div>
            {config.header.social ? (
              <ul
                className="socialWrapper visibleMobileView"
                dangerouslySetInnerHTML={{ __html: config.header.social }}
              ></ul>
            ) : null}
            {isSearchEnabled ? (
              <div className={'searchWrapper hiddenMobile navBarUL'}>
                <LoadableComponent collapse={true} indices={searchIndices} />
              </div>
            ) : null}
            <div id="navbar" className={'topnav'}>
              <div className={'visibleMobile'}>
                <Sidebar location={location} />
                <hr />
              </div>
              <ul className={'navBarUL navBarNav navBarULRight'}>
                {headerLinks.map((link, key) => {
                  if (link.link !== '' && link.text !== '') {
                    return (
                      <li key={key}>
                        <a
                          className="sidebarLink"
                          href={link.link}
                          target="_blank"
                          rel="noopener noreferrer"
                          dangerouslySetInnerHTML={{ __html: link.text }}
                        />
                      </li>
                    );
                  }
                })}
                {helpUrl !== '' ? (
                  <li>
                    <a href={helpUrl}>
                      <img src={help} alt={'Help icon'} />
                    </a>
                  </li>
                ) : null}
    
                {tweetText !== '' ? (
                  <li>
                    <a
                      href={'https://twitter.com/intent/tweet?&text=' + tweetText}
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      <img className={'shareIcon'} src={twitter} alt={'Twitter'} />
                    </a>
                  </li>
                ) : null}
                {tweetText !== '' || githubUrl !== '' ? (
                  <li className="divider hiddenMobile"></li>
                ) : null}
                {config.header.social ? (
                  <li className={'hiddenMobile'}>
                    <ul
                      className="socialWrapper"
                      dangerouslySetInnerHTML={{ __html: config.header.social }}
                    ></ul>
                  </li>
                ) : null}
                {githubUrl !== '' ? (
                  <li className={'githubBtn'}>
                    <GitHubButton
                      href={githubUrl}
                      data-show-count="true"
                      aria-label="Star on GitHub"
                    >
                      Star
                    </GitHubButton>
                  </li>
                ) : null}
                <li>
                  <DarkModeSwitch
                    isDarkThemeActive={isDarkThemeActive}
                    toggleActiveTheme={toggleActiveTheme}
                  />
                </li>
              </ul>
            </div>
          </nav>
          <StyledBgDiv isDarkThemeActive={isDarkThemeActive}>
            <div className={'navBarDefault removePadd'}>
              <span
                onClick={myFunction}
                className={'navBarToggle'}
                onKeyDown={myFunction}
                role="button"
                tabIndex={0}
              >
                <span className={'iconBar'}></span>
                <span className={'iconBar'}></span>
                <span className={'iconBar'}></span>
              </span>
            </div>
            {isSearchEnabled ? (
              <div className={'searchWrapper'}>
                <LoadableComponent collapse={true} indices={searchIndices} />
              </div>
            ) : null}
          </StyledBgDiv>
        </div>
      );
    }}

    /> );

    export default Header;

    ===============================================================================

    The only other files that I touched were:

    ANCHOR.JS - deleted target=”_blank” so catch-links works Added STYLES.CSS Updated GlobalStyles.JS

    My Gatsby info is:

    C:\Git\GERS_Genl_Doco>gatsby info

    System: OS: Windows 10 10.0.19043 CPU: (8) x64 Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz Binaries: Node: 14.18.0 - C:\Program Files\nodejs\node.EXE npm: 6.14.15 - C:\Program Files\nodejs\npm.CMD Languages: Python: 3.9.7 Browsers: Edge: Spartan (44.19041.1266.0), Chromium (95.0.1020.44) npmPackages: gatsby: ^4.0.0 => 4.0.0 gatsby-link: ^4.0.0 => 4.0.0 gatsby-plugin-algolia: ^0.19.0 => 0.19.0 gatsby-plugin-catch-links: ^4.0.0 => 4.0.0 gatsby-plugin-emotion: ^7.0.0 => 7.0.0 gatsby-plugin-gtag: ^1.0.13 => 1.0.13 gatsby-plugin-layout: ^3.0.0 => 3.0.0 gatsby-plugin-manifest: ^4.0.0 => 4.0.0 gatsby-plugin-mdx: ^3.0.0 => 3.0.0 gatsby-plugin-offline: ^5.0.0 => 5.0.0 gatsby-plugin-react-helmet: ^5.0.0 => 5.0.0 gatsby-plugin-remove-serviceworker: ^1.0.0 => 1.0.0 gatsby-plugin-remove-trailing-slashes: ^3.4.0 => 3.14.0 gatsby-plugin-sharp: ^4.0.0 => 4.0.0 gatsby-plugin-sitemap: ^5.0.0 => 5.0.0 gatsby-remark-copy-linked-files: ^5.0.0 => 5.0.0 gatsby-remark-images: ^6.0.0 => 6.0.0 gatsby-source-filesystem: ^4.0.0 => 4.0.0 gatsby-transformer-remark: ^5.0.0 => 5.0.0 npmGlobalPackages: gatsby-cli: 4.1.1

    As you can see I run on Windows 10.

    I am hoping someone can guide me to how to fix this.

    Eugene Morrow, New South Wales, Australia

  • emorrow38 commented 2 years ago

    I have corrected my first post so that the images are correct (originally they were not).

    I hope this is enough information for someone to spot the problem.

    emorrow38 commented 2 years ago

    I have spotted a key symptom of this problem: if a folder is mentioned in "forcedNavOrder" in config.js, then the last markdown file in that folder will get Runtime Error. However, if the folder is NOT mentioned in that place, then the last markdown file in that folder displays normally.
    Hopefully this will be enough information for someone to work out what the problem is. Crossing fingers someone works this one out for me !

    emorrow38 commented 2 years ago

    Another key symptom: if you have only one folder everything works, because the last file in the last folder does display. If you have more than one folder, then the last file in each folder gets "Runtime Error" except for the last file in the last folder. All the folders must be mentioned in "forcedNavOrder" of course (in config.js).

    emorrow38 commented 2 years ago

    I have solved my own problem.
    The problem was my coding of forcedNavOrder in config.js. I'm a typical newbie who stuffs up simple things.

    Some sites say to use a folder name. For example, https://joolfe.github.io/gatsby-for-docs/04-publishing-content says this: "sidebar": { "forcedNavOrder": [ "/introduction", "/codeblock" ]

    Other sites say to use a filename. For example, https://githubhelp.com/hasura/gatsby-gitbook-starter says this: forcedNavOrder for left sidebar navigation order. It should be in the format "/"

    So I was using both filenames and foldernames. The files were the "contents topic" for a folder which shows what is in the folder. My coding was similar to:

    sidebar: { forcedNavOrder: [ '/Home', 'Folder_this', '/Folder_this', 'Folder_that', '/Folder_that', etc.

    The result looked good - except he last file in each folder gets a Runtime error.

    The fix was simply to list FOLDERS ONLY as follows:

    sidebar: { forcedNavOrder: [ '/Home', '/Folder_this', '/Folder_that', etc.

    It looks identical to the first attempt - except the last file in each folder displays correctly.

    I am putting this here in case some other newbies get this weird error.

    I would prefer that the internet advice was clear - ONLY USE FOLDER NAMES under forcedNavOrder. I guess there's no accounting for some people meaning folder name when they write "filename:".

    This topic can now be closed.

    emorrow38 commented 2 years ago

    I will reopen for two reasons:

    1. I want to correct my last post.

    I had written: Other sites say to use a filename. For example, https://githubhelp.com/hasura/gatsby-gitbook-starter says this: forcedNavOrder for left sidebar navigation order. It should be in the format "/"

    The site actually says: forcedNavOrder for left sidebar navigation order. It should be in the format "/filename"

    There are < and > around the filename and that gets confused on this site and the "filename" disappears.

    Anyway, the point is that the site said /filename and I would have preferred it said /foldername.

    1. I will allow others to comment. I will understand if they will wonder whether my brain-cell has a companion and I accept it is very lonely a lot of the time.
    emorrow38 commented 2 years ago

    I thought I had reopened this issue. Perhaps there is a delay in this.

    emorrow38 commented 2 years ago

    I think I can finally describe how to code Config.JS in the sections forcedNavOrder and collapsedNav. Remember that to have folders of Markdown topics, there are two things needed:

    1. A new folder under folder "content", say folder ABC. This folder contains Markdown topics.
    2. A Markdown topic that is the "table of contents" for that new folder. This topic is ABC.md (named same as the folder). This topic is in folder "content".

    Here is how to do the coding in Config.js: In forcedNavOrder put: "sidebar: { forcedNavOrder: [ '/ABC', ], " In collapsedNav, put: " collapsedNav: [ '/ABC', ], "

    Obviously we have lots of items between [ and ] and they are spread over multiple lines (cosmetic). Obviously, forcedNavOrder is likely to have /Home as well (which I do). This will not be in collapsedNav.

    What is important is the two sections (forcedNavOrder and collapsedNav) look the same, but the first is referring to the "contents topics" in folder content whereas the second is referring to the folders under content. They look the same because they are named the same way, but that is what I believe is really happening.
    I wish this had been described in the internet sites I looked at about this. I have learned the hard way