Sitecore XM Cloud Development Guide

Sitecore XM Cloud | A Frontend Developer's Complete Guide

Published:

Sitecore XM Cloud: A Frontend Developer’s Complete Guide

Welcome to this comprehensive guide on Sitecore XM Cloud development from a frontend perspective. This article will walk you through everything you need to know to get started with Sitecore XM Cloud using Next.js, from basic setup to advanced implementation techniques.

Understanding Sitecore XM Cloud

Sitecore XM Cloud represents the next evolution in content management systems, offering a cloud-native, headless CMS solution. As a frontend developer, you’ll be working with:

Why Next.js with Sitecore XM Cloud?

The combination of Sitecore XM Cloud and Next.js offers several advantages:

Getting Started

Project Setup

First, let’s create a new Next.js project with Sitecore JSS integration:

# Create new Next.js project
npx create-next-app@latest my-sitecore-project --typescript

# Install Sitecore JSS
npm install @sitecore-jss/sitecore-jss-nextjs

### Essential Dependencies

Your `package.json` should include these core dependencies:

```json
{
  "dependencies": {
    "@sitecore-jss/sitecore-jss-nextjs": "^21.0.0",
    "next": "^13.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "graphql": "^16.0.0"
  }
}

Project Structure

A well-organized Sitecore XM Cloud project follows this structure:

├── src/
│   ├── components/
│   │   ├── Layout/
│   │   └── Navigation/
│   ├── lib/
│   │   └── api.ts
│   ├── pages/
│   │   ├── _app.tsx
│   │   ├── [[...path]].tsx
│   │   └── api/
│   └── sitecore/
│       ├── definitions/
│       └── typings/
├── sitecore.config.js
└── next.config.js

Configuration Setup

Next.js Configuration

Create a next.config.js file:

const jssConfig = require("./sitecore.config.js");

module.exports = {
  images: {
    domains: [process.env.NEXT_PUBLIC_SITECORE_DOMAIN],
  },
  publicRuntimeConfig: {
    sitecoreApiKey: process.env.SITECORE_API_KEY,
    sitecoreApiHost: process.env.NEXT_PUBLIC_SITECORE_API_HOST,
  },
};

Environment Configuration

Create a .env.local file:

NEXT_PUBLIC_SITECORE_API_HOST=https://your-instance.sitecorecloud.io
SITECORE_API_KEY=your-api-key
JSS_EDITING_SECRET=your-editing-secret

Component Development

Creating a Basic Layout Component

import { LayoutServiceData, SitecoreContext } from '@sitecore-jss/sitecore-jss-nextjs';

interface LayoutProps {
  layoutData: LayoutServiceData;
}

const Layout: React.FC<LayoutProps> = ({ layoutData }) => {
  return (
    <SitecoreContext layoutData={layoutData}>
      {/* Your layout content */}
    </SitecoreContext>
  );
};

export default Layout;

Working with Placeholders

import { Placeholder } from '@sitecore-jss/sitecore-jss-nextjs';

const ContentBlock: React.FC = () => {
  return (
    <div>
      <Placeholder name="content" rendering={rendering} />
    </div>
  );
};

JSS Components Examples

Basic JSS Components

Τα JSS Components είναι ο θεμελιώδης τρόπος δημιουργίας επαναχρησιμοποιήσιμων στοιχείων στο Sitecore XM Cloud. Ας δούμε μερικά βασικά παραδειγματα:

1. Text Component

import { Text, Field, withDatasourceCheck } from '@sitecore-jss/sitecore-jss-nextjs';

interface TextComponentProps {
  fields: {
    heading: Field<string>;
    content: Field<string>;
  };
}

const TextComponent: React.FC<TextComponentProps> = ({ fields }) => {
  return (
    <div className="text-component">
      <h2><Text field={fields.heading} /></h2>
      <div><Text field={fields.content} /></div>
    </div>
  );
};

export default withDatasourceCheck()(TextComponent);
  1. Rich Text Component
import { RichText, Field } from '@sitecore-jss/sitecore-jss-nextjs';

interface RichTextComponentProps {
  fields: {
    content: Field<string>;
  };
}

const RichTextComponent: React.FC<RichTextComponentProps> = ({ fields }) => {
  return (
    <div className="rich-text">
      <RichText field={fields.content} />
    </div>
  );
};

export default RichTextComponent;
  1. Image Component με Advanced Features
import { Image, withDatasourceCheck } from '@sitecore-jss/sitecore-jss-nextjs';

interface ImageComponentProps {
  fields: {
    image: ImageField;
    caption: Field<string>;
  };
}

const ImageComponent: React.FC<ImageComponentProps> = ({ fields }) => {
  return (
    <div className="image-wrapper">
      <Image
        field={fields.image}
        editable={true}
        imageParams={{ mw: 800 }}
        height={400}
        width={800}
      />
      {fields.caption && (
        <p className="caption">
          <Text field={fields.caption} />
        </p>
      )}
    </div>
  );
};

export default withDatasourceCheck()(ImageComponent);
  1. Navigation Component
import { Link, Text, LinkField } from '@sitecore-jss/sitecore-jss-nextjs';

interface NavigationProps {
  fields: {
    items: {
      fields: {
        link: LinkField;
        title: Field<string>;
      };
    }[];
  };
}

const Navigation: React.FC<NavigationProps> = ({ fields }) => {
  return (
    <nav className="navigation">
      <ul>
        {fields.items.map((item, index) => (
          <li key={index}>
            <Link field={item.fields.link}>
              <Text field={item.fields.title} />
            </Link>
          </li>
        ))}
      </ul>
    </nav>
  );
};

export default Navigation;
  1. Composite Component
import { Placeholder, withPlaceholder } from '@sitecore-jss/sitecore-jss-nextjs';

interface CompositeComponentProps {
  rendering: ComponentRendering;
}

const CompositeComponent: React.FC<CompositeComponentProps> = ({ rendering }) => {
  return (
    <div className="composite-component">
      <div className="header">
        <Placeholder name="header" rendering={rendering} />
      </div>
      <div className="content">
        <Placeholder name="content" rendering={rendering} />
      </div>
      <div className="footer">
        <Placeholder name="footer" rendering={rendering} />
      </div>
    </div>
  );
};

export default withPlaceholder(['header', 'content', 'footer'])(CompositeComponent);

Data Handling

Static Props Generation

import { GetStaticProps } from "next";
import {
  SitecorePageProps,
  handleGetStaticProps,
} from "@sitecore-jss/sitecore-jss-nextjs";

export const getStaticProps: GetStaticProps = async context => {
  try {
    const props = await handleGetStaticProps(context);
    return props;
  } catch (error) {
    return { notFound: true };
  }
};

GraphQL Integration

const query = `
  query PageQuery($path: String!, $language: String!) {
    site {
      siteInfo {
        name
      }
    }
  }
