While the SPA codebase is managed outside of AEM, an AEM project is required to setup supporting configuration and content requirements. This chapter walks through the creation of an AEM project that contains necessary configurations:
Download the aem-guides-wknd-graphql
project from Github.com. This will contain some baseline files used in this project.
$ mkdir -p ~/Code
$ git clone https://github.com/adobe/aem-guides-wknd-graphql.git
$ cd remote-spa-tutorial
Create an AEM project in which configurations and baseline content are managed. This project will be generated within the cloned aem-guides-wknd-graphql
project’s remote-spa-tutorial
folder.
Always use the latest version of the AEM Archetype.
$ cd ~/Code/aem-guides-wknd-graphql/remote-spa-tutorial
$ mvn -B archetype:generate \
-D archetypeGroupId=com.adobe.aem \
-D archetypeArtifactId=aem-project-archetype \
-D archetypeVersion=39 \
-D aemVersion=cloud \
-D appTitle="WKND App" \
-D appId="wknd-app" \
-D groupId="com.adobe.aem.guides.wkndapp" \
-D frontendModule="react"
$ mv ~/Code/aem-guides-wknd-graphql/remote-spa-tutorial/wknd-app ~/Code/aem-guides-wknd-graphql/remote-spa-tutorial/com.adobe.aem.guides.wknd-app
The last command simply renames the AEM project folder so it is clear it’s the AEM project, and not to be confused with Remote SPA_
While frontendModule="react"
is specified, the ui.frontend
project is not used for the Remote SPA use case. The SPA is developed and managed externally to AEM and only uses AEM as a content API. The frontendModule="react"
flag is required for the project include the spa-project
AEM Java™ dependencies and set up the Remote SPA Page Templates.
The AEM Project Archetype generates the following elements that used to configure AEM for integration with the SPA.
ui.apps/src/.../apps/wknd-app/components
ui.apps/src/.../apps/wknd-app/components/remotepage
ui.content/src/.../conf/wknd-app/settings/wcm/templates
ui.content/src/...
ui.content/src/.../content/wknd-app
ui.config/src/.../apps/wknd-app/osgiconfig
With the base AEM project is generated, a few adjustments ensure SPA Editor compatibility with Remote SPAs.
Since the SPA is a Remote SPA, assume it’s developed and managed outside of the AEM project. To avoid conflicts, remove the ui.frontend
project from deploying. If the ui.frontend
project is not removed, two SPAs, the default SPA provided in the ui.frontend
project and the Remote SPA, is loaded at the same time in the AEM SPA Editor.
Open the AEM project (~/Code/aem-guides-wknd-graphql/remote-spa-tutorial/com.adobe.aem.guides.wknd-app
) in your IDE
Open the root pom.xml
Comment the <module>ui.frontend</module
out from the <modules>
list
<modules>
<module>all</module>
<module>core</module>
<!-- <module>ui.frontend</module> -->
<module>ui.apps</module>
<module>ui.apps.structure</module>
<module>ui.config</module>
<module>ui.content</module>
<module>it.tests</module>
<module>dispatcher</module>
<module>ui.tests</module>
<module>analyse</module>
</modules>
The pom.xml
file should look like:
Open the ui.apps/pom.xml
Comment out the <dependency>
on <artifactId>wknd-app.ui.frontend</artifactId>
<dependencies>
<!-- Remote SPA project will provide all frontend resources
<dependency>
<groupId>com.adobe.aem.guides.wkndapp</groupId>
<artifactId>wknd-app.ui.frontend</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
-->
</dependencies>
The ui.apps/pom.xml
file should look like:
If the AEM project was built before these changes, manually delete the ui.frontend
generated Client Library from the ui.apps
project at ui.apps/src/main/content/jcr_root/apps/wknd-app/clientlibs/clientlib-react
.
For AEM to load the Remote SPA in the SPA Editor, mappings between the SPA’s routes and the AEM Pages used to open and author content must be established.
The importance of this configuration is explored later.
The mapping can be done with Sling Mapping defined in /etc/map
.
In the IDE, open the ui.content
subproject
Navigate to src/main/content/jcr_root
Create a folder etc
In etc
, create a folder map
In map
, create a folder http
In http
, create a file .content.xml
with the contents:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:Mapping">
<localhost_any/>
</jcr:root>
In http
, create a folder localhost_any
In localhost_any
, create a file .content.xml
with the contents:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:Mapping"
sling:match="localhost\\.\\d+">
<wknd-app-routes-adventure/>
</jcr:root>
In localhost_any
, create a folder wknd-app-routes-adventure
In wknd-app-routes-adventure
, create a file .content.xml
with the contents:
<?xml version="1.0" encoding="UTF-8"?>
<!--
The 'wknd-app-routes-adventure' mapping, maps requests to the SPA's adventure route
to it's corresponding page in AEM at /content/wknd-app/us/en/home/adventure/xxx.
Note the adventure AEM pages are created directly in AEM.
-->
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:Mapping"
sling:match="adventure:.*/([^/]+)/?$"
sling:internalRedirect="/content/wknd-app/us/en/home/adventure/$1"/>
Add the mapping nodes to ui.content/src/main/content/META-INF/vault/filter.xml
to they included in the AEM package.
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/conf/wknd-app" mode="merge"/>
<filter root="/content/wknd-app" mode="merge"/>
<filter root="/content/dam/wknd-app/asset.jpg" mode="merge"/>
<filter root="/content/experience-fragments/wknd-app" mode="merge"/>
<!-- Add the Sling Mapping rules for the WKND App -->
<filter root="/etc/map" mode="merge"/>
</workspaceFilter>
The folder structure and .context.xml
files should look like:
The filter.xml
file should look like:
Now, when the AEM project is deployed, these configurations are automatically included.
The Sling Mapping effects AEM running on http
and localhost
, so only support local development. When deploying to AEM as a Cloud Service, similar Sling Mappings must be added that target https
and the appropriate AEM as a Cloud Service domain/s. For more information, see the Sling Mapping documentation.
Next, configure AEM to protect the content so only this SPA can access the AEM content. Configure Cross-Origin Resource Sharing in AEM.
In your IDE, open the ui.config
Maven subproject
Navigate src/main/content/jcr_root/apps/wknd-app/osgiconfig/config
Create a file named com.adobe.granite.cors.impl.CORSPolicyImpl~wknd-app_remote-spa.cfg.json
Add the following to the file:
{
"supportscredentials":true,
"exposedheaders":[
""
],
"supportedmethods":[
"GET",
"HEAD",
"POST",
"OPTIONS"
],
"alloworigin":[
"https://external-hosted-app", "localhost:3000"
],
"maxage:Integer":1800,
"alloworiginregexp":[
".*"
],
"allowedpaths":[
".*"
],
"supportedheaders":[
"Origin",
"Accept",
"X-Requested-With",
"Content-Type",
"Access-Control-Request-Method",
"Access-Control-Request-Headers",
"authorization"
]
}
The com.adobe.granite.cors.impl.CORSPolicyImpl~wknd-app_remote-spa.cfg.json
file should look like:
The key configuration elements are:
alloworigin
specifies which hosts are allowed to retrieve content from AEM.
localhost:3000
is added to support the SPA running locallyhttps://external-hosted-app
acts as a placeholder to be replaced with the domain that Remote SPA is hosted on.allowedpaths
specify which paths in AEM are covered by this CORS configuration. The default allows access to all content in AEM, however this can be scoped to only the specific paths the SPA can access, for example: /content/wknd-app
.The AEM Project Archetype generates a project primed for AEM’s integration with a Remote SPA, but requires a small, but important adjustment to auto-generated AEM page structure. The auto-generated AEM page must have its type changed to Remote SPA page, rather than a SPA page.
In your IDE, open the ui.content
subproject
Open to src/main/content/jcr_root/content/wknd-app/us/en/home/.content.xml
Update this .content.xml
file with:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="cq:Page">
<jcr:content
cq:template="/conf/wknd-app/settings/wcm/templates/spa-remote-page"
jcr:primaryType="cq:PageContent"
jcr:title="WKND App Home Page"
sling:resourceType="wknd-app/components/remotepage">
<root
jcr:primaryType="nt:unstructured"
sling:resourceType="wcm/foundation/components/responsivegrid">
<responsivegrid
jcr:primaryType="nt:unstructured"
sling:resourceType="wcm/foundation/components/responsivegrid">
<text
jcr:primaryType="nt:unstructured"
sling:resourceType="wknd-app/components/text"
text="<p>Hello World!</p>"
textIsRich="true">
<cq:responsive jcr:primaryType="nt:unstructured"/>
</text>
</responsivegrid>
</root>
</jcr:content>
</jcr:root>
The key changes are updates to the jcr:content
node’s:
cq:template
to /conf/wknd-app/settings/wcm/templates/spa-remote-page
sling:resourceType
to wknd-app/components/remotepage
The src/main/content/jcr_root/content/wknd-app/us/en/home/.content.xml
file should look like:
These changes allow this page, which acts are the SPA’s root in AEM, to load the Remote SPA in SPA Editor.
If this project was previously deployed to AEM, make sure to delete the AEM page as Sites > WKND App > us > en > WKND App Home Page, as the ui.content
project is set to merge nodes, rather than update.
This page could also be removed and re-created as a Remote SPA Page in AEM itself, however since this page is auto-created in the ui.content
project it is best to update it in the code base.
Ensure that AEM Author service is running on port 4502
From the command line, navigate to the root of the AEM Maven project
Use Maven to deploy the project to your local AEM SDK Author service
$ mvn clean install -PautoInstallSinglePackage
With the AEM Project deployed, there is one last step to prepare SPA Editor to load our Remote SPA. In AEM, mark the AEM page that corresponds to the SPA’s root,/content/wknd-app/us/en/home
, generated by the AEM Project Archetype.
Log in to AEM Author
Navigate to Sites > WKND App > us > en
Select the WKND App Home Page, and tap Properties
Navigate to the SPA tab
Fill out the Remote SPA Configuration
http://localhost:3000
Tap Save & Close
Remember that we changed this page’s type to that of a Remote SPA Page, which is what allows us to see the SPA tab in its Page Properties.
This configuration only must be set on the AEM page that corresponds to the root of the SPA. All AEM pages beneath this page inherit the value.
You’ve now prepared AEM’s configurations and deployed them to your local AEM author! You now know how to:
ui.frontend
With AEM configured, we can focus on bootstrapping the Remote SPA with support for editable areas using AEM SPA Editor!