My new blog present here.

Featured Post

Insights into Sitecore Search: A Definitive Introduction

A key component of digital experience management is effective information retrieval. A simplified approach is required for websites, applications, and platforms containing a lot of material so that consumers can easily get the data they require. This need is met by Sitecore, a well-known name in the field of digital experience platforms (DXPs), which provides powerful and comprehensive search functionality. We will travel into the realm of Sitecore Search in this article, learning about its capabilities, architecture , and the enormous value it offers both developers and end users. Introduction to Sitecore Search    A headless content discovery platform powered by AI , Sitecore Search enables you to build predictive and custom search experiences across various content sources. To extract and index you

Building a Non-Sitecore Page with Sitecore JSS and NextJS: A Step-by-Step Guide

As the world of web development continues to evolve, dynamic sites have become increasingly popular for their ability to provide a more engaging and interactive user experience. There are numerous cases where we need to consume data from external sources (e.g., third party api) to display in the Sitecore Next.js based application where pages are not present in the Sitecore Content Tree.

In this tutorial, I will be focusing on building of Non-Sitecore Page and it’s Page Layout with Sitecore JSS and NextJS, and will be passing existing Sitecore NextJS components from the Non-Sitecore page to the Page Layout to render.
Introduction to Sitecore JSS and NextJS
Sitecore JSS is a headless CMS that provides developers with a way to build dynamic sites using React components. NextJS, on the other hand, is a React framework that provides server-side rendering and other performance optimizations.

By combining Sitecore JSS and NextJS, developers can build dynamic sites that are optimized for performance and user experience.

In this tutorial, I will be providing a step-by-step guide on how to build a NextJS page and it's layout, and reuse of existing components on Non-Sitecore Pages (NextJS page).
Understanding the basics of Sitecore JSS Pages
In Next.js, a page is a React component that is used to define the content and behavior of a specific route in your application. Next.js have pages in the form of physical files which are stored in the /pages directory.

The Sitecore JSS uses the Next.js routing system and all route related to Sitecore JSS application defined in the file /src/pages/[[...path]].tsx and this route helps Sitecore JSS framework to render Pages which are created in Sitecore.

Here are some key things to know about Sitecore JSS pages:
  • Pages are defined in JSON format: In Sitecore JSS, pages are defined as JSON objects that contain the data and metadata for a specific route in your application. The JSON object can contain fields, components, placeholders, and other data that define the content and presentation of the page
  • Sitecore JSS pages are created in the Sitecore content tree using a special page template. The page template contains fields and components that correspond to the JSON object structure for the page. When a JSS app requests a page, Sitecore retrieves the JSON object for the page and sends it back to the app
  • Pages can be created using a variety of data sources: Sitecore JSS pages can be created using data from a variety of sources, including Sitecore content, external APIs, and custom data sources. This allows developers to create dynamic and personalized pages that incorporate data from multiple sources
  • Pages can be enhanced with custom components: Sitecore JSS pages can be enhanced with custom components created using the JavaScript framework of your choice. These components can be shared across multiple pages to provide a consistent look and feel to your application
  • Pages can be previewed and published using Sitecore: Sitecore JSS pages can be previewed and published using the Sitecore Experience Editor and Content Editor. This allows content authors to create and manage JSS pages alongside traditional Sitecore content  
Understanding the basics of NextJS Pages
Next.js is a popular React-based framework for building server-side rendered (SSR) web applications. Here are some important things to know about Next.js pages:
  • By default all Pages in a Next.js application are located in the /pages directory. Each page should have its own file with a unique name that matches the name of the route it represents. For example, the page for the /about route should be named about.js or about.tsx
  • Pages are automatically routed: Next.js automatically routes URLs to the appropriate page based on the file name in the /pages directory. For example, a URL of /about will automatically route to the about.js or about.tsx file in the /pages directory
  • Pages can be dynamic: Next.js allows you to create dynamic routes by using square brackets [ ] in the page file name. For example, a page file named posts/[foo].js would match any URL that starts with /posts/ followed by a variable foo. You can then access the value of the foo as a parameter in the getStaticProps() or getServerSideProps() function
  • Pages can have different export functions: In addition to the default export of the page component, Next.js allows you to export other functions such as getStaticProps(), getServerSideProps(), and getStaticPaths(). These functions can be used to fetch data or specify dynamic routes for the page
  • Pages can be enhanced with additional components: Next.js pages can be enhanced with additional React components such as layout components, navigation components, and footer components. These components can be shared across multiple pages to provide a consistent look and feel to your application  
