CX Works

CX Works brings the most relevant leading practices to you.
It is a single portal of curated, field-tested and SAP-verified expertise for SAP Customer Experience solutions

Migrate Your Accelerator-based Storefront to Project Spartacus

18 min read

Migrate your accelerator-based storefront to Project Spartacus

If you've read the "Five reasons to move to a project Spartacus javascript storefront " and "Getting started with SAP Commerce Cloud Project Spartacus" you may be wanting to migrate to a stateless high-performance architecture and  now wonder how to actually prepare for migration.    In this article we will discuss an approach suitable for small storefronts, but with a process that can also help larger migrations, where a full re-implementation is recommended.

Table of Contents

To Migrate or Not?

Although the recommendation is to use the move to Spartacus as an opportunity to start fresh and rethink your storefront experience, you may have requirements to migrate to Spartacus and maintain the same experience. Depending on the number and method of customizing your accelerator-based storefront, you made find trying to migrate your existing experience over to Spartacus to be something simple or difficult. If you're unsure, you can use the steps below to go through an exercise to identify the number of changes without necessarily spending the time to implement. This can give you an idea of how much work may be required to migrate vs. starting with a greenfield approach.

As mentioned in "Getting started with SAP Commerce Cloud Project Spartacus" you can run your Accelerator and Spartacus storefronts at the same time to reduce risk, though it is recommended to not do this for a prolonged period. Maintaining two storefronts on two technology stacks can make development and testing quite difficult, not to mention you may be giving your customers an inconsistent user experience depending on which storefront page they are hitting.

Prerequisites

It's recommended that you start your migration to a Spartacus storefront after upgrading to SAP Commerce 1905 or later, as the way Omni Commerce Connect (OCC) application programming interfaces (APIs) are installed has been simplified (they are now available as extensions instead of AddOns).

To get started you will also need the following:

Initial Setup

Front-End Team

The front-end team will build the storefront User Interface composed of layout and Angular Modules.  The core skills of the developers will be:

  • Angular
  • RxJS 
  • Spartacus
  • HMTL5

See Getting started with SAP Commerce Cloud Project Spartacus for a complete list of front-end technologies that your team will need to get acquainted with, before embarking on a migration or re-implementation.

Back-End Team

The back-end team will build the OCC APIs needed by the front-end team.  The core developer skills needed are:

  • SAP Commerce
  • OCC

Anatomy of a Spartacus-based Storefront

Before you begin your migration, you should be familiar with how a Spartacus storefront works. Start by visiting the  Spartacus Storefront Documentation and taking a look at the Modules and Components directory. It will look like this:

Navigate the Modules and Components and get acquainted with the functionality offered by Spartacus.  Pay special attention at Modules that provide a default <CmsConfig> which define the Mapping between standard CMS Components and Spartacus Components. In the example below, the BannerComponent provides mappings to SimpleResponsiveBannerComponent,  BannerComponent and SimpleBannerComponent.

BannerModule
@NgModule({
  imports: [CommonModule, RouterModule, GenericLinkModule, MediaModule],
  providers: [
    provideDefaultConfig(<CmsConfig>{
      cmsComponents: {
        SimpleResponsiveBannerComponent: {
          component: BannerComponent,
        },
        BannerComponent: {
          component: BannerComponent,
        },
        SimpleBannerComponent: {
          component: BannerComponent,
        },
      },
    }),
  ],
  declarations: [BannerComponent],
  entryComponents: [BannerComponent],
  exports: [BannerComponent],
})
export class BannerModule {}


To see the which API endpoints are available in your local installation, navigate to the OCC Swagger documentation. You may need to install additional extensions if a given endpoint is missing.




Accelerator-based Storefront vs Spartacus-based Storefront

You might be familiar with the standard Spring-MVC based accelerator on the left side of the picture below, but look carefully to the description of the Spartacus storefront on the right to understand the key differences.

Accelerator Storefront

In the traditional storefront, the browser makes requests to the server which retrieve the page structure  and executes controllers, facades and services to process and retrieve the information needed to render the view.

Most of the state is kept on the server-side.

Spartacus Storefront

In the headless storefront the front-end is loaded on the browser, and the page structure and layout is retrieved from the server (unless it has a static layout).  The Spartacus Components (see Modules and Components above) are used to build the page on the client side, and they execute OCC Calls to the server (see OCC APIs above) to retrieve data needed for rendering.   The initial page might, however, be built initially on the Server (using a technology known as Server Side Rendering - SSR), for performance and SEO purposes. 

State is kept on the Client side.