`;

Experience Editor Integration

Editable Components

import { EditingComponentPlaceholder } from '@sitecore-jss/sitecore-jss-nextjs';

const EditableComponent: React.FC = () => {
  return (
    <EditingComponentPlaceholder
      rendering={rendering}
      fields={fields}
    />
  );
};

Performance Optimization

Image Optimization

import Image from 'next/image';

const OptimizedImage: React.FC = () => {
  return (
    <Image
      src={imageUrl}
      width={800}
      height={600}
      alt="Description"
      priority
    />
  );
};

SEO Implementation

import Head from 'next/head';

const SEOComponent: React.FC = ({ metadata }) => {
  return (
    <Head>
      <title>{metadata.title}</title>
      <meta name="description" content={metadata.description} />
    </Head>
  );
};

Deployment Considerations

When deploying your Sitecore XM Cloud application, follow these steps:

  1. Build your Next.js application:
npm run build
  1. Configure your Vercel deployment:
{
  "build": {
    "env": {
      "NEXT_PUBLIC_SITECORE_API_HOST": "@sitecore_api_host",
      "SITECORE_API_KEY": "@sitecore_api_key"
    }
  }
}

Testing Strategy

Jest Configuration

module.exports = {
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
  testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
};

Component Testing

import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('renders correctly', () => {
    render(<MyComponent />);
    expect(screen.getByRole('heading')).toBeInTheDocument();
  });
});

Best Practices

  1. TypeScript Integration

    • Use TypeScript for better type safety and developer experience
    • Implement strict type checking
    • Create custom type definitions for Sitecore components
  2. Performance Optimization

    • Implement code splitting
    • Use Next.js Image optimization
    • Implement caching strategies
    • Utilize incremental static regeneration
  3. Development Workflow

    • Use Sitecore CLI for automation
    • Implement continuous integration
    • Regular dependency updates
    • Code review practices

Troubleshooting Common Issues

  1. GraphQL Query Issues

    • Verify query syntax
    • Check field permissions
    • Validate API endpoints
  2. Layout Service Errors

    • Verify route configuration
    • Check authentication
    • Validate environment variables
  3. Experience Editor Problems

    • Verify editing mode configuration
    • Check component rendering
    • Validate placeholder settings

Resources and Documentation

Conclusion

Sitecore XM Cloud with Next.js provides a powerful platform for creating modern web applications. By following this guide, you now have the foundation needed to build robust, scalable, and performant applications. Remember to stay updated with the latest Sitecore and Next.js developments, as both platforms continue to evolve rapidly.

Keep coding, keep learning, and most importantly, enjoy building great experiences with Sitecore XM Cloud!

Code with passion, create with purpose!