Getting Started with React and AEM SPA Editor - Chapter 0

Chapter 0 details the setup of a Maven multi module AEM project with a dedicated module for Single Page Application or SPA development. The goal for this chapter is to integrate a React project, based on the Create React App, with a traditional AEM Maven build process.

Tutorial Table of Contents


Review the required tooling and instructions for setting up a local development environment here.

New to AEM? Check out how to set up a local development environment.

Download Starter Project

To accelerate the tutorial, we will start from a predefined project. Download the following ZIP file and unzip locally:


You can also clone the Git Repository and start the tutorial from there:

$ git clone 
$ cd aem-guides-wknd-events 
$ git checkout react/start

The AEM Project

Persona: AEM Developer


When starting a new SPA Editor enabled project it is recommended to use the Maven Archetype for SPA Starter Kit.

There are a couple options for creating a Maven Multimodule project for AEM. This tutorial leverages the Maven AEM Project Archetype 14. The recommended approach for starting a new SPA Editor enabled project is to use the Maven Archetype for SPA Starter Kit.

The following properties were used when generating the AEM project from Archetype 14:

Property Value
groupId com.adobe.aem.guides
artifactId aem-guides-wknd-events
version 0.0.1-SNAPSHOT
package com.adobe.aem.guides.wkndevents
appsFolderName wknd-events
artifactName WKND Events
componentGroupName WKND Events - Content
confFolderName wknd-events
contentFolderName wknd-events
cssId wknd-events
packageGroup aem-guides/wknd-events
siteName WKND Events
  1. Inspecting the Project

    There are five areas to the project:

    • Parent POM - deploys maven modules and manages dependency versions
    • core - Java bundle containing all core functionality like OSGi services, listeners or schedulers, as well as component-related Java code such as servlets or request filters.
    • ui.apps - contains the /apps parts of the project, ie JS&CSS clientlibs, components, runmode specific configs as well as Hobbes-tests
    • ui.content - contains structural content and configurations (/content, /conf)
    • react-app - a webpack project for the React application. Later in the chapter the webpack project will be turned into a Maven module to be deployed to AEM as a client library.

    More details about the inner workings of the project can be found in Getting Started with AEM Sites Part 1 - Project Setup.

  2. Build and deploy the project to a local AEM instance

    From the command line, within the aem-guides-wknd-events directory run the following:

    $ mvn clean install -PautoInstallPackage -Padobe-public

    The above command will deploy the project to AEM running on http://localhost:4502.


    The inclusion of the adobe-public profile as part of the Maven command can be made optional. You can avoid having to include this everytime by updating your settings.xml file to include Adobe's nexus repository based on this article.

  3. View Package Manager to verify the deployment

    Navigating to http://localhost:4502/crx/packmgr/index.jsp you should see that 5 packages were installed. The ui.apps and ui.content package for the WKND events project and 3 packages for AEM Core Components.

  4. The ui.content module includes two templates as part of the starter project. Inspect the templates by navigating to: http://localhost:4502/libs/wcm/core/content/sites/templates.html/conf/wknd-events

    You should see a template for WKND Event Page and WKND Event React App:

    The SPA Editor is designed to work with Editable templates. This gives the implementation the full power of re-usable policies and other features. With the initial release of the SPA Editor the UI for Editable Templates cannot be used. This is expected to be updated in the next release of the SPA Editor.

    In order to update features of the template, developers will need to do this manually via CRXDE-Lite or in the XML in the ui.content project. 

    For example, the allowed components on the layout container are defined here:

The React App

Persona: Front End Developer

A starter React application has been created using the create-react-app module from Facebook.

  1. Run the app locally

    Navigate to the react-app directory and run the following commands:

    $ cd <src-dir>/aem-guides-wknd-events/react-app
    $ npm install
    $ npm start
  2. View the app

    The command npm start should launch the React app on a local dev server running at http://localhost:3000/.

  3. Build a production distribution of the app:

    Press ctrl+c to stop the server.

    $ npm run build

    Notice that several files are created beneath the react-app/build folder.


    Next, we will move these files into an AEM client library and deploy as part of the ui.apps module.

Integration Approach

The SPA development will be done in the Webpack project. The compiled SPA, following a production build, is then copied into the ui.apps module as an AEM client-side library and deployed to AEM as part of an AEM package. The concept is similar to the integration of the core Java bundle, where the Java bundle is compiled into a jar file that is embedded into the ui.apps module and deployed to AEM as an AEM package.

To achieve this integration two tools will be used:

  1. aem-clientlib-generator - used to transform compiled CSS and JS files into an AEM client library
  2. frontend-maven-plugin - used to trigger NPM commands via a Maven build. This plugin will download/install Node and NPM locally for the project, ensuring consistency and making the project easy to integrate with a Continuous Integration/Continuous Deployment environment.

Configure aem-clientlibs-generator