During the migration, you will break down the existing accelerator Controller functionality into individual Spartacus Angular Components (also including the view/template logic) and OCC APIs, as indicated by the dotted lines. Be aware in some cases it might be necessary to also modify existing underlying Facades and Services. 

Changes to the Content Catalog will also be required, the Spartacus documentation gives a good overview of the differences between the accelerator and  Spartacus sample data.

Finally, you can analyze a sample call for the Product Details Page with the help of Chrome Developer Tools, to see how everything comes together. Use the Network Tab to see the requests generated by Spartacus.


Going through the calls above in more detail, using the Swagger API documentation as reference, you can see:

Call Parameters Purpose OCC Controller
/occ/v2/electronics-spa/cms/pages

ng=en&curr=USD

Requests the product details page including all WCMS Slots and Components.

Using the Component list in the response, Spartacus will use the CMSConfig mappings (see BannerModule example above) and will instantiate an Angular Component for each CMS Component and build the page using the structure provided by the slots, on the customer's browser.

de.hybris.platform.cmsocc.controllers.PageController

/sockjs-node/info info?t=1597322562030 Only used during development, this socket is used to update the web app when the backend rebuilds

/occ/v2/electronics-spa/products/300938


300938?fields=name,purchasable,baseOptions(DEFAULT…iantOptions(DEFAULT),variantType&lang=en&curr=USD

Returns details of a single product according to the product code 300938

                

de.hybris.platform.commercewebservices.core.v2.controller.ProductsController

/occ/v2/electronics-spa/cms/components components?fields=DEFAULT&productCode=300938&curre…nk%2CBlankVideotapesCategoryLink&lang=en&curr=USD Requests a list of the provided CMS components 

de.hybris.platform.cmsocc.controllers.ComponentController

/occ/v2/electronics-spa/languages languages?lang=en&curr=USD Gets a list of available languages

de.hybris.platform.commercewebservices.core.v2.controller.MiscsController

/occ/v2/electronics-spa/currencies currencies?lang=en&curr=USD Gets a list of available currencies

de.hybris.platform.commercewebservices.core.v2.controller.MiscsController

/occ/v2/electronics-spa/cms/components components?fields=DEFAULT&productCode=300938&curre…ink%2CFacebookLink%2CTwitterLink&lang=en&curr=USD Requests additional CMS components

de.hybris.platform.cmsocc.controllers.ComponentController

/occ/v2/electronics-spa/users/anonymous/consenttemplates consenttemplates?lang=en&curr=USD Fetches the list of consents

de.hybris.platform.commercewebservices.core.v2.controller.ConsentsController

/occ/v2/electronics-spa/cms/components components?fields=DEFAULT&productCode=300938&curre…eviewsTabComponent%2CdeliveryTab&lang=en&curr=USD Requests additional CMS components

de.hybris.platform.cmsocc.controllers.ComponentController

/occ/v2/electronics-spa/products/300938 300938?fields=code,name,summary,price(formattedVal…nfiguratorType,configurable,tags&lang=en&curr=USD Requests additional fields for product code 300938

de.hybris.platform.commercewebservices.core.v2.controller.ProductsController

/occ/v2/electronics-spa/products/300938/references

references?fields=DEFAULT%2Creferences(target(images(FULL)))

&referenceType=SIMILAR&lang=en&curr=USD

Requests product references for product code 300938

de.hybris.platform.commercewebservices.core.v2.controller.ProductsController

/occ/v2/electronics-spa/products/300938 300938?fields=classifications&lang=en&curr=USD Retrieves classifications for the product code 300938

de.hybris.platform.commercewebservices.core.v2.controller.ProductsController

/occ/v2/electronics-spa/products/300938/reviews reviews?lang=en&curr=USD Retrieves customer reviews for this product

de.hybris.platform.commercewebservices.core.v2.controller.ProductsController


Using the Augury Chrome Plugin you can see the resulting component hierarchy after the page has been built in the browser.



Starting the Migration

Now that you understand how Spartacus works on a technical level, you are ready to proceed with the migration.

Step 1 - Make an Inventory of your CMS Components and Pages

It is important to make an inventory of the pages and components used in your current storefront, like in the table below. For each page, list the controllers and custom CMS Components that are used, and  for each component, figure out which data it needs to display or process. Some of the information needed might not be visible at first sight, such as dropdown boxes or pop-up windows. 

You can filter requests to /pagescontentslotscomponents in SmartEdit while editing a given page in  your existing storefront to retrieve the component details.

Components used in the Accelerator Product Details Page
0: {componentId: "SiteLogoComponent",…}
1: {componentId: "HomepageNavLink",…}
2: {componentId: "OrderComponent",…}
3: {componentId: "MiniCart",…}
4: {componentId: "ElectronicsCategoryNavComponent",…}
5: {componentId: "breadcrumbComponent",…}
6: {componentId: "TabPanelContainer",…}
7: {componentId: "FooterNavigationComponent",…}
8: {componentId: "MyAccountComponent",…}
9: {componentId: "MyCompanyComponent",…}
10: {componentId: "SearchBox",…}
11: {componentId: "VariantSelector",…}
12: {componentId: "AddToCart",…}
13: {componentId: "Similar",…}
14: {componentId: "CookieNotificationComponent",…}
15: {componentId: "AnonymousConsentManagementComponent",…}
16: {componentId: "AssistedServiceComponent",…}
17: {componentId: "ProfileTagScriptComponent",…}
18: {componentId: "PersonalizationScriptComponent",…}
19: {componentId: "BundleCarouselComponent",…}

You may find it helpful to make screenshots of your storefront and annotate the components, like so:


Out-of-the-box Spartacus supports almost all responsive B2C CMS components, so you will only need to focus on your custom components, as well as those coming from third party addons or marketplace extensions not covered in the standard library. Group and classify them according to the functional area, using a component inventory like the one below. Be aware that unlike the Accelerator Page approach, everything needs to be a component in Spartacus, so you might need to componentize parts of an existing Jakarta Server Page (JSP) layout.

The following queries give you an overview of the Components, PageTemplates and Pages used in your storefront:

Useful Flexible Search Queries
// Component list
select
    {ct.code},
    {c.id},
    {ct.extensionName},
    count(*) as cnt
from {
    AbstractCMSComponent as acc
    join ComposedType as ct on {ct.pk} = {acc.itemtype}
    join CatalogVersion as cv on {cv.pk} = {acc.catalogversion}
    join Catalog as c on {cv.catalog} = {c.pk}
}
where {c.id} LIKE '%ContentCatalog' and {cv.version} = 'Online'
group by {ct.code}, {cv.version}, {c.id},{ct.extensionName}
order by cnt desc



// Page Templates
select
    {ct.code},
    {c.id},
    {pt.name},
	{pt.frontendTemplateName}
from {
    PageTemplate as pt
    join ComposedType as ct on {ct.pk} = {pt.itemtype}
    join CatalogVersion as cv on {cv.pk} = {pt.catalogversion}
    join Catalog as c on {cv.catalog} = {c.pk}
}
where {c.id} LIKE '%ContentCatalog' and {cv.version} = 'Online'
order by {ct.code}


// Pages
select 
	{ct:code},
    {c:id},
    {ap:name[de]},
    {ap:uid}
from {
    AbstractPage  as ap
    join ComposedType as ct on {ct.pk} = {ap.itemtype}
    join CatalogVersion as cv on {cv.pk} = {ap.catalogversion}
    join Catalog as c on {cv.catalog} = {c.pk}
}
where {c.id} LIKE '%ContentCatalog' and {cv.version} = 'Online'
order by {ct.code}


// Pages, Components and Slots
select
    {c.id},
    {cv.version},
    {p.uid}              as "Page",
    {pt.uid}             as "Template",
    {s4p.position}       as "Template assigned position",
    {st.uid}             as "content slot id 4t",
    {st.active}          as "content slot 4t active",
    {sn.templatePOS}     as "pos",
    {sn.name}            as "template available position",
    {comp.uid},
    {compt.code},
    {comp.visible}
from {
    AbstractPage as p
    join CatalogVersion as cv on {cv.pk} = {p.catalogVersion}
    join Catalog as c on {c.pk} = {cv.catalog}
    join PageTemplate as pt on {pt.pk} = {p.masterTemplate}
    join ContentSlotForPage as s4p on {s4p.page} = {p.pk}
    join ContentSlot as st on {st.pk} = {s4p.contentSlot}
    left join ContentSlotName as sn on {sn.template} = {pt.pk} and {sn.name} = {s4p.position}
    join ElementsForSlot as e2s on {st.pk} = {e2s.source}
    join AbstractCMSComponent as comp on {comp.pk} = {e2s.target}
    join ComposedType as compt on {compt.pk} = {comp.itemtype}
} where 
{cv.version} = 'Online' and {c.id} like '%ContentCatalog' 
order by {cv.version},{c.id},{p.uid},{sn.templatePOS},{comp.uid}

// Templates, components and slots
select
    {c.id},
    {cv.version},
    {p.uid},
    {pt.uid},
    {s4t.position}       as "template assigned position",
    {st.uid}             as "content slot id 4t",
    {st.active}          as "content slot 4t active",
    {s4t.allowOverwrite} as "template allow overwrite",
    {sn.templatePOS}     as "pos",
    {sn.name}            as "template available position",
    {comp.uid},
    {compt.code},
    {comp.visible}
from {
    AbstractPage as p
    join CatalogVersion as cv on {cv.pk} = {p.catalogVersion}
    join Catalog as c on {c.pk} = {cv.catalog}
    join PageTemplate as pt on {pt.pk} = {p.masterTemplate}
    join ContentSlotForTemplate as s4t on {s4t.pageTemplate} = {pt.pk}
    join ContentSlot as st on {st.pk} = {s4t.contentSlot}
    left join ContentSlotName as sn on {sn.template} = {pt.pk} and {sn.name} = {s4t.position}
    join ElementsForSlot as e2s on {st.pk} = {e2s.source}
    join AbstractCMSComponent as comp on {comp.pk} = {e2s.target}
    join ComposedType as compt on {compt.pk} = {comp.itemtype}
} where 
{cv.version} = 'Online' and {c.id} like '%ContentCatalog' 
order by {cv.version},{c.id},{p.uid},{sn.templatePOS},{comp.uid}


Component Inventory

ID Page Component Implementation Render in SSR Nested Data Needed Notes  Component Screenshot
10.1 PDP FinancingWidgetComponent FinancingWidgetController Yes No User, Cart, FinancingPreferences Custom Layout
10.2 PDP PersonalizedRecommendationsComponent PersonalizedRecommendationsController No No RecommendationList Recommendation Engine could be queried directly
10.3 PLP LastPurchases.jsp JSP  Yes No Previous Orders New Component needed

On Page Controllers

In the standard accelerator, a PageController (based on AbstractPageController) prepares the context needed to render a page. In Spartacus most of this work is already performed by the framework, but it's a good idea to manually check for logic that might need to be moved to a custom OCC extension or an individual component.

Step 2 - Perform a GAP Analysis

For each component, identify if there is a corresponding OCC API that provides the needed data (and corresponding Injectable Service), otherwise describe the OCC Extensions that will be needed. Also, set a development priority (or importance) for each component.

Component GAP Analysis

ID Priority Page Component Description Data Needed Existing OCC Missing OCC 
10.1 A PDP FinancingWidgetComponent Calculates Product finance options  Customer, Cart, FinancingPreferences Cart, Users FinancingPreferences
10.2 B PDP PersonalizedRecommendationsComponent Using Analytics recommends best rated products RecommendationList N/A Recommendations
10.3 B PLP LastPurchases.jsp Displays the last 3 online purchases Previous Orders Orders

Step 3 - Start the API Implementation

Using an API First approach, create missing OCC Extensions and define the interfaces based on the semantics of existing OCC services.  Start with empty (or mock) implementations as this will allow the front-end team to start work in parallel in the next step.  

U se  Swagger CodeGen  to automatically  generate the Typescript Angular client code needed in the front-end.  Augment DTOs with necessary missing fields.

Step 4 - Implement the CMS Pages and Components

Create a base web content management system (WCMS) structure that duplicates your current storefront and launch your Spartacus application.  Open your Console Tab in Chrome Developer Tools and you will see a warning for every CMS Component that does not have a corresponding Angular Component, there will also be a warning for the available CMS Slots. 

Verify that this information matches your CMS Component Inventory

Spartacus Storefront

In the headless storefront the front-end is loaded on the browser, and the page structure and layout is retrieved from the server (unless it has a static layout).  The Spartacus Components (see Modules and Components above) are used to build the page on the client side, and they execute OCC Calls to the server (see OCC APIs above) to retrieve data needed for rendering.   The initial page might, however, be built initially on the Server (using a technology known as Server Side Rendering - SSR), for performance and SEO purposes. State is kept on the Client side.

Proceed to re-implement the new CMS components and Pages in Angular.  Use the CMS Component Schematic add-cms-component command to generate skeleton classes  (see also:  Creating Pages and Components  and  Create a new page in Spartacus ) and add your custom logic. 

Conclusion

This article provided a more technical introduction to Spartacus and the techniques needed to migrate an existing accelerator storefront. A migration can involve a significant amount of re-engineering but there are tangible performance and maintenance benefits that make it worth it. Careful preparation is key to a successful migration.

If you have any questions, please do not hesitate to reach out to  sapcx-services@sap.com . If you have technical questions as you develop on Spartacus we encourage you post your question to StackOverflow with the spartacus-storefront tag.

Overlay