Overall, Next.js pages provide a powerful and flexible way to define the content and behavior of your application routes. By using the built-in routing and dynamic route features of Next.js, you can easily create complex and dynamic web applications with minimal configuration.
Steps to build a Non-Sitecore page and it’s Page Layout in Sitecore JSS NextJS Application
Sitecore JSS is a headless CMS that provides developers with a way to build dynamic sites using React components.

Sitecore JSS provides several benefits, including the ability to build dynamic sites quickly and easily, the ability to reuse components across multiple sites, and the ability to integrate with other Sitecore features and services.

Sitecore JSS uses the NextJS file-based routing system, so we can build pages which are not coming from Sitecore in the Sitecore NextJS application code base by creating the required page inside the Pages directory. When a file is added to the pages directory, it's automatically available as a route.

To create a Non-Sitecore JSS page and it’s Page Layout, you would typically follow these steps:
  • Go to the pages directory in the Sitecore NextJS project code at Website\src\rendering\src\ and create the integrations folder:  
    Here I am trying to create page hierarchy so created the integrations folder otherwise you can directly create page inside the pages directory/folder directly, e.g., the page for the /about route can be created as about.js or about.tsx.
  • Create the Website\src\rendering\src\pages\integrations\index.tsx file which will handle the route /integrations
    ├── src                 
       ├── pages
    	├── integrations
    		├── index.tsx     
    
    The integrations page is NextJS Page so it will not be using Layout which are defined at Website\src\rendering\src\Layout.tsx for Sitecore pages.
  • In Next.js, a page layout is typically defined as a React component that wraps the actual page component. The layout component can then include common elements such as a header, footer, navigation, or any other component that you want to include on every page.
    Create the folder NonSitecorePageLayout at Website\src\rendering\src\layouts\ to store the Layout for Non-Sitecore Page
  • Create the index.ts and NonSitecorePageLayout.tsx file inside the folder Website\src\rendering\src\layouts\NonSitecorePageLayout\, and these file will be used to create the skeleton of NextJS Layout page:
    The details of Website\src\rendering\src\layouts\NonSitecorePageLayout\index.ts file
    export { NonSitecorePageLayout as default } from "./NonSitecorePageLayout"
    

    This page is using NonSitecorePageLayout.tsx which contains the structure of Layout page. With this way we can define other layout components and include in the layout page.
  • The details of NonSitecorePageLayout.tsx file
    import Footer, { FooterProps } from "components/Navigation/Footer"
    import MainNavigation, { MainNavigationProps } from "components/Navigation/MainNavigation"
    import Head from "next/head"
    import React, { FC } from "react"
    
    
    type PageLayoutProps = {
      title?: string
    }
    
    export const NonSitecorePageLayout: FC<PageLayoutProps> = (props): JSX.Element => {
      const footerProps = {
        fields: {
          data: {
            item: {
              footerLogo: {},
            },
            links: {
              displayName: 'Footer',
              children: {
                results: [
                  {
                    displayName: 'Follow Us',
                    children: {
                      results: [
                        {
                          displayName: 'Facebook',
                          icon: { value: 'faFacebookF' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Youtube',
                          icon: { value: 'faYoutube' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Twitter',
                          icon: { value: 'faTwitter' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Instagram',
                          icon: { value: 'faInstagram' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Linkedin',
                          icon: { value: 'faLinkedin' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                      ],
                    },
                  },
                  {
                    displayName: 'PLAY! Summit',
                    children: {
                      results: [
                        {
                          displayName: 'Home',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{68DC89A4-1B04-59A8-9C4E-3B49D6C61052}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'Sessions',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/sessions',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{68DC89A4-1B04-59A8-9C4E-3B49D6C61052}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'Speakers',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/speakers',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{1F4B781B-F2A5-5647-99DF-C0C369162C4D}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'Vendors',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/vendors',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{774E44E8-0F30-5879-B847-AD233FFB41AA}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'Sponsors',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/sponsors',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{66C99E47-7BBF-52D1-B1D7-4662B850744A}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'About Us',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/about-us',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{2717574C-48A0-5469-85A8-A332DF71F1E4}',
                              },
                            },
                          },
                        },
                        {
                          displayName: 'News',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: {
                              value: {
                                href: '/en/news',
                                text: '',
                                anchor: '',
                                linktype: 'internal',
                                class: '',
                                title: '',
                                target: '',
                                querystring: '',
                                id: '{0E4A63DA-7496-557E-BF80-5BD52255E431}',
                              },
                            },
                          },
                        },
                      ],
                    },
                  },
                  {
                    displayName: 'Join Us',
                    children: {
                      results: [
                        {
                          displayName: 'Book Tickets',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Become a Sponsor',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Become a Vendor',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                      ],
                    },
                  },
                  {
                    displayName: 'Get Support',
                    children: {
                      results: [
                        {
                          displayName: 'FAQ',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                        {
                          displayName: 'Tech Support',
                          icon: { value: '' },
                          title: { value: '' },
                          field: {
                            jsonValue: { value: { href: '' } },
                          },
                        },
                      ],
                    },
                  },
                ],
              },
            },
          },
        },
      } as unknown as FooterProps;
    
      const mainNavProps = {
        fields: {
          data: {
            item: {
              id: '4790380A3F0C443AA954269ECB2D5566',
              path: '/sitecore/content/EdgeWebsite/Data/Config',          
              headerLogo: {
                jsonValue: {
                  value: {
                  mediaid:'',
                  thumbnailsrc: 'https://playsummit.sitecoresandbox.cloud/api/gateway/30940/thumbnail',
                  src: 'https://playsummit.sitecoresandbox.cloud/api/public/content/83a458a1cb54401cab2308488bbd1031?v=bdb6447b&t=web',
                  alt: 'PLAY! Summit logo - stacked light grey',
                  height: '113',
                  width: '274'
                }              
                },
                alt: 'PLAY! Summit logo - stacked light grey'
              },
            },
            links: {
              displayName: 'Main Navigation',
              children: {
                results: [
                  {
                    displayName: 'Sessions',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/sessions',
                          class: '',
                          id: '{68DC89A4-1B04-59A8-9C4E-3B49D6C61052}',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'internal',
                          text: ''
                        }
                      }
                    }
                  },
                  {
                    displayName: 'Speakers',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/speakers',
                          class: '',
                          id: '{1F4B781B-F2A5-5647-99DF-C0C369162C4D}',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'internal',
                          text: ''
                        }
                      }
                    }
                  },
                  {
                    displayName: 'Vendors',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/vendors',
                          class: '',
                          id: '{774E44E8-0F30-5879-B847-AD233FFB41AA}',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'internal',
                          text: ''
                        }
                      }
                    }
                  },
                  {
                    displayName: 'Sponsors',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/sponsors',
                          class: '',
                          id: '{66C99E47-7BBF-52D1-B1D7-4662B850744A}',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'internal',
                          text: ''
                        }
                      }
                    }
                  },
                  {
                    displayName: 'About Us',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/about-us',
                          class: '',
                          id: '{2717574C-48A0-5469-85A8-A332DF71F1E4}',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'internal',
                          text: ''
                        }
                      }
                    }
                  },
                  {
                    displayName: 'Integrations',
                    field: {
                      jsonValue: {
                        value: {
                          href: '/integrations',
                          class: '',
                          id: '',
                          querystring: '',
                          anchor: '',
                          target: '',
                          title: '',
                          linktype: 'external',
                          text: ''
                        }
                      }
                    }
                  }              
                ]
              }
            },
          },
        },
      } as unknown as MainNavigationProps;
    
      return (
        <>
          <Head>
            <link rel="icon" href="/favicon.ico" />
            <title>{props.title || "Play! Summit"}</title>
          </Head>
          <header>
            <MainNavigation {...mainNavProps}/>
          </header>      
            {props.children}
          <footer>
            <Footer {...footerProps} />
          </footer>
        </>
      )
    }
    
    In this file we have defined the page structure of the page including the use of common components like header and footer so that it will be available to all pages who will be using this layout:  
  • Now go back to the integration page (Website\src\rendering\src\pages\integrations\index.tsx) created in step-2 and use the newly created layout  
    import Section, { SectionProps } from 'components/PageContent/Section';
    import NonSitecorePageLayout from 'src/layouts/NonSitecorePageLayout';
    import sectionJsonContent from '../../staticData/sectionComponents.Data.Integrations.Page.json';
    
    const Integrations = (): JSX.Element => {
      return (
        <>
        </>
      );
    };
    
    Integrations.getLayout = function getLayout() {
      const sectionData = {
        fields:sectionJsonContent
      } as unknown as SectionProps;
    
      return (
        <NonSitecorePageLayout
        title="Integrations"
      >
        <Section {...sectionData}/>
        
      </NonSitecorePageLayout>    
      );
    };
    
    export default Integrations;
    
    Here we are using Next.js, getLayout function that allows you to dynamically set the layout for a specific page or group of pages. This allows you to define the layout on a per-page basis, so its also called as Per-Page Layouts.

    The getLayout function is typically defined in a layout component and returns the layout component with any additional props that you want to pass down to the children components. Here's an example:  
    // components/Layout.js
    
    const Layout = ({ children }) => {
      return (
        <div>
          <Header />
          <main>{children}</main>
          <Footer />
        </div>
      )
    }
    
    const getLayout = page => {
      return (
        <Layout>
          {page}
        </Layout>
      )
    }
    
    export default Layout
    export { getLayout }
    
    In this page, we are using layout component and passing the layout properties and component to layout component so that it will render inside the layout  
    The static data for Section component defined at Website\src\rendering\src\staticData\sectionComponents.Data.Integrations.Page.json  
    {
      "brightness": {
        "value": "light"
      },
      "callToActionLink": {
        "value": {
          "href": ""
        }
      },
      "content": {
        "value": "<p class=\"font-bold\">\r\nThis page will show the listing of different types of integrations on non-Sitecore pages\r\n</p>"
      },
      "cssClass": {
        "value": "left-full"
      },
      "title": {
        "value": "This page is non-Sitecore Page"
      }
    }
    
  • The output of the Non-Sitecore page /integrations ( Website\src\rendering\src\pages\integrations\index.tsx) https://www.edge.localhost/integrations  