Persona: AEM Developer

  1. Install the aem-clientlibs-generator node plugin as part of the react-app project.

    $ cd <src>/aem-guides-wknd-events/react-app
    $ npm install aem-clientlib-generator --save-dev
  2. Notice that package.json has been updated with the dev dependencies for aem-clientlib-generator.


        "devDependencies": {
            "aem-clientlib-generator": "^1.4.1"
  3. Create a new file beneath the aem-guides-wknd-events/react-app folder named clientlib.config.js. Populate the file with the following:

    module.exports = {
        // default working directory (can be changed per 'cwd' in every asset option)
        context: __dirname,
        // path to the clientlib root folder (output)
        clientLibRoot: "./../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs",
        libs: {
            name: "react-app",
            allowProxy: true,
            categories: ["wknd-events.react"],
            serializationFormat: "xml",
            jsProcessor: ["min:gcc"],
            assets: {
                js: [
                css: [


    This file directs the aem-clientlib-generator to create a client library in the ui.apps module beneath /apps/wknd-events/clientlibs. The client library will have a category of wknd-events.react and will include any files with an extension of .js and .css beneath the react-app/build/static folder.


  4. Add the clientlib directive as part of the npm run build script by updating react-app/package.json file with the following line:

     "scripts": {
       "build": "react-scripts build && clientlib --verbose",
  5. Test out the changes by running the following command:

    $ cd <src>/aem-guides-wknd-events/react-app
    $ npm run build
    > react-scripts build && clientlib --verbose
    Creating an optimized production build...
    Compiled successfully.
    File sizes after gzip:
    37.34 KB  build/static/js/main.d1cb61c2.js
    299 B     build/static/css/main.c17080f1.css
    The project was built assuming it is hosted at the server root.
    You can control this with the homepage field in your package.json.
    For example, add this to build it for GitHub Pages:
    "homepage" : "",
    The build folder is ready to be deployed.
    You may serve it with a static server:
    npm install -g serve
    serve -s build
    Find out more about deployment here:
    start aem-clientlib-generator
    working directory: ../src/aem-guides-wknd-events/react-app
    processing clientlib: react-app
    Write node configuration using serialization format: xml
    write clientlib json file: ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/.content.xml
    write clientlib asset txt file (type: js): ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/js.txt
    copy: build/static/js/1.7eae6140.chunk.js ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/js/1.7eae6140.chunk.js
    copy: build/static/js/main.5dd257ec.chunk.js ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/js/main.5dd257ec.chunk.js
    copy: build/static/js/runtime~main.229c360f.js ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/js/runtime~main.229c360f.js
    write clientlib asset txt file (type: css): ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/css.txt
    copy: build/static/css/main.506bfdb1.chunk.css ../ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/css/main.506bfdb1.chunk.css
  6. Beneath /ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/ should be a new folder named react-app and should contain both the css and js files generated from the react app.

  7. (Optional) Ignore the react-app AEM client library in ui.apps from source control.

    The client library react-app in ui.apps should always be generated by the aem-clientlib-generator at build time. It is important ignore this client library from source control. For example, if using Git, a file named .gitignore would be created beneath the ui.apps folder:

    # ui.apps/.gitignore
    # Ignore React generated client libraries from source control

Configure frontend-maven-plugin

Persona: AEM Developer

Next, configure the react-app project to also be a Maven module. This way it can be triggered by the parent reactor POM and the entire AEM project can be built with a single command. As mentioned earlier the frontend-maven-plugin will be used to install and trigger an npm build within the react-app project.

  1. Open up the parent reactor POM, <src>/aem-guides-wknd-events/pom.xml, and add the react-app as a module to build. The order in which the modules are built matters:

        <!-- add React App -->
  2. Within the parent reactor POM, <src>/aem-guides-wknd-events/pom.xml, and add the following properties for the frontend-maven-pluginnode and npm versions.


    Use the same version of node and npm that you have installed locally.

        <!-- Update: Used by frontend-maven-plugin -->
        <!-- end update -->

    These properties will be used by the frontend-maven-plugin to determine the local version of node and npm to install. As a best practice version properties should be managed at the parent pom level.

  3. Create a new file named pom.xml beneath <src>/aem-guides-wknd-events/react-app folder. Populate the pom.xml with the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="" xmlns:xsi="" xsi:schemaLocation="">
        <!-- ====================================================================== -->
        <!-- P A R E N T  P R O J E C T  D E S C R I P T I O N                      -->
        <!-- ====================================================================== -->
        <!-- ====================================================================== -->
        <!-- P R O J E C T  D E S C R I P T I O N                                   -->
        <!-- ====================================================================== -->
        <name>WKND Events - React App</name>
        <description>UI React application code for WKND Events</description>
        <!-- ====================================================================== -->
        <!-- B U I L D   D E F I N I T I O N                                        -->
        <!-- ====================================================================== -->
                <id>install node and npm</id>
                <id>npm install</id>
                <!-- Optional configuration which provides for running any npm command -->
                <id>npm run build</id>
                <arguments>run build</arguments>
  4. Within the react-app folder run the following Maven command to trigger a build:

    $ cd <src>/aem-guides-wknd-events/react-app
    $ mvn clean install

    You should see that the frontend-maven-plugin downloads and installs a local version of node and npm. The command npm run build is then executed which will build the React app and then copy the compiled JS and CSS files into the ui.apps project.

    Check the timestamps of /ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/css/main.<hash>.css and /ui.apps/src/main/content/jcr_root/apps/wknd-events/clientlibs/react-app/js/main.<hash>.js to confirm that these files were just built.

  5. Navigate to the Parent Reactor POM and run the following command to build the entire project and deploy it to AEM:

    $ cd <src>/aem-guides-wknd-events 
    $ mvn -PautoInstallPackage -Padobe-public clean install 
    Package imported. 
    Package installed in 53ms. 
    [INFO] ------------------------------------------------------------------------ 
    [INFO] Reactor Summary: 
    [INFO] aem-guides-wknd-events ............................. SUCCESS [  0.291 s] 
    [INFO] WKND Events - Core ................................. SUCCESS [  2.176 s] 
    [INFO] WKND Events - React App ............................ SUCCESS [ 21.766 s] 
    [INFO] WKND Events - UI apps .............................. SUCCESS [  3.548 s] 
    [INFO] WKND Events - UI content ........................... SUCCESS [  0.302 s] 
    [INFO] ------------------------------------------------------------------------ 
    [INFO] ------------------------------------------------------------------------ 
    [INFO] Total time: 29.073 s 
    [INFO] Finished at: 2018-10-10T10:35:19-04:00 
    [INFO] Final Memory: 49M/617M 
    [INFO] ------------------------------------------------------------------------ 
  6. Navigate to CRXDE-Lite to verify that the React App and the rest of the AEM project has been deployed beneath /apps/wknd-events/clientlibs/react-app.

Integrate the React app on the Page

Persona: AEM Developer

Next we will integrate the React app on to the page via the client library.

Open up the aem-guides-wknd-events/ui.apps project to edit.

  1. Beneath /apps/wknd-events/components/structure/page open the file customheaderlibs.html.

    This HTL template will get loaded in the HTML <head> section.

    Replace the contents of the file with the following:

    Custom Headerlibs for React Site
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta property="cq:datatype" data-sly-test="${wcmmode.edit || wcmmode.preview}" content="JSON"/>
    <meta property="cq:wcmmode" data-sly-test="${wcmmode.edit}" content="edit"/>
    <meta property="cq:wcmmode" data-sly-test="${wcmmode.preview}" content="preview"/>
    <meta property="cq:pagemodel_root_url""com.adobe.aem.guides.wkndevents.core.models.HierarchyPage" 
    <sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
    <sly data-sly-call="${clientlib.css @ categories='wknd-events.react'}"/>

    This will load the CSS for the wknd-events.react client library at the top of the page. This will also set a meta property for cq:pagemodel_root_url. This will be used by the AEM SPA Editor SDK to identify the root page JSON to load.

  2. Beneath /apps/wknd-events/components/structure/page open the file customfooterlibs.html.

    This HTL template will get loaded at the bottom of the page right before the closing </body> tag.

    Replace the contents of the file with the following:

    Custom footer React libs
    <sly data-sly-use.clientLib="${'/libs/granite/sightly/templates/clientlib.html'}"></sly>
    <sly data-sly-test="${wcmmode.edit || wcmmode.preview}"
        data-sly-call="${clientLib.js @ categories='cq.authoring.pagemodel.messaging'}"></sly>
    <sly data-sly-call="${clientLib.js @ categories='wknd-events.react'}"></sly>

    This will load the JS for the wknd-events.react client library at the bottom of the page. The code above also incluces the cq.authoring.pagemodel.messaging when the page is being edited in the AEM environment. This client library allows for the SPA editing capabilities using the AEM Sites Editor.

  3. Create a new file named body.html beneath /apps/wknd-events/components/structure/page

    Populate body.html with the following:

    - body.html
    - includes div that will be targeted by SPA
    <div id="root"></div>

    This will insert the DOM element that the React application is targeting. You can see in the code /aem-guides-wknd-events/react-app/src/index.js:

    ReactDOM.render(<App />, document.getElementById('root'));
  4. Deploy the changes to AEM

    Deploy the changes by running the following maven command from the project root:

    $ cd aem-guides-wknd-events 
    $ mvn -PautoInstallPackage -Padobe-public clean install
  5. Navigate to http://localhost:4502/editor.html/content/wknd-events/react/home.html

    You should now see the React application being rendered on the AEM page.

Next Steps

Next part in the tutorial: 

View the solution for GitHub.

Download the finished package for this part of the tutorial:



If you get stuck or have additional questions make sure to check out the Experience League forums for AEM or review existing GitHub issues

Didn't find what you were looking for? Think you found an error? Please file a GitHub issue for the WKND Events project

Adobe logo

Sign in to your account