AEM Cloud Service - React SPA with SSR (Server Side Render) with Local Express Server

Goal

This post puts together the pieces for rendering a AEM SPA Page Server Side, running a NodeJS Express Server locally. For more on this check documentation

Package Install | Github


Solution

1) Create the project with flag -DenableSSR=y

mvn -B org.apache.maven.plugins:maven-archetype-plugin:3.2.1:generate -D archetypeGroupId=com.adobe.aem 
-D archetypeArtifactId=aem-project-archetype -D archetypeVersion=36 -D aemVersion="cloud"
-D appTitle="Experience AEM React SSR Sample" -D appId="eaem-sites-react-spa-ssr" -D groupId="apps.experienceaem.sites"
-D frontendModule=react -D includeExamples=n -D includeDispatcherConfig=n -DenableSSR=y

2) For this sample removed all additional components except the Text and Page components


3)  Build and install the package to local AEM using cmd mvn -PautoInstallPackage clean install (make sure you have maven > 3.6.0), assuming you have node and npm installed for building the ui.frontend module

4) At this point you should be able to see the client side rendered SPA page http://localhost:4502/content/eaem-sites-react-spa-ssr/us/en/home.html


5) Build and Run the Local Express Server

                    eaem-sites-react-spa-ssr\ui.frontend> npm run build-with-express

                    eaem-sites-react-spa-ssr\ui.frontend> npm run start-ssr-express



6) Using POSTMan, check if you can POST the Sling Model JSON to Express and get the html back (rendered by ReactDOMServer.renderToString() in eaem-sites-react-spa-ssr\ui.frontend\src\server\aem-processor.functions.js). Get the Sling Model JSON first by accessing http://localhost:4502/content/eaem-sites-react-spa-ssr/us/en.model.json and use it in the request body to express server...

                    POST to http://localhost:3233/api/v1/web/guest/eaem-sites-react-spa-ssr-0.1.0/ssr/content/eaem-sites-react-spa-ssr/us/en/home.html



6) So Express server is now returning html. Hook AEM up with Express server so AEM can get this html response and add in page body. Check the Remote Renderer OSGI Service configuration, properties should be set for AEM to communicate with Express Server running locally...

                   http://localhost:4502/system/console/configMgr/com.adobe.cq.remote.content.renderer.impl.factory.ConfigurationFactoryImpl~eaem-ssr




7) Page body eaem-sites-react-spa-ssr\ui.apps\src\main\content\jcr_root\apps\eaem-sites-react-spa-ssr\components\page\body.html includes the resourceType cq/remote/content/renderer/request/handler for invoking Remote Renderer and get the html...

<!-- this starts the SSR rendering chain !-->

<div id="spa-root" data-sly-resource="${resource @ resourceType='cq/remote/content/renderer/request/handler'}"></div>

8) With Express server running locally on 3233 and Remote Renderer OSGI service configured to get the html response from express server, accessing http://localhost:4502/content/eaem-sites-react-spa-ssr/us/en/home.html should now return full html response from AEM, decreasing initial page load time of SPA and better SEO...




9) Here server is building the initial html, so in eaem-sites-react-spa-ssr\ui.frontend\src\index.js instead of using render() use hydrate() function

For Client Side Rendering of Initial Html....
 

const renderApp = () => {
ModelManager.initialize(modelManagerOptions).then(pageModel => {
const history = createBrowserHistory();
render(
<Router history={history}>
<App... />
</Router>,
document.getElementById('spa-root')
);
});
};

For Server Side Rendering of Initial Html....

const hydrateApp = (initialState) => {
modelManagerOptions.model = initialState.rootModel;
ModelManager.initialize(modelManagerOptions).then(pageModel => {
const history = createBrowserHistory();
hydrate(
<Router history={history}>
<App.../>
</Router>,
document.getElementById('spa-root')
);
});
}

No comments:

Post a Comment