Category Archives: XM Cloud

From FoxPro to Next.js: Embracing a Career of Never-Ending Learning

As I dive deeper into headless technology and frameworks like Next.js, I can’t help but reconsider how much this industry has evolved since I started working. Back in 1998, my career began with a desktop store app written in Visual FoxPro, complete with its own database engine. Visual FoxPro, released in 1995, was a go-to tool for database applications. This was a time when tech books weren’t available, at least not in the Bulgarian market. Learning was all about using the help menu—yes, the help of Visual FoxPro itself. Internet access wasn’t even available at home; we had limited access at the university, and the only search engine was Yahoo, which didn’t have many results.

Maybe the only consistency in my career is MS SQL Server—it’s been around for decades, first released in 1989, and widely used ever since. Today, I have colleagues who weren’t even born when I started. I remember when ASP (Microsoft’s Active Server Pages, introduced in 1996) was the most modern way to build websites. It was fancy for the time! I even remember working with asynchronous calls before they formally called it “AJAX.” It wasn’t until 2005 that the term AJAX was coined by Jesse James Garrett, but we’d been doing similar things before that.

In those days, there were no FEs, QAs, DevOps, PMs, or AMs—none of the abbreviations of today! Learning HTML, CSS, and JavaScript was just part of a normal day.

Enter the CMS Era
The arrival of content management systems (CMS) changed everything. Now, content editors could update content without needing to call us to build or deploy it. My first CMS was Microsoft CMS, released in 2001. This was around 2002, and yes, most of you readers were probably not born yet! I don’t remember all the details, but I worked on a few projects where we built admin portals so clients could manage content themselves. We even started teaching them how to use these tools.

The MVC Revolution
Then came MVC frameworks. Microsoft launched ASP.NET MVC in 2009, and it felt revolutionary to build websites with this kind of structure. It simplified the process, making it easy to manage and pass data through controllers and views. Eventually, we moved from good old web services to REST APIs. REST, introduced by Roy Fielding in 2000, became the standard for web services because it was simpler than SOAP.

Sitecore

Later, I started working with Sitecore, starting with version 6, which was released in 2008. Sitecore was robust, offering tons of features, and it allowed for a lot of customization using C# and API calls. SXA (Sitecore Experience Accelerator) arrived later, in 2016, with predefined components that allowed clients to build pages on their own. So, I learned SXA, variants, and themes—a new level of learning.

The PowerShell module for Sitecore made it easier to handle batches of items around 2012 with the Sitecore PowerShell Extensions (SPE). Then there was TDS (Team Development for Sitecore), and later Unicorn (2014) and Razl, tools that simplified content synchronization between environments. I even learned to write PowerShell scripts to create Windows schedulers that could sync content between environments automatically, letting me sleep while work happened!

Component-Oriented Development and the Cloud
Then Helix design principles were introduced in 2016. This component-oriented approach led to solutions with 60+ projects, making readability and feature management easier. Around the same time, Azure and other cloud platforms started to change how we work. Microsoft Azure launched in 2010, bringing with it managed cloud services. Tools like Application Insights (2014) became necessary for tracking and logging without needing traditional servers.

The Headless Shift and the Rise of Modern JavaScript Frameworks
Then came headless technology and the push to separate frontend and backend development. This shift started around 2015, driven by the need for flexibility in mobile and single-page applications. Now I’m learning Visual Studio Code (released in 2015), Node.js, React (launched by Facebook in 2013), Next.js (launched by Vercel in 2016), Storybook, Vercel, and other tools. React and Next.js are incredibly fast compared to traditional .NET applications, and their modularity aligns perfectly with the headless approach.

AI and the Modern Developer’s Toolkit
In today’s world, we have countless free courses online, and tools like ChatGPT are widely used in our sector. OpenAI launched ChatGPT in late 2022, and by 2023 it became a staple for helping with small tasks, like writing better comments in Jira. While it can handle some trivial tasks, it doesn’t go far beyond the easy level in development yet.

A Never-Ending Learning Curve
So, we keep learning! The learning curve never ends. It doesn’t end with school, university, or an IT crash course. And while many think a few months of training is enough to demand big salaries and think they “know everything,” the truth is—you know nothing, Jon Snow!

How to Create a New Story for the Card Component in Sitecore XM Cloud with Storybook

The Card component is created in my guide on Building Variant Card Components in Sitecore XM Cloud with Next.js.

Storybook is an excellent tool for developing UI components in isolation, and in this post, we’ll walk through creating a new Story for the Card component in your Sitecore XM Cloud Foundation Head project. We will define three different versions of the Card component: Default, Small, and Large, with varying layout sizes and mock data.

