Setting up 404 and 500 pages is always part of the overall configuration of a website. You need to have those pages to gracefully and correctly tell the end-user to stop looking for web pages that don’t exist on your site. It proved to be a bit of work in a Sitecore JSS context running with Static Site Generation (SSG) and the multisite plugin.

The issue stems from the getStaticProps call to fetch the site information:

export const getStaticProps: GetStaticProps = async (context) => {
  const site = siteResolver.getByName(config.sitecoreSiteName);
  ...
}

Notice that the siteResolver is fetching the site defined in the confing.sitecoreSiteName. In a multisite setup, however, this will result in incorrectly serving the main site’s 404/500 pages for all of the sites. The correct config attribute to use should be config.sites where the array of site definitions is set during build.

// use the value of config.sites which contains the site definitions of all the sites in the current tenant
const sites = JSON.parse(config.sites) as SiteInfo[];

The next step is to actually fetch the 404/500 page configured on the SXA Site Setting item using the GraphQLErrorPagesService:

if (sites && sites.length) {
  // we need to use regular for-loop here because array iteration methods like map are not aync aware
  for (const site of sites) {

    const errorPagesService = new GraphQLErrorPagesService({
      clientFactory: graphQLClientFactory,
      siteName: site.name,
      language,
      retries:
        (process.env.GRAPH_QL_SERVICE_RETRIES &&
         parseInt(process.env.GRAPH_QL_SERVICE_RETRIES, 10)) ||
         0,
    });

    try {
      // fetch each site's error page settings using the ootb errorPagesService
      const resultErrorPages = await errorPagesService.fetchErrorPages();
      ...
    } catch (error) {
      ...
    }
  }
}

If your page layout makes a GraphQL call to fetch components, you will need to implement an extra step. For example, on our site, the Header and Footer components execute a GraphQL query to fetch all the data needed to render themselves. On a regular page, the component-props.ts plugin runs for component-level data fetching. Because the 404/500 pages are statically generated and does not go through the typical JSS page routing process, you will need to explicitly call the ComponentPropsService to get the complete layout data:

const componentPropsService = new ComponentPropsService();

// we need to use regular for-loop here because array iteration methods like map are not aync aware
for (const site of siteErrorPagePaths) {
  const ctx = context;

  // force context param to use site-specific error page path
  ctx.params = {
    path: [`_site_${site.siteName}`, site.errorPagePath],
  };

  try {
    if (site.layoutData) {
      const componentProps = await componentPropsService.fetchStaticComponentProps({
        layoutData: site.layoutData,
        context,
        moduleFactory,
      });

      if (componentProps) {
        ...
      }
    } 
  } catch (error) {
    ...
  }
}

Here’s the gist of how everything works together: https://gist.github.com/m-are/708a963a7098bd2271ba9c4595007d1f

Posted in , , , ,

Leave a comment