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 Adobe Experience Manager (AEM) for a site built using such frameworks.
This article presents important questions to consider when engaging a front-end developer to develop a SPA for AEM and gives an overview of the architecture of AEM regarding deploying SPAs on AEM.
The SPA Editor is the recommended solution for projects that require SPA framework-based client-side rendering (for example, React or Angular).
Developing single page applications on AEM assumes that the front-end developer observes standard best practices when creating an SPA. If as a front-end developer you follow these general best practices and a few AEM-specific principles, your SPA will be functional with AEM and its content-authoring capabilities.
If you keep these principles in mind as you develop your SPA, it will be as flexible and as future proof as possible while enabling all supported AEM authoring functionality.
If you do not need to support AEM authoring features, you may need to consider a different SPA design model.
As when developing any component, your components should be designed in such a way that maximizes their portability. Any patterns that work against the portability or reusability of the components should be avoided to ensure compatibility, flexibility, and maintainability going forward.
The resulting SPA should be built with highly portable and reusable components.
The front-end developer must think of themselves as responsible for creating a library of SPA components that are used to build the app. The front-end developer has full control of the internal structure of the components. However, AEM, at all times, owns the structure of the site.
This means that the front-end developer can add customer content before or after the entry point of the components and can also make third-party calls inside the component. However, the front-end developer is not in full control of how the components nest, for example.
The SPA should only rely on dynamic rendering of content. This is the default expectation where AEM fetches and renders all children of the content structure.
Any explicit rendering that points to specific content is considered static rendering and though supported will not be compatible with AEM’s content authoring features. This also goes against the principle of portability.
As with rendering, all routing should also be dynamic. In AEM, the SPA should always own the routing and AEM listens to it and fetches content based on it.
Any static routing works against the principle of portability and limits the author by not being compatible with content authoring features of AEM. For example, with static routing, if the content author wants to change a route or change a page, the author would have to ask the front-end developer to do it.
Any AEM project should use the AEM Project Archetype, which supports SPA projects using React or Angular and uses the SPA SDK.
If the principles of developing SPAs in AEM are followed, then your SPA will be functional with all supported AEM content authoring features.
There may be cases however when this is not entirely necessary. The following table gives an overview of the various design models, their advantages, and their disadvantages.
Design Model |
Advantages | Disadvantages |
---|---|---|
AEM is used as a headless CMS without using the SPA Editor SDK framework. | The front-end developer has full control over the app. | Content authors cannot use AEM's content authoring experience. The code is not portable or reusable if it contains static references or routing. Does not allow use of the template editor so the front-end developer must maintain editable templates via the JCR. |
The front-end developer uses the SPA Editor SDK framework but only opens some areas to the content author. | The developer keeps control over the app by only enabling authoring in restricted areas of the app. | Content authors are restricted to a limited set of AEM's content authoring experience. The code risks being neither portable nor reusable if it contains static references or routing. Does not allow use of the template editor so the front-end developer must maintain editable templates by way of the JCR. |
The project fully uses the SPA Editor SDK and the frontend components are developed as a library and the content structure of the app is delegated to AEM. | The app is reusable and portable. The content author can edit the app using AEM's content authoring experience. The SPA is compatible with the template editor. |
The developer is not in control of the structure of the app and the portion of content delegated to AEM. The developer can still reserve areas of the app for the content that is not meant to be authored using AEM. |
Although all models are supported in AEM, only by implementing the third (and therefore following the recommended SPA development principles in AEM) can content authors interact with and edit the content of the SPA in AEM as they are accustomed.
Generally if your SPA follows the SPA Development Principles for AEM, then your SPA will work in AEM and be editable using the AEM SPA Editor.
Follow these steps to get your existing SPA ready to work with AEM.
Make your JS components modular.
Make them capable of being rendered in any order, position, and size.
Use the containers provided by Adobe’s SDK to place your components on the screen.
AEM provides a page and paragraph system component for you to use.
Create an AEM component for each JS component.
The AEM components define the dialog and JSON output.
The main task in engaging a front-end developer to create a SPA for AEM is to agree on the components and their JSON models.
The following is an outline of the steps that a front-end developer needs to follow when developing a SPA for AEM.
Agree on components and their JSON model
Front-end developers and back-end AEM developers need to agree on which components are necessary and a model so there is a one-on-one match from SPA components to the back-end components.
AEM components are still necessary mostly to provide edit dialogs and to export the component model.
In React components, access the model via this.props.cqModel
Once components are agreed and the JSON model is in place, the front-end developer is free to develop the SPA and can simply access the JSON model via this.props.cqModel
.
Implement component’s render()
method
The front-end developer implements the render()
method as they see fit and can use the fields of the cqModel
property. This outputs the DOM and the HTML fragments that are inserted into the page. This is the standard way of building an app in React.
Map the component to the AEM resource type via MapTo()
The mapping stores component classes and is used internally by the provided Container
component to retrieve and dynamically instantiate components based on the given resource type.
This serves as the “glue” between front end and back end so editor knows to which components the react components correspond.
The Page
and ResponsiveGrid
are good examples of classes extending the base Container
.
Define the component’s EditConfig
as parameter to MapTo()
This parameter is necessary to tell the editor how the component should be named as long at is not yet rendered or has no content to render.
Extend the provided Container
class for pages and containers
Pages and paragraph systems should extend this class so that delegation to inner components works as expected.
Implement a routing solution that using the HTML5 History
API.
When the ModelRouter
is enabled, calling the pushState
and replaceState
functions trigger a request to the PageModelManager
to fetch a missing fragment of the model.
The current version of the ModelRouter
only supports the use of URLs that points to the actual resource path of Sling Model entry points. It doesn’t support the use of vanity URLs or aliases.
The ModelRouter
can be disabled or configured to ignore a list of regular expressions.
These code blocks illustrate how your React and Angular components need nothing that is Adobe or AEM specific.
The MapTo
helper is the “glue” that allows the back-end and the front-end components to be matched together:
For more information about using MapTo
and building SPAs for AEM in general, see the Getting Started guide for your chosen framework.
The general architecture of AEM including development, authoring, and publishing environments does not change when using SPAs. However it is helpful to understand how SPA development fits into this architecture.
Build Environment
This is where the source for the SPA application source and component source is checked-out.
AEM Author
Content is created on the AEM author, including authoring SPAs.
When a SPA is edited using the SPA Editor on the authoring environment:
cq-data
attributes.cq-data
attributes allows the editor to load additional page information so that it knows what edit configurations are available for the components.AEM Publish
This is where the authored content and compiled libraries including SPA application artifacts, clientlibs, and components are published for public consumption.
Dispatcher / CDN
The Dispatcher serves as the caching layer of AEM for visitors to the site.
Inside AEM, there is no need to execute JavaScript build mechanisms or to execute the JavaScript itself. AEM only hosts the compiled artifacts from the SPA application.
For an overview of how a simple SPA in AEM is structured and how it works, see the getting started guide for both React and Angular.
For a step-by-step guide to creating your own SPA, see the Getting Started with the AEM SPA Editor - WKND Events Tutorial.
For further details about the dynamic model to component mapping and how it works within SPAs in AEM, see the article Dynamic Model to Component Mapping for SPAs.
If you wish to implement SPAs in AEM for a framework other than React or Angular or simply wish to take a deep dive into how the SPA SDK for AEM works, see the SPA Blueprint article.