If you haven’t set up Storybook yet, check out my previous post on Integrating Storybook with Sitecore XM Cloud Foundation Head for a step-by-step guide.

Step 1: Create a Story File for the Card Component

Inside your Storybook setup, create a new file in your project, following a similar path to where your Card component exists. Typically, you’ll want to place it within a stories or components folder.

Let’s assume your project structure looks like this:

src/  
components/
Card.tsx
stories/
Card.stories.tsx

In Card.stories.tsx, we will define the stories for the Card component using mock data.

Step 2: Import Dependencies and Define Metadata

First, import the necessary modules from Storybook and Sitecore JSS to ensure the component and fields are correctly typed:

import type { Meta, StoryObj } from '@storybook/react'; 
import { CardWithImage as CardImage } from '../components/Card';
import { ImageField, LinkField } from '@sitecore-jss/sitecore-jss-nextjs';
import '../assets/main.scss';

Next, define the metadata (meta) for the Card component, which will be used by Storybook to render the component properly:

 
const meta = {
  component: CardImage,
} satisfies Meta<typeof CardImage>;

export default meta;

This block of code informs Storybook that the CardImage component is the one being used and provides the necessary type checks.

Step 3: Define Story Variants

We’ll now create different versions of the Card component (called “stories”) by passing in mock data. Each story represents a different size of the card (Default, Small, and Large), using mock heading, body, link, and image fields from Sitecore JSS.

Here’s the structure for our Default, Small, and Large stories:

 type Story = StoryObj;
// Default Card
export const Default: Story = {
args: {
params: {
styles: 'col-lg-4', // Custom class for layout
},
fields: {
heading: {
value: 'Sample Heading',
},
body: {
value: 'This is a sample content. You can replace this with your actual content from Sitecore.',
},
link: {
href: 'https://www.example.com',
text: 'Click here to learn more',
} as unknown as LinkField,
image: {
src: 'https://via.placeholder.com/300x200', // Dummy placeholder image
alt: 'Placeholder Image',
} as ImageField,
},
index: 0, // Optional index property
},
};
// Small Card
export const Small: Story = {
args: {
params: {
styles: 'col-lg-3', // Smaller layout
},
fields: {
heading: {
value: 'Sample Heading',
},
body: {
value: 'This is a sample content. You can replace this with your actual content from Sitecore.',
},
link: {
href: 'https://www.example.com',
text: 'Click here to learn more',
} as unknown as LinkField,
image: {
src: 'https://via.placeholder.com/300x200', // Dummy placeholder image
alt: 'Placeholder Image',
} as ImageField,
},
index: 0,
},
};
// Large Card
export const Large: Story = {
args: {
params: {
styles: 'col-lg-6', // Larger layout
},
fields: {
heading: {
value: 'Sample Heading',
},
body: {
value: 'This is a sample content. You can replace this with your actual content from Sitecore.',
},
link: {
href: 'https://www.example.com',
text: 'Click here to learn more',
} as unknown as LinkField,
image: {
src: 'https://via.placeholder.com/300x200', // Dummy placeholder image
alt: 'Placeholder Image',
} as ImageField,
},
index: 0,
},
};

Step 4: Running Storybook

Once your story is defined, you can launch Storybook to visualize the different variants of the Card component. Run the following command in your terminal:

npm run storybook 

Storybook will start on http://localhost:6006. You should see the Card component rendered with three variants: Default, Small, and Large. Each will show a mock card with a heading, body, link, and image.

Integrating Storybook with Sitecore XM Cloud Foundation Head

Storybook is a powerful tool for developing, documenting, and testing UI components in isolation. It can be incredibly useful when working with Sitecore XM Cloud projects. In this guide, I will walk you through integrating Storybook into the Sitecore XM Cloud Foundation Head project.

Prerequisites

Make sure you have the following installed:

  • Node.js (We’ll use NVM to manage Node.js versions)
  • GitHub CLI: Install it using the command below:
  • winget install --id github.cli

After installation, restart your terminal.

Step 1: Manage Node Versions with NVM (Optional)

To ensure you’re using the correct Node.js version, install NVM (Node Version Manager) for Windows.

  1. Download the NVM for Windows installer.
  2. Install the latest Node.js version by running:
  3. nvm install latest
  4. Verify the installation with
  5. node -v

Step 2: Clone the Sitecore Foundation Head Repository

Now, authenticate with GitHub using the CLI and clone the Sitecore XM Cloud Foundation Head repository:

gh auth login
gh repo clone sitecorelabs/xmcloud-foundation-head-dev
cd xmcloud-foundation-head-dev

