top of page
  • Writer's pictureGowtham

Converting Sitecore MVC to Jamstack: A Comprehensive Guide

When I first embarked on my journey with Headless technology, I wondered if it was feasible to transition an existing Sitecore MVC site to a more modern Headless solution, or if it was necessary to start development from scratch. This article will provide a step-by-step guide on how to convert an existing Sitecore MVC application to the Jamstack architecture. It's crucial to modernize our traditional Sitecore applications to leverage the capabilities of modern technology stacks such as Headless, SSG, ISR, multi-channel, and others.


Architecture overview

Jamstack architecture for existing Sitecore MVC sites is possible because of the ability of the Sitecore Layout Service to render MVC components to HTML, and include them in its output.

The following diagram represents the publishing and rendering process for Sitecore MVC components when using Experience Edge and Next.js.

Diagram illustrating the publishing and rendering process in static HTML generation of MVC applications

The publishing and rendering process consists of the following steps:


  1. The Layout Service outputs MVC components as HTML, embedded in its usual service output.

  2. The Layout Service output is published to Experience Edge with each page/route, allowing it to be queried by Sitecore headless SDKs such as Next.js.

  3. The Next.js application queries the Layout Service output for the route and passes it into one or more Placeholder components.

  4. Based on the lack of a componentName property in the layout data, the Placeholder component in the Sitecore Next.js SDK renders the Sitecore component directly as HTML into the pre-rendered document.

Prerequisites

  • Sitecore version 10.2+ – An upgrade of your MVC application would be needed.

  • Sitecore Headless Services module version 19+.

  • You must install the JSS CLI version 19+.

Migrating from 10.1 to 10.2

You can access the comprehensive solution containing all the changes by following the link provided. To set it up on your local system immediately, please refer to the instructions in the readme file.


I am currently utilizing the "Basic Company - Unicorn" website from the Sitecore Helix examples with Docker for demonstration purposes. The repository link for the Basic Company site that I am using can be found here.


As stated earlier, in order to carry out the migration, it is necessary to have Sitecore version 10.2 or higher. The repository currently has version 10.1, but with some configuration changes, I will upgrade it to 10.2. The corresponding changes can be found here.


To initialize the docker container and start the image, please clone the repository and run the following command:

.\init.ps1 -LicenseXmlPath C:\License\license.xml -SitecoreAdminPassword b
docker compose up -d

Adapting MVC components to be compatible with JSS

Up to this point, we have accomplished the migration of Sitecore 10.2, integrated Rendering Host and Next JS. Our next step is to adjust our MVC components to work seamlessly with JSS.


However, before we proceed with modifying the components themselves, we must first make some modifications at the template level to enable the components to serve data in JSON format.


The services used by JSS, such as the Layout Service, GraphQL, Tracking Service, and Dictionary Service, utilize the API Key mechanism provided by Sitecore Services Client (SSC). You must create an API Key and note its Item ID for using it when connecting JSS

To generate an API key

  1. Open your Sitecore Content Editor in the Master database.

  2. Navigate to /sitecore/system/Settings/Services/API Keys.

  3. Click on "API Key" to create a new API key.

  4. Assign the name of your Next JS application to the API key. In this case, we have named our app "basic-company," so we will use the same name for the API key.

  5. After creating the API key item, update the "CROS Origins" and "Allowed Controllers" values to "*". Please note that we are using a wildcard only for demo purposes, and it is not recommended for scaled instances. For further details, please refer to Sitecore's official website.

Screenshot showing how to enable editing and static generation support for the JSS app by inheriting from the JavaScript Services/App template in Sitecore

In order to enable editing and static generation support for the JSS app, the site root must inherit from the /sitecore/templates/Foundation/JavaScript Services/App template.

Screenshot depicting how to enable editing support by using or inheriting the JavaScript Services/JSS Layout template in Sitecore for your page layouts

To enable editing support, make sure that the layouts for your pages use or inherit the /sitecore/templates/Foundation/JavaScript Services/JSS Layout template.

Screenshot illustrating how to configure root placeholders for a selected layout in the Sitecore content tree by navigating to the 'Layout Service Placeholders' field

To configure the root placeholders for your selected layout in the content tree, navigate to /sitecore/layout/Layouts/Project/BasicCompany/Default and add every root placeholder to the "Layout Service Placeholders" field. If a Placeholder Settings item does not exist, create one.

