Show Menu
TOPICS×

SPA Introduction and Walkthrough

Single page applications (SPAs) can offer compelling experiences for website users. Developers want to be able to build sites using SPA frameworks and authors want to seamlessly edit content within AEM for a site built using such frameworks.
The SPA Editor offers a comprehensive solution for supporting SPAs within AEM. This article walks through using a basic SPA application for authoring and shows how it relates to the underlying AEM SPA Editor.

Introduction

Article Objective

This article introduces the basic concepts of SPAs before leading the reader through a walkthrough of the SPA editor by using a simple SPA application to demonstrate basic content editing. It then dives down into the construction of the page and how the SPA application relates to and interacts with the AEM SPA Editor.
The goal of this introduction and walkthrough is to demonstrate to an AEM developer why SPAs are relevant, how they generally work, how a SPA is handled by the AEM SPA Editor, and how it is different from a standard AEM application.
The walkthrough is based on standard AEM functionality and the sample WKND SPA Project app. To follow along, please download and install the sample WKND SPA Project app from GitHub here.
This document uses the WKND SPA Project app for demonstration purposes only. It should not be used for any project work.
Any AEM project should leverage the AEM Project Archetype , which supports SPA projects using React or Angular and leverages the SPA SDK.

What is a SPA?

A single-page application (SPA) differs from a conventional page in that it is rendered client-side and is primarily Javascript-driven, relying on Ajax calls to load data and dynamically update the page. Most or all content is retrieved once in a single page load with additional resources loaded asynchronously as needed based on user interaction with the page.
This reduces the need for page refreshes and presents an experience to the user that is seamless, fast, and feels more like a native app experience.
The AEM SPA Editor allows front-end developers to create SPAs that can be integrated into an AEM site, allowing the content authors to edit the SPA content as easily as any other AEM content.

Why a SPA?

By being faster, fluid, and more like a native application, a SPA becomes a very attractive experience not only for the visitor of the webpage, but also for marketers and developers due to the nature of how SPAs work.

Visitors

  • Visitors want native-like experiences when they interact with content.
  • There is clear data that the faster a page, the more likely a conversion will occur.

Marketers

  • Marketers want to offer rich, native-like experiences to entice visitors to fully engage with content.
  • Personalization can make these experiences even more compelling.

Developers

  • Developers want a clean separation of concerns between content and presentation.
  • Clean separation makes the system more extensible as well as allow for independent front-end development.

How Does a SPA Work?

The primary idea behind a SPA is that calls to and dependency on a server are reduced in order to minimize delays caused by server latency so that the SPA approaches the responsiveness of a native application.
In a traditional, sequential webpage, only the data needed for the immediate page is loaded. This means that when the visitor moves to another page, the server is called for the additional resources. Additional calls might be necessary as the visitor interacts with elements on the page. These multiple calls can give a sense of lag or delay as the page has to catch up with the visitor's requests.
For a more fluid experience, which approaches what a visitor expects from mobile, native apps, a SPA loads all necessary data for the visitor on the first load. Although this might take a bit longer at first, it then eliminates the need for additional server calls.
By rendering on the client side, page elements react faster, and interactions with the page by the visitor are immediate. Any additional data that might be needed are called asynchronously to maximize the speed of the page.
For technical details on how SPAs work in AEM, see the articles:
For a closer look at the design, architecture, and technical workflow of the SPA Editor, see the article:

Content Editing Experience with SPA

When a SPA is built to leverage the AEM SPA Editor, the content author notices no difference when editing and creating content. Common AEM functionality is available and no changes to the author's workflow is required.
  1. Edit the WKND SPA Project app in AEM.
    http://localhost:4502/editor.html/content/wknd-spa-react/us/en/home.html
  2. Select a text component and notice that a toolbar appears like for any other component. Select Edit .
  3. Edit the content as normal within AEM and note that the changes are persisted.
  4. Use the Assets Browser to drag-and-drop a new image into an image component.
  5. The change is persisted.
Additional authoring tools such as dragging-and-dropping additional components on the page, rearranging components, and modifying the layout are supported as in any non-SPA AEM application.
The SPA Editor does not modify the DOM of the application. The SPA itself is responsible for the DOM.
To see how this works, continue on to the next section of this article SPA Apps and the AEM SPA Editor .

SPA Apps and the AEM SPA Editor