Summary
By following the above listed steps, you can create the pages for your Sitecore NextJS application which are not part of your Sitecore Content Tree.

The Sitecore JSS and NextJS framework provides flexibility to extend your Layout and Pages as per your need to build a dynamic Sitecore JSS website which can provide numerous benefits, including improved performance, scalability, and user experience.

If you’re interested in learning more about Sitecore JSS and NextJS, be sure to check out the resources listed above and this blog site.  

The code base present at the GitHub branch


Credit/References:

Creating a JSS Next.js application with the JSS CLI Connecting a Next.js JSS app to Sitecore editors Preparing the list of pages for static generation or export in
Routing and page composition in JSS Next.js apps Connecting a code-first JSS Next.js application to Sitecore Creating a new component in a JSS Next.js app using
Architecture and APIs for integrating JSS Next.js apps Prefetch Sitecore data with React Query NextJS Image Basic Features: Image Optimization
nextConfig issue while building or running the project how to add domains to next.config.js for "next/image" while using a plugin nextConfig issue while building or running the project
Content Creation using ChatGPT OpenAI
How to Create Pages in Next.js? NextJS Pages NextJS Page Layouts 
Sitecore NextJS Component Refactoring and Reusability Routing and page composition in JSS Next.js apps Sitecore PLAY! Summit Demo Edge – GitHub