Step 3: Install Dependencies

In the project directory, install the necessary dependencies:

npm install 

Once dependencies are installed, build and start the project:

npm run build 
npm start

Step 4: Set Up Storybook

Install Storybook CLI

If you don’t already have npx installed globally, do so by running:

npm i -g npx 

Now, initialize Storybook in your project:

npx storybook init 

Step 5: Add Additional Packages

To extend Storybook functionality with additional features, install the following packages:

npm install --save-dev @storybook/addon-actions @storybook/addon-links @storybook/nextjs 

Step 6: Update package.json Scripts

To streamline Storybook’s usage in your project, update the scripts section in your package.json file to include the following commands:

"scripts": {   
"prestorybook": "",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
}

Step 7: Configure TypeScript (If Applicable)

If your project is using TypeScript, you may need to adjust the tsconfig.json file to ensure that Storybook resolves the correct type definitions.

  1. Open tsconfig.json.
  2. Update the compilerOptions section with the following entry:
"compilerOptions": {   
"paths": {
"react": ["node_modules/@types/react"]
}
}

This ensures that Storybook uses the correct React type definitions, which is critical for TypeScript-based projects.

Step 8: Run Storybook

To start Storybook and view your components in an isolated environment, simply run:

npm run storybook 

This will launch Storybook on http://localhost:6006, where you can view and interact with your components in real-time.

Building Variant Card Components in Sitecore XM Cloud with Next.js

As more organizations move towards headless architecture, Sitecore XM Cloud paired with Next.js offers an excellent combination for building modern, scalable websites. One of the key benefits of Sitecore XM Cloud is its ability to dynamically manage content while Next.js provides fast rendering, client-side routing, and flexibility.

In this tutorial, we’ll walk through an example of how to create reusable and dynamic card components in Sitecore XM Cloud using Next.js. We will explore different variations of the same card component: a default card, a static card, and a card with an image.

Prerequisites

To follow along, you need the following:

  • A Sitecore XM Cloud instance with JSS setup.
  • A Next.js application connected to the Sitecore XM Cloud instance.

Step 1: Define the Card Component

First, let’s define a base card component in React. This component will receive fields and params as props, which represent the content data (fields) and the rendering parameters (params) from Sitecore.

Here’s a cleaned-up version of the card component:

import React from 'react';
import { Text, Field, RichText, Image as JssImage, Link as JssLink, ImageField, LinkField } from '@sitecore-jss/sitecore-jss-nextjs';

interface Fields {
  heading: Field<string>;
  body: Field<string>;
  link: LinkField;
  image: ImageField;
  index?: number;
}

export type CardProps = {
  params: { [key: string]: string };
  fields: Fields;
  index: number;
};

const CardDefaultComponent = (props: CardProps): JSX.Element => (
  <div className={`component card ${props.params.styles}`}>
    <div className="component-content">
      <span className="is-empty-hint">Card</span>
    </div>
  </div>
);

This is a simple CardDefaultComponent that acts as a fallback when no data is available. It can be used when fields are missing or in the process of building a card variant.

Step 2: Create the Default Card Variant

In this step, we’ll create a default card variant. The card will render the heading and body from the provided Sitecore fields.

export const Default = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="article-wrapper">
          <article>
            <div className="article-body">
              <h3>
                <Text field={props.fields.heading} />
              </h3>
              <RichText field={props.fields.body} />
            </div>
          </article>
        </div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

In this default card, we are displaying:

  • The heading as an H3 element.
  • The body as rich text (using Sitecore’s RichText component).

Step 3: Create the Static Card Variant

The static card variant will have a structured layout with a header, body, and footer. This variant is useful for cards with a more predefined and fixed structure.

export const Static = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="card-header">
          <Text field={props.fields.heading} />
        </div>
        <div className="card-body">
          <h5 className="card-title">
            <RichText field={props.fields.body} />
          </h5>
          <div className="card-text">
            <RichText field={props.fields.body} />
          </div>
        </div>
        <div className="card-footer">Contact number:</div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

This variant adds a bit more structure by:

  • Displaying a card-header with the heading.
  • Displaying a card-body with the title and body content.
  • Adding a card-footer for additional information.

Step 4: Create the Card with Image Variant

This variant introduces an image, making it useful for cards that require a visual element along with the text content.