Experiencing how a SPA behaves for the end user and then inspecting the SPA page helps to better understand how a SAP app works with the SPA Editor in AEM.

Using an SPA Application

  1. Load the WKND SPA Project application either on the publish server or using the option View as Published from the Page Information menu in the page editor.
    http://<host>:<port>/content/wknd-spa-react/us/en/home.html
    Note the pages structure including navigation to child pages, menu, and article cards.
  2. Navigate to a child page using the menu and see that the page loads immediately without the need for a refresh.
  3. Open your browser's built-in developer tools and monitor network activity as you navigate the child pages.
    There is very little traffic as you move from page to page in the app. The page is not reloaded and only the new images are requested.
    The SPA manages the content and routing entirely on the client side.
So if the page is not reloaded when navigating through the child pages, how is it loaded?
The next section, Loading a SPA Application , digs deeper into the mechanics of loading the SPA and how content can be loaded synchronously and asynchronously.

Loading an SPA Application

  1. If not already loaded, load the We.Retail Journal application either on the publish server or using the option View as Published from the Page Information menu in the page editor.
    http://<host>:<port>/content/wknd-spa-react/us/en/home.html
  2. Use the built-in tool of your browser to view the source of the page.
  3. Note that the content of the source is limited.
     <!DOCTYPE html>
     <html lang="en">
     <head>
         <meta charset="UTF-8"/>
         <title>WKND SPA React Home Page</title>
    
         <meta name="template" content="spa-page-template"/>
         <meta name="viewport" content="width=device-width, initial-scale=1"/>
    
     <link rel="stylesheet" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-base.min.css" type="text/css">
    
     <meta name="theme-color" content="#000000"/>
     <link rel="icon" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-react/resources/favicon.ico"/>
     <link rel="apple-touch-icon" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-react/resources/logo192.png"/>
     <link rel="manifest" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-react/resources/manifest.json"/>
    
     <!-- AEM page model -->
     <meta property="cq:pagemodel_root_url" content="/content/wknd-spa-react/us/en.model.json"/>
     <link href="//fonts.googleapis.com/css?family=Source+Sans+Pro:400,600|Asar&display=swap" rel="stylesheet"/>
     <meta property="cq:datatype" content="JSON"/>
     <meta property="cq:wcmmode" content="edit"/>
    
     <link rel="stylesheet" href="/libs/cq/gui/components/authoring/editors/clientlibs/internal/page.min.css" type="text/css">
     <link rel="stylesheet" href="/etc.clientlibs/wcm/foundation/clientlibs/main.min.css" type="text/css">
     <script type="text/javascript" src="/libs/cq/gui/components/authoring/editors/clientlibs/internal/messaging.min.js"></script>
     <script type="text/javascript" src="/libs/cq/gui/components/authoring/editors/clientlibs/utils.min.js"></script>
     <script type="text/javascript" src="/libs/granite/author/deviceemulator/clientlibs.min.js"></script>
     <script type="text/javascript" src="/libs/cq/gui/components/authoring/editors/clientlibs/internal/page.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/wcm/foundation/clientlibs/main.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/clientlibs/granite/jquery.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/clientlibs/granite/utils.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/clientlibs/granite/jquery/granite.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/foundation/clientlibs/jquery.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/foundation/clientlibs/shared.min.js"></script>
    
     <!--cq{"decorated":false,"type":"cq/cloudconfig/components/scripttags/header","path":"/content/wknd-spa-react/us/en/home/jcr:content/cloudconfig-header","structurePath":"/content/wknd-spa-react/us/en/home/jcr:content/cloudconfig-header","selectors":null,"servlet":"Script /libs/cq/cloudconfig/components/scripttags/header/header.html","totalTime":2,"selfTime":2}-->
    
     <link rel="stylesheet" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-react.min.css" type="text/css">
    
     </head>
    
     <body class="page basicpage">
         <noscript>You need to enable JavaScript to run this app.</noscript>
     <div id="spa-root"></div>
    
     <script type="text/javascript" src="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-react.min.js"></script>
    
     <script type="text/javascript" src="/etc.clientlibs/core/wcm/components/commons/site/clientlibs/container.min.js"></script>
     <script type="text/javascript" src="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-base.min.js"></script>
    
     <script type="text/javascript" src="/libs/cq/gui/components/authoring/editors/clientlibs/internal/pagemodel/messaging.min.js"></script>
    
     <link rel="stylesheet" href="/etc.clientlibs/wknd-spa-react/clientlibs/clientlib-author.min.css" type="text/css">
    
     <!--cq{"decorated":true,"type":"cq/cloudserviceconfigs/components/servicecomponents","path":"/content/wknd-spa-react/us/en/home/jcr:content/cloudservices","selectors":null,"servlet":"Script /libs/cq/cloudserviceconfigs/components/servicecomponents/servicecomponents.jsp","totalTime":2,"selfTime":2}-->
    
     <!--cq{"decorated":false,"type":"cq/cloudconfig/components/scripttags/footer","path":"/content/wknd-spa-react/us/en/home/jcr:content/cloudconfig-footer","structurePath":"/content/wknd-spa-react/us/en/home/jcr:content/cloudconfig-footer","selectors":null,"servlet":"Script /libs/cq/cloudconfig/components/scripttags/footer/footer.html","totalTime":2,"selfTime":2}-->
    
     </body>
     </html>
     <!--cq{"decorated":false,"type":"wknd-spa-react/components/page","path":"/content/wknd-spa-react/us/en/home/jcr:content","selectors":null,"servlet":"Script /apps/spa-project-core/components/page/page.html","totalTime":39,"selfTime":33}-->
    
    
    The page does not have any content within its body. It is primarily made up of stylesheets and a call to various scripts such as clientlib-react.min.js .
    These scripts are the primary drivers of this application and are responsible for rendering all content.
  4. Use your browser's built-in tools to inspect the page. See the content of the DOM fully loaded.
  5. Switch to the Network tab in the Inspector and reload the page.
    Ignoring image requests, note that the primary resources loaded for the page are the page itself, CSS, the React Javascript, its dependencies, as well as JSON data for the page.
  6. Load the home.model.json in a new tab.
    http://<host>:<port>/content/wknd-spa-react/us/en/home.model.json
    The AEM SPA Editor leverages AEM Content Services to deliver the entire content of the page as a JSON model.
    By implementing specific interfaces, Sling Models provide the information necessary to the SPA. The delivery of the JSON data is delegated downward to each component (from page, to paragraph, to component, etc.).
    Each component chooses what it exposes and how it is rendered (server-side with HTL or client-side with React or Angular). This article focuses on client-side rendering with React.
  7. The model can also group pages together so that they are loaded synchronously, reducing the number of page reloads needed.
    In the example of We.Retail Journal, the home , page-1 , page-2 , and page-3 pages are loaded synchronously, since visitors commonly visit all of those pages.
    This behavior is not mandatory and is fully definable.
  8. To view this difference in behavior, reload the home page and clear the network activity of the inspector. Navigate to page-1 in the page menu and see that the only network activity is a request for the image of page-1 . page-1 itself does not need to load.