Pingback:
sitecore next.js sitecore jss nextjs sitecore jamstack 
sitecore nextjs sample website sitecore jss dynamic placeholder sitecore-jss-nextjs github
Creating a JSS Next.js application with the JSS CLI The Sitecore Containers template for JSS Next.js apps Connecting a code-first JSS Next.js application to Sitecore
Setting up a development environment with the Sitecore Containers template for Next.js Jamstack for Sitecore JSS using Next.js with Uniform SDK Sitecore JavaScript Rendering SDK (JSS) for Next.js 
Prerendering methods and data fetching strategies in JSS Next.js apps Architecture and APIs for integrating JSS Next.js apps with Sitecore editors Getting started with JSS for Next.js development
Query examples - Sitecore Documentation Start using Sitecore GraphQL API - Sitecore Documentation Sitecore Experience Edge 
next.js sitecore sitecore node js next js sitecore
next.js sample project sitecore query examples sitecore jss quick start
unit test next js sitecore nvelocity sitecore 9 exam questions and answers
nextjs best practices github next js folder structure best practices nextjs api best practices 
next js logging best practices next js styling best practices next js tips
next js routing best practices next js authentication best practices next js api best practices
next js best practices next js css best practices sitecore graphql ui 
sitecore support jobs sitecore graphql search query sitecore graphql authentication required 
sitecore graphql example sitecore graphql pagination sitecore graphql api
sitecore graphql cache sitecore graphql schema sitecore graphql server cannot be reached
sitecore graphql configuration experience accelerator sitecore sitecore 8 end of life
sitecore 9 end of life sitecore graphql contextitem sitecore experience edge api  
sitecore-nextjs github sitecore nextjs forms sitecore jss
sitecore jss experience editor dotnet new sitecore nextjs gettingstarted sitecore ssg 
sitecore jss cli sitecore github sitecore nextjs getting started
sitecore nextjs placeholder sitecore nextjs graphql sitecore jss getstaticprops
sitecore jss richtext sitecore pages sitecore-jss-react
sitecore jss tutorial sitecore jss api sitecore jss templates 
sitecore jss routing sitecore jss topology sitecore jss 404 page
sitecore jss example sitecore jss personalization sitecore jss architecture
jss sitecore first sitecore jss demo site sitecore jss dictionary
sitecore forms jss npm sitecore jss sitecore jss license
sitecore jss manifest sitecore jss nextjs sitecore-jss 
sitecore 10 jss why sitecore jss sitecore jss proxy
sitecore jss site sitecore jss nextjs page sitecore nextjs
sitecore jss getting started sitecore next.js sitecore jss docs
jss sitecore github sitecore jss headless sitecore jss placeholder
jss next js sitecore jss sxa jss setup sitecore
sitecore jss node version sitecore nextjs page sitecore page not found 
next js sitecore gitignore next js pages next js
wordpress next.js sitecore-jss-nextjs github sitecore javascript rendering
next.js 404 page next.js custom 404 page next.js 404
next js 500 page Sitecore Headless SXA Sitecore Headless NextJS SXA
Component-level data fetching in Sitecore JSS with Next.js Sitecore NextJS Component Refactoring and Reusability How to setup Secure Sitecore JSS Site
sitecore edge 

Comments

Popular posts from this blog

Sitecore GraphQL Queries

Configuring Sitecore Next.js Headless SXA Multisite App in a Sitecore Container

Sitecore Experience Manager Cloud (XM Cloud) Building blocks