Content Insights Tip #57 | Run preview environment multi stage

 

Content Insights Logo

When working with Sitecore XM Cloud, you have the flexibility to host your head application on various hosting providers. Among these, Vercel stands out with its array of developer-friendly features. One notable feature is its automatic generation of preview deployments for each pull request. This means your entire team can quickly assess changes and ensure everything is functioning correctly without the need to maintain multiple environments separately, thus saving time and resources.

Moreover, a significant advantage of this setup is the ability to seamlessly switch between different sites within Vercel using just one URL. By simply appending "?sc_site=[enter site name]" to the URL, the head application automatically switches. Behind the scenes, the Sitecore multisite plugin checks the provided site name and orchestrates the switch while setting the necessary "sc_site" cookie to inform the head application which site to load.

Now armed with this knowledge, you can effortlessly navigate between any available sites within your Sitecore instance. However, one drawback is the requirement to know which sites are accessible. To address this, I devised a straightforward yet effective solution.

Introducing the "SiteSelection" component—a simple yet powerful tool I developed. This component fetches the list of available site names from an environment variable and presents them in a dropdown menu. With this intuitive interface, anyone can easily select the desired site, eliminating the need for manual URL adjustments and streamlining the process of switching between sites. This enhancement not only saves time but also reduces the potential for errors, ensuring a smoother development experience for all involved.

Here is an example of that code:

import { ChangeEvent } from 'react';

const SitecoreSiteKey = 'sc_site';

type SiteSelectionProps = {
  isFeatureEnabled: boolean;
  currentSitecoreSite: string;
  sites: string[];
};

export default function SiteSelection() {
  const props = initializeProps();

  return (
    <>
      {props.isFeatureEnabled ? (
        <div
          style={{
            position: 'absolute',
            zIndex: '9999',
            right: '20px',
            top: '20px',
            background: 'rgba(0, 0, 0, 0.2)',
            padding: '20px',
          }}
        >
          <select title="Site selection" value={props.currentSitecoreSite} onChange={handleChange}>
            {props.sites.map((site) => (
              <option key={site} value={site}>
                {site}
              </option>
            ))}
          </select>
        </div>
      ) : (
        <></>
      )}
    </>
  );
}

function handleChange(event: ChangeEvent<HTMLSelectElement>): void {
  event.preventDefault();
  window.location.href = `${window.location.origin}?${SitecoreSiteKey}=${event.target.value}`;
}

function initializeProps(): SiteSelectionProps {
  const isFeatureEnabled = process.env.NEXT_PUBLIC_FEATURE_SITE_SELECTION_ENABLED === 'true';
  const currentSitecoreSite = getCookie(SitecoreSiteKey) || '';

  let sites = [];
  try {
    if (process.env.NEXT_PUBLIC_SITES_LIST != undefined) {
      sites = JSON.parse(process.env.NEXT_PUBLIC_SITES_LIST);
      sites.sort();
    }
  } catch {}

  return {
    isFeatureEnabled,
    currentSitecoreSite,
    sites,
  };
}

function getCookie(name: string): string | null {
  try {
    // Check if the environment supports document object
    if (typeof document === 'undefined') {
      console.error('The document object is not available.');
      return null;
    }

    // Extract cookie value
    const cookieValue = document.cookie
      .split(';')
      .map((cookie) => cookie.trim())
      .find((cookie) => cookie.startsWith(`${name}=`));

    if (cookieValue) {
      return cookieValue.split('=')[1];
    } else {
      console.warn(`Cookie '${name}' not found.`);
      return null;
    }
  } catch (error) {
    console.error('An error occurred while reading the cookie:', error);
    return null;
  }
}


The code relies on two environment settings:
  1. NEXT_PUBLIC_FEATURE_SITE_SELECTION_ENABLED - this is the feature flags that enables this component. We don't want to render this component on a production URL. By default the component will not render itself.
  2. NEXT_PUBLIC_SITES_LIST - this is an array of sites (names) that are available on the XM Cloud instance. 
The component is generated at the top right as drop down. See the image for an example:
Site Selection example


Hope this helps you create a good XM Cloud experience. Until next time!