The SPA Editor is the recommended solution for projects that require SPA framework based client-side rendering (e.g. React or Angular).
AEM 6.5.1.0 or later is required to use the SPA server side rendering features as described in this document.
Single page applications (SPAs) can offer the user a rich, dynamic experience that reacts and behaves in familiar ways, often just like a native application. This is achieved by relying on the client to load the content up front and then do the heavy lifting of handling user interaction and thus minimizing the amount of communication needed between the client and the server, making the app more reactive.
However this can lead to longer initial load times, especially if the SPA is large and rich in its content. In order to optimize load times, some of the content can be rendered server-side. Using server side rendering (SSR) can accelerate the initial load of the page and then pass further rendering on to the client.
SSR is not required on all projects. Although AEM fully supports JS SSR for SPA, Adobe does not recommend implementing it systematically for every project.
When deciding to implement SSR you must first estimate what additional complexity, effort, and cost adding SSR realistically represents for the project, including the long term maintenance. An SSR architecture should be chosen only when the added value clearly exceeds the estimated costs.
SSR usually provides some value when there is a clear “yes” to either of the following questions:
Only when at least one of these two questions are answered with a clear “yes” for your project does Adobe recommend implementing SSR. The following sections describe how to do this using Adobe I/O Runtime.
If you are confident that your project requires the implementation of SSR, Adobe’s recommended solution is to use Adobe I/O Runtime.
For more information on Adobe I/O Runtime, please see
The following sections detail how Adobe I/O Runtime can be used to implement SSR for your SPA in two different models:
Adobe recommends a separate Adobe I/O Runtime workspace per environment (stage, prod, testing, etc.). This allows for typical systems development life cycle (SDLC) patterns with different versions of a single application deployed to different environments. See the document CI/CD for Project App Builder Applications for more information.
A separate workspace is not needed per instance (author, publish) unless there are differences in the runtime implementation per instance type.
AEM must know where the remotely-rendered content can be retrieved. Regardless of which model you choose to implement for SSR, you will need to specify to AEM how to access this remote rendering service.
This is done via the RemoteContentRenderer - Configuration Factory OSGi service. Search for the string “RemoteContentRenderer” in the Web Console Configuration console at http://<host>:<port>/system/console/configMgr
.
The following fields are available for the configuration:
key=value
Regardless of if you choose to implement the AEM-driven communication flow or the Adobe I/O Runtime-driven flow, you must define a remote content renderer configuration.
This configuration also must be defined if you choose to use a custom Node.js server.
This configuration leverages the Remote Content Renderer, which has additional extension and customization options available.
When using SSR, the component interaction workflow of SPAs in AEM includes a phase in which the initial content of the app is generated on Adobe I/O Runtime.
The browser requests the SSR content from AEM.
AEM posts the model to Adobe I/O Runtime.
Adobe I/O Runtime returns the generated content.
AEM serves the HTML returned by Adobe I/O Runtime via the HTL template of the backend page component.
The previous section describes the standard and recommended implementation of server side rendering with regards to SPAs in AEM, where AEM performs the bootstrapping and serving of content.
Alternatively, SSR can be implemented so that Adobe I/O Runtime is responsible for the bootstrapping, effectively reversing the communication flow.
Both models are valid and supported by AEM. However, one should consider the advantages and disadvantages of each before implementing a particular model.
Bootstrapping | Advantages | Disadvantages |
---|---|---|
via AEM |
|
|
via Adobe I/O Runtime |
|
|
Generally only part of an application needs to be rendered server side. The common example is the content that will be displayed above the fold on the initial load of the page is rendered server side. This saves time by delivering to the client, already rendered content. As the user interacts with the SPA, the additional content is rendered by the client.
As you consider implementing server side rendering for your SPA, you need to review for what parts of the app it will be necessary.
SPA components could be rendered by the client (in the browser) or server side. When rendered server side, browser properties such as window size and location are not present. Therefore SPA components should be isomorphic, making no assumption about where they will be rendered.
To leverage SSR, you will need to deploy your code in AEM as well as on Adobe I/O Runtime, which is responsible for the server side rendering. Most of the code will be the same, however server-specific tasks will differ.
SSR for SPAs in AEM require Adobe I/O Runtime, which is called for the rendering of the app content server side. Within the HTL of the app, a resource on Adobe I/O Runtime is called to render the content.
Just as AEM supports the Angular and React SPA frameworks out-of-the box, server side rendering is also supported for Angular and React apps. See the NPM documentation for both frameworks for further details.
For a simplistic example, please refer to the We.Retail Journal app. It renders the entire application server side. Although this is not a real-world example, it does illustrate what is needed to implement SSR.
The We.Retail Journal app is for demonstration purposes only and therefore uses Node.js as a simple example instead of the recommended Adobe I/O Runtime. This example 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.
Adobe I/O Runtime is the recommended solution for implementing SSR for SPAs in AEM.
For on-premesis AEM instances, it is also possible to implement SSR using a custom Node.js instance in the same way as described above. Although this is supported by Adobe, it is not recommended.
Node.js is not supported for Adobe-hosted AEM instances.
If SSR must be implemented via Node.js, Adobe recommends a separate Node.js instance for every AEM environment (author, publish, stage, etc.).
The Remote Content Renderer Configuration that is required to use SSR with your SPA in AEM taps into a more generalized rendering service that can be extended and customized to meet your needs.
RemoteContentRenderingService
is an OSGi service to retrieve content rendered on a remote server, such as from Adobe I/O. The content sent to the remote server is based on the request parameter passed.
RemoteContentRenderingService
can be injected by dependency inversion into either a custom Sling model or servlet when additional content manipulation is required.
This service is internally used by the RemoteContentRendererRequestHandlerServlet.
The RemoteContentRendererRequestHandlerServlet
can be used to programmatically set the request configuration. DefaultRemoteContentRendererRequestHandlerImpl
, the provided default request handler implementation, allows you to create multiple OSGi configurations in order to map a location in the content structure to a remote endpoint.
To add a custom request Handler, implement the RemoteContentRendererRequestHandler
interface. Be sure to set the Constants.SERVICE_RANKING
component property to an integer higher than 100, which is the ranking of the DefaultRemoteContentRendererRequestHandlerImpl
.
@Component(immediate = true,
service = RemoteContentRendererRequestHandler.class,
property={
Constants.SERVICE_RANKING +":Integer=1000"
})
public class CustomRemoteContentRendererRequestHandlerImpl implements RemoteContentRendererRequestHandler {}
The configuration of the default handler must be configured as described in the section Remote Content Renderer Configuration.
To have a servlet fetch and return some content that can be injected into the page:
Usually, the HTL template of a page component is the main recipient of such a feature.
<sly data-sly-resource="${resource @ resourceType='cq/remote/content/renderer/request/handler'}" />
The servlets leverage the Sling Model Exporter to serialize the component data. By default, both the com.adobe.cq.export.json.ContainerExporter
and com.adobe.cq.export.json.ComponentExporter
are supported as Sling Model adapters. If necessary, you can add classes that the request should be adapted to using the RemoteContentRendererServlet
and implementing the RemoteContentRendererRequestHandler#getSlingModelAdapterClasses
. The additional classes must extend the ComponentExporter
.