Interaction with the SPA Editor

Using the sample WKND SPA Project application, it is clear how the app behaves and is loaded when published, leveraging content services for JSON content delivery as well as asynchronous loading of resources.
Additionally, for the content author, content creation using a SPA editor is seamless within AEM.
In the following section we will explore the contract that allows the SPA Editor to relate components within the SPA to AEM components and achieve this seamless editing experience.
  1. Load the WKND SPA Project application in the editor and switch to Preview mode.
    http://<host>:<port>/editor.html/content/wknd-spa-react/us/en/home.html
  2. Using your browser's built-in developer tools, inspect the content of the page. Using the selection tool, select an editable component on the page and view the element detail.
    Note that the component has a new data attribute data-cq-data-path .
    For example
    data-cq-data-path="/content/wknd-spa-react/us/en/home/jcr:content/root/responsivegrid/text
    This path allows the retrieval and association of the edit context configuration object of each component.
    This is the only markup attribute required for the editor to recognize this as an editable component within the SPA. Based on this attribute, the SPA Editor will determine which editable configuration is associated with the component, so that the correct frame, toolbar, etc. is loaded.
    Some specific class names are also added for marking placeholders and for asset drag-and-drop functionality.
    This behavior differs from server-side rendered pages in AEM, where there is a cq element inserted for each editable component.
    This approach in the SPA Editor removes the need to inject custom elements, relying only an additional data attribute, making the markup simpler for the frontend developer.

Next Steps

Now that you understand the SPA editing experience in AEM and how a SPA relates to the SPA Editor, take a deeper dive into understanding how a SPA is built.