export const CardWithImage = (props: CardProps): JSX.Element => {
  const id = props.params.RenderingIdentifier;
  if (props.fields) {
    return (
      <div className={`component card ${props.params.styles}`} id={id ? id : undefined}>
        <div className="article-wrapper">
          <article>
            <figure>
              <JssImage field={props.fields.image} />
            </figure>
            <div className="article-body">
              <h3>
                <Text field={props.fields.heading} />
              </h3>
              <RichText field={props.fields.body} />
              <JssLink field={props.fields.link} className="read-more">
                Read more <span className="sr-only">about <Text field={props.fields.heading} /></span>
                <svg xmlns="http://www.w3.org/2000/svg" className="icon" viewBox="0 0 20 20" fill="currentColor">
                  <path fillRule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clipRule="evenodd" />
                </svg>
              </JssLink>
            </div>
          </article>
        </div>
      </div>
    );
  }
  return <CardDefaultComponent {...props} />;
};

Here we:

  • Add a <figure> to display the image using JssImage from Sitecore.
  • Include a link (JssLink) to allow users to navigate to more detailed content.
  • Use an SVG icon to enhance the link visually.

Step 5: Use the Card Components in the Next.js Application

Once you’ve created these variants, you can now use them within your Next.js application. Sitecore’s JSS platform will allow you to switch between these card components dynamically based on the rendering parameters or content structure defined in Sitecore.

You can map the card component variants to Sitecore renderings and configure them from the Experience Editor. This flexibility enables you to control how each card should appear, giving marketers the ability to swap between card layouts or content effortlessly.

Live demo: https://nona-local.vercel.app/ND-Test-Page

CSS and JS issues when deploying Sitecore XM Cloud to Vercel

When I first started working with XM Cloud and Vercel, I quickly realized how much there was to learn, especially when it came to the specifics of deployment and environment configurations. I followed the official documentation to set up my site and configured Vercel for deployment, but I encountered a frustrating issue: the theme — both the CSS and JavaScript files — wasn’t loading correctly on the user interface. The site looked broken, with no styles or scripts applied, making it impossible to move forward.

After spending some time troubleshooting and scouring the internet for solutions, I came across a very helpful and detailed blog post. It outlined several common pitfalls with deploying to Vercel and how to address them. The problem I was facing was that the assets weren’t loading because the PUBLIC_URL environment variable hadn’t been set properly.

The solution turned out to be simple but effective: I needed to set the PUBLIC_URL environment variable in Vercel and point it to the production deployment URL. Once I made that change, the issue was resolved, and both the CSS and JavaScript files started loading correctly, restoring the site’s appearance and functionality.

This experience highlighted the importance of understanding how environment variables like PUBLIC_URL work in cloud deployments and how they directly affect asset loading, especially when working with tools like Vercel.

My experience preparing for XM Cloud Developer certification exam

I recently took the XM Cloud Developer Certification exam, and I think sharing my experience to the public will help them cover the exam

About the Exam

50 questions for 100 minutes to finish it.

To pass and obtain certification, minimum score of 80% is required

Pre-requisites

This exam is intended for Sitecore XM Cloud developers. You should be familiar with Sitecore Cloud portal and XM Cloud application. It will be good to have some basic experience with Sitecore JSS as well.

Exam Competencies

The exam covers a wide range of topics, including:

  1. XM Cloud Architecture and Developer Workflow – 12%
  2. Deployment of XM Cloud Projects – 16%
  3. Renderings and Layout – 14%
  4. Sitecore Content Serialization – 14%
  5. Sitecore APIs & Webhooks – 10%
  6. XM Cloud Pages – 10%
  7. Security for Developers – 10%
  8. Data Modeling – 14%

How to Prepare for the Exam

  • Sitecore e-learning platform, is where you should start.
  •  XM Cloud documentation for developers contains detailed information for each topic.
  • If possible, spend time on XM Cloud portal to navigate trhough different sections, to understand each topic in real exams
  • Sitecore Videos are in a great help.
  • I’ve generated 81 different questions with possible answers and created Google Forms with them. I’ve divided the questions by competency so each colleague can test specific areas, rather than answering all the questions. If you would like to test your competencies, send me a message, and I will provide you with the link to the form.

Sitecore Headless Workshop: Exploring JSS, React, and Best Practices

Recently, December 12, 2023, I organized a Sitecore Headless workshop for our team, focusing on JavaScript Services (JSS) and React. My colleague led the session, presenting key concepts and practical insights into Sitecore’s headless architecture. It was an excellent opportunity for anyone looking to learn more about the flexibility and power of a headless CMS, and how JSS can transform Sitecore development.

  1. JSS and React
  2. Benefits of Using JSS React with Sitecore
  3. Headless CMS Concept
  4. Scalability and Flexibility
  5. Real-world Examples Q&A Session

You can see some photos here.