Screenshot demonstrating layout inheritance in Sitecore, preparing for the validation of Layout Service response

Validating Layout Service response

We have now completed 90% of the work, and before we proceed to the next steps, we can check the Layout Service. To access the Layout Service, use the URL provided below and replace the sc_apikey with your own. However, make sure to publish your site beforehand, or else you will not receive a response from the Layout Service.

https://cm.basic-company-unicorn.localhost/sitecore/api/layout/render?item={97479C6B-BB30-4A15-AFD1-2C89F207E9D6}&sc_apikey={6E80F612-7793-48AE-B286-4EE2B6AFAE3E}

If everything is fine you'll get the response as below

{"sitecore":{"context":{"pageEditing":false,"site":{"name":null},"pageState":"normal","language":"en","itemPath":"/Basic-Company/Home"},"route":{"name":"Home","displayName":"Home","fields":{"Navigation Title":{"value":"Home"},"Footer Copyright":{"value":"Copyright"},"Header Logo":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/helix-logo.png?h=44&iar=0&w=139&hash=098C1B36D12B08BF1A9ED55C0B91073A","alt":"Sitecore Helix","width":"139","height":"44"}}},"databaseName":"web","deviceId":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3","itemId":"97479c6b-bb30-4a15-afd1-2c89f207e9d6","itemLanguage":"en","itemVersion":1,"layoutId":"4ed48317-062f-4465-b9af-1e636841525b","templateId":"63cd29ba-0e08-44d5-ab10-e05298a9818d","templateName":"Home Page","placeholders":{"Header":[{"uid":"7d4f689f-208c-4ea3-88ba-0bc6e615771e","componentName":"Header","dataSource":""}],"main":[{"uid":"bb562955-2cf5-4a57-b6c7-ddf2278ec0e0","componentName":"Hero Banner","dataSource":"{9C581356-66D4-4993-BB25-757B710A06E8}","fields":{"Title":{"value":"Basic Company"},"Image":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/hero-home.jpg?h=510&iar=0&w=1920&hash=CBD65D270D2DC471EAADE5C57332C88C","alt":"Basic Company","width":"1920","height":"510"}},"Subtitle":{"value":"Lorem Ipsum Dolor Sit Amet"}}},{"uid":"e10e7525-8542-41bc-939e-3082925b9c52","componentName":"Promo Container","dataSource":""},{"uid":"d65c5c87-61b0-4e2d-9842-6d6b1faed3cf","componentName":"Section Header","dataSource":"{086CBC66-2B60-4711-BEE5-14C11181FB27}","fields":{"Text":{"value":"Section Header"}}},{"uid":"0b6b5e57-eb1c-42a6-86f3-da06dfd1f319","componentName":"Promo Container","dataSource":""}],"Footer":[{"uid":"66b647e6-3d33-45ef-af06-ebb2175bc56b","componentName":"Footer","dataSource":""}]}}}} 

As we examine the response, we can observe that the placeholders we included earlier (main, header, and footer) are present.


Modify the Sitecore Layout Service settings to generate HTML for MVC renderings.

Now, let's proceed with the configuration of the "Hero Banner" component to display HTML instead of JSON.HTML for MVC renderings.


Go to the path /sitecore/layout/Renderings/Feature/BasicContent/Hero Banner and activate the "Render as HTML" option. This will allow the MVC rendering to present the information in HTML format rather than JSON.

render-as-html

After publishing the item, go to the Layout Service endpoint URL to view the updates. The HTML content for the Hero Banner will be included in the response. By doing this, we have successfully made the necessary changes to the Sitecore Layout Service settings to produce HTML for MVC renderings.

{"sitecore":{"context":{"pageEditing":false,"site":{"name":null},"pageState":"normal","language":"en","itemPath":"/Basic-Company/Home"},"route":{"name":"Home","displayName":"Home","fields":{"Navigation Title":{"value":"Home"},"Footer Copyright":{"value":"Copyright"},"Header Logo":{"value":{"src":"https,http,http://www.basic-company-unicorn.localhost/-/media/Basic-Company/helix-logo.png?h=44&iar=0&w=139&hash=098C1B36D12B08BF1A9ED55C0B91073A","alt":"Sitecore Helix","width":"139","height":"44"}}},"databaseName":"web","deviceId":"fe5d7fdf-89c0-4d99-9aa3-b5fbd009c9f3","itemId":"97479c6b-bb30-4a15-afd1-2c89f207e9d6","itemLanguage":"en","itemVersion":1,"layoutId":"4ed48317-062f-4465-b9af-1e636841525b","templateId":"63cd29ba-0e08-44d5-ab10-e05298a9818d","templateName":"Home Page","placeholders":{"Header":[{"uid":"7d4f689f-208c-4ea3-88ba-0bc6e615771e","componentName":"Header","dataSource":""}],"main":[{"name":"section","type":"text/sitecore","contents":"\r\n    <div class=\"hero-body\">\r\n        <div class=\"container\">\r\n            <h1 class=\"title\">\r\n                Basic Company\r\n            </h1>\r\n            <h2 class=\"subtitle\">\r\n                Lorem Ipsum Dolor Sit Amet\r\n            </h2>\r\n        </div>\r\n    </div>\r\n","attributes":{"class":"hero is-medium is-black","style":"background-image: url(/-/media/Basic-Company/hero-home.jpg)"},"cacheable":true,"immutable":true},{"uid":"e10e7525-8542-41bc-939e-3082925b9c52","componentName":"Promo Container","dataSource":""},{"uid":"d65c5c87-61b0-4e2d-9842-6d6b1faed3cf","componentName":"Section Header","dataSource":"{086CBC66-2B60-4711-BEE5-14C11181FB27}","fields":{"Text":{"value":"Section Header"}}},{"uid":"0b6b5e57-eb1c-42a6-86f3-da06dfd1f319","componentName":"Promo Container","dataSource":""}],"Footer":[{"uid":"66b647e6-3d33-45ef-af06-ebb2175bc56b","componentName":"Footer","dataSource":""}]}}}}

You can find the changes up to this point here.


Adding Rendering Host

Once the site is up and running, it confirms that the migration from Sitecore 10.1 to 10.2 was successful and along with that we have enabled the Layout service. The next step is to add the Rendering Host, which we will use to establish communication between our Next.js front-end and Layout Service.


In order to accomplish it, certain modifications must be made to the files listed below.

  • docker-compose.override.yml

  • .env

  • init.ps1

  • docker/build/cd/Dockerfile

  • docker/build/cm/Dockerfile

  • docker/build/mssql-init/Dockerfile

  • docker/build/nodejs/Dockerfile

  • docker/build/rendering/Dockerfile

The specifics of the alterations made to the previously mentioned files can be found in this PR.


Execute the following PowerShell command in Sitecore to set all MVC renderings to have the "Render as HTML" option checked.

Get-ChildItem "/sitecore/layout/Renderings" -Recurse |
	Where-Object { $_.TemplateName -eq "View rendering" -or $_.TemplateName -eq "Controller rendering" } |
	ForEach-Object {
		$val = $_.Fields["Render as HTML"].Value
		if ($val -eq "1") {
		    return
		}
		Write-Host "Setting '$($_.Name)'"
		$_.Editing.BeginEdit()
	    $_.Fields["Render as HTML"].Value = 1
		$_.Editing.EndEdit()
	}	

Once the modifications have been made, it is now time to install Next.js for our Basic Company Project.

  • Open PowerShell in admin mode and execute the following command to navigate to the specified folder. In this example, I have cloned the repository on my D drive.

cd D:\mvc-to-headless\src\Project\BasicCompany
  • Run the below command to initiate the Next JS installation

npx create-sitecore-jss@ver20 nextjs
  • During the process, you will be presented with multiple options. Please select the options that I have chosen:

next-js-instillation
  • I selected "nextjs-sxa" for the final option, which was to include any add-ons.

  • Upon successful completion of the installation, you will receive a message indicating that it was successful.

next-js-instillation-completion

We have developed the JSS application. To link it with our Sitecore instance, we need to configure it. Execute the subsequent CLI command to proceed:

cd basic-company
jss setup

You will encounter the following questions, and you may either enter values identical to mine or customize them to suit your requirements.

  1. Is your Sitecore instance on this machine or accessible via network share? [y/n]: y

  2. Path to the Sitecore folder (e.g. c:\inetpub\wwwroot\my.siteco.re): ..\..\..\..\docker\deploy\website

  3. Sitecore hostname (e.g. http://myapp.local.siteco.re; see /sitecore/config; ensure added to hosts): https://www.basic-company-unicorn.localhost

  4. Sitecore import service URL [https://www.basic-company-unicorn.localhost/sitecore/api/jss/import]:

  5. Sitecore API Key (ID of API key item): {EE2E30DB-2744-4DE4-9928-E334F89886BA}

  6. Please enter your deployment secret (32+ random chars; or press enter to generate one): joxh265cwali5j2qunjrgeorozv8948s66spmgck0d

Note:

  • To use the default values for options 4 , press "Enter".

  • For the option 6 use the JSS_BasicCompany_DEPLOYMENT_SECRET from .env file

  • For option 2, if you cloned your repo on a drive other than D, adjust the drive value accordingly.

  • I used the path of the D drive since that's where I cloned my repository.

Please go to the following directory: \src\Project\BasicCompany\basic-company\sitecore\config\basic-company.config and modify the root path for your JSS site. Also, make sure to change the database from "master" to "web".

      <site patch:before="site[@name='website']"
        inherits="website"
        name="basic-company"
        hostName="www.basic-company-unicorn.localhost"
        rootPath="/sitecore/content/basic company"
        startItem="/home"
        database="web" />

The configuration is now set for deployment (please ensure that the files created under src\Project\BasicCompany\basic-company\sitecore\config\basic-company.config are correct). To proceed, run the following command in the CLI. Remember to switch the database to web from master before executing the script.

jss deploy config

Get the Next.js application ready to display our content.

After successfully deploying the configuration, we must modify the Layout.tsx file to include our newly added placeholders (header, main, footer).

layout.tsx

Duplicate the "basic-company.css" file from the website directory to the "src/assets" directory, and then modify the _app.tsx file with the following changes:

_app.tsx

Execute the command below to initiate our JSS application and link it to our Sitecore application for operation.

jss start:connected

By visiting http://localhost:3000 , you will be able to observe the Basic Company MVC website rendered as a JSS App, which is all set to be deployed and generated statically.

localhost_3000

However, let's take a step forward and begin converting one of the components to React. I consider this method to be an incremental way to start the migration process to JSS (React).

Start converting components from MVC (C#/Razor) to Next.js (JavaScript/React) incrementally

To proceed, we will duplicate the "Hero Banner" rendering in Sitecore, modify its template to transform it into a "/sitecore/templates/Foundation/JavaScript Services/Json Rendering", and rename it to "HeroBanner" so that it follows the naming conventions of React. Additionally, the "Render as HTML" checkbox must be unchecked, and the "component name" field should be set to "HeroBanner". Finally, we need to insert this new component next to the MVC version on the Homepage.

HeroBanner

After publishing the rendering, review the Layout Service response once again. You should be able to see both versions of the component - the one in HTML and the one in JSON.


If we refresh our JSS App(http://localhost:3000) now, we will notice that the component has been added, but it still requires a React implementation.

localhost3000_HeroBanner

To generate the React implementation of the component we created, execute the following command in the terminal from the JSS App root:

jss scaffold BasicContent/HeroBanner 
HeroBanner_Scaffold

Now open the BasicContent/HeroBanner.tsx and replace with the below content and you can see the JSS Component on the JSS App.

import { Text, Field, ImageField } from '@sitecore-jss/sitecore-jss-nextjs';
export type HeroBannerProps = {
  fields: {
    Title: Field<string>;
    Subtitle: Field<string>;
    Image: ImageField;
  };
};
const HeroBanner = ({ fields }: HeroBannerProps): JSX.Element => {
  const bannerStyle = {
    backgroundImage: `url(${fields.Image?.value?.src})`,
  };
  return (
    <section className="hero is-medium is-black" style={bannerStyle}>
      <div className="hero-body">
        <div className="container">
          <Text field={fields.Title} tag="h1" className="title" />
          <Text field={fields.Subtitle} tag="h2" className="title" />
        </div>
      </div>
    </section>
  );
};
export default HeroBanner;
added_component_jss_app

Both the MVC and React components are now residing on the same site. I have retained both of them to make it more visually apparent, but it is recommended to replace only the MVC rendering when migrating.


By modifying the docker-compose.override.yml and Dockerfile for Rendering, we can integrate our JSS application to run in our Docker environment.


I hope you found this useful. You can access the complete solution here - it is a Sitecore Helix Examples fork with added headless services, Sitecore 10.2 upgrade, a NextJS rendering host, and application.

145 views0 comments
bottom of page