One of our projects these days is all the rage (well mostly). A Headless SXA build using Experience Edge and Vercel NextJS. Learning curves aside, the project has been pretty fun. Lots of new things to figure out, problems so solve, workarounds to do… it’s a treat (not sarcastically)

One thing we ran into while enabling Static Site Generation (SSG not to be confused with TNG) at build, was that it looked like Vercel was trying to SSG our pages in the /tenant/site/Presentation/Page Branches/ folder. Which, if you’re using those…they should not be rendered. They don’t exactly have a relative home node and any type of logic is likely going to break. They’re templates, really. Not for human consumption! (ok that was dramatic)

Here’s what we saw in our build logs:

So, where does that come from? Well, from Edge. Something in our Edge Connector was publishing these routes, and we could easily find them by running the following edge query:

query SiteConfigurationQuery {
    site {
      siteInfoCollection {
        name,
        pageInfo {
            endCursor
            hasNext
          }
        routes(language:"en", first: 20, after:"") {
          results {
            routePath  
          }
        }
      }
    }
  }

The results were found on page two of that, we saw the following:

There’s a few ways to fix this:

  1. De-compile the Edge Connector to figure out how to exclude those items. This is probably going to be a long-solve and possibly break our Edge Connector updates…not fun
  2. Tell the NextJS app to skip those items and just move on. Nothing to see here.

Choice 2 was the fairly obvious choice here. Now, to start digging! NextJS uses something call getStaticPaths to determine which set of URLs need to be generated at build time. I won’t go into the deets on all this, but you can check it out inside the /<your app>/src/pages/[[…path]].tsx file. It looks something like this:

let paths: StaticPath[] = [];
let fallback: boolean | 'blocking' = 'blocking';

if (
  process.env.NODE_ENV !== 'development' &&
  !process.env.DISABLE_SSG_FETCH
) {
  try {
    // Note: Next.js runs export in production mode
    paths = await sitemapFetcher.fetch(context);
  } catch (error) {
    // eslint-disable-next-line no-console
    console.log('Error occurred while fetching static paths');

    // eslint-disable-next-line no-console
    console.log(error);
  }

  fallback = process.env.EXPORT_MODE ? false : fallback;
}

return {
  paths,
  fallback,
};

Line 10 is where the magic happens. This sitemapFetcher (not to be confused with XML Sitemap, or if you’re building a website in 2007, the HTML Sitemap). This executes a graph query similar to what we have above. Making sense? So what we’re going to do is put a filter in, essentially.

One thing to note is the type that comes back is array of StaticPath, which is something like this: (path: string[], language: string) where a StaticPath is an array of URL segments, and a language code. So your url of “/about-us/we-are-super-honest-for-real” in English is going to have a path array with three elements in it, and a language string of “en”. Why three, and not two? The first element is the Site Name, typically in a “_site_SITENAME” format. Ok, now how to filter?

if (
  process.env.NODE_ENV !== 'development' &&
  process.env.DISABLE_SSG_FETCH === 'false'
) {
  try {
    let dirtyPaths: StaticPath[] = [];

    dirtyPaths = await sitemapFetcher.fetch(context);

    dirtyPaths.forEach((p) => {

      //Sitename first, first segment after
      if (p.params.path.length > 1) {
        if (p.params.path[1].toLocaleLowerCase() === 'presentation') {
          // eslint-disable-next-line no-console
          console.log(
            `Purging Presentation Route: ${p.params.path.join('/')}`
          );

          return;
        }
      }

      paths.push(p);
    });
  } catch (error) {
    // eslint-disable-next-line no-console
    console.log('Error occurred while fetching static paths');

    // eslint-disable-next-line no-console
    console.log(error);
  }

  fallback = process.env.EXPORT_MODE ? false : fallback;
}

return {
  paths,
  fallback,
};

The real meat here is using a dirtyPaths to store and then iterate. If our array has more than one (because all items will have one) and if the first item is “presentation” then we skip it. Otherwise we move on. You *may* need to do more checking if your site actually has a page named Presentation in the root level. Check this out 🙂

So many life lessons.

Next time you build, you should see quite a few “Purging Presentation” lines from the log file, and no errors! Everyone wins! Even you, Dave…