Goal
Adobe Experience Manager 2021.10.5933.20211012T154732Z-210900 (Oct 12, 2021)
This post is on making necessary changes in React SPA generated by the maven archetype (https://github.com/adobe/aem-project-archetype) to shorten the URLs eg. /content/eaem-spa-short-urls/us/en/home.html to /us/en/home.html
For Vanity urls check this post
Solution
1) Create the React SPA maven project using following command...
mvn -B archetype:generate -D archetypeGroupId=com.adobe.aem -D archetypeArtifactId=aem-project-archetype -D archetypeVersion=31 -D aemVersion=cloud -D appTitle="Experience AEM Short URLs" -D appId="eaem-spa-short-urls" -D groupId="apps.experienceaem.sites" -D frontendModule=react -D includeExamples=n -D includeDispatcherConfig=n
2) Create script eaem-spa-short-urls\ui.frontend\src\components\appConstants.js with the following code to give App root url...
export const PROJECT_URL_ROOT = "/content/eaem-spa-short-urls";
3) Adjust Router code to add the shortened URL in eaem-spa-short-urls\ui.frontend\src\components\RouteHelper\RouteHelper.js
import React, {Component} from 'react';
import {Route} from 'react-router-dom';
import {AuthoringUtils} from "@adobe/aem-spa-page-model-manager";
import {PROJECT_URL_ROOT} from "../appConstants";
export const withRoute = (WrappedComponent, extension) => {
return class CompositeRoute extends Component {
render() {
let routePath = this.props.cqPath;
if (!routePath) {
return <WrappedComponent {...this.props} />;
}
extension = extension || 'html';
let paths = ['(.*)' + routePath + '(.' + extension + ')?'];
if (!AuthoringUtils.isInEditor() && routePath.startsWith(PROJECT_URL_ROOT)) {
paths.push(routePath.substring(PROJECT_URL_ROOT.length) + ".html");
}
console.log(paths);
// Context path + route path + extension
return (
<Route
key={routePath}
exact
path={ paths }
render={routeProps => {
return <WrappedComponent {...this.props} {...routeProps} />;
}}
/>
);
}
};
};
4) Adjust the code in Navigation components to create links to shortened urls eg. eaem-spa-short-urls\ui.frontend\src\components\Nav\Nav.js
class NavItem extends Component {
render() {
if(!this.props.path || !this.props.title || !this.props.url) {
return null;
}
let url = this.props.url;
url = url.substring(PROJECT_URL_ROOT.length);
return (
<li className="NavItem" key={this.props.path}>
<Link className="NavItem-link" to={url}>
{this.props.title}
</Link>
</li>
);
}
}
5) Under the hood, app makes calls to AEM for the model.json eg. /content/eaem-spa-short-urls/us/en.model.json, however due to the shortened url it makes additional call for fetching the model.json using shortened one eg. us/en.model.json. To snub this additional request to server, extend the ModelClient, creating ShortURLModelClient in eaem-spa-short-urls\ui.frontend\src\index.js and ignore such requests....
class ShortURLModelClient extends ModelClient {
fetch(modelPath) {
//if the path does not start with /content (page editing) or /conf (template editing) return empty model
if (modelPath && !/^\/content|^\/conf/.test(modelPath)) {
return Promise.resolve({});
} else {
return super.fetch(modelPath);
}
}
}
const modelManagerOptions = {};
if (process.env.REACT_APP_PROXY_ENABLED) {
modelManagerOptions.modelClient = new LocalDevModelClient(process.env.REACT_APP_API_HOST);
} else {
modelManagerOptions.modelClient = new ShortURLModelClient(process.env.REACT_APP_API_HOST);
}
6) For handling the Resource mapping of URL eg. /us/en/home.html and do an internal redirect to the real url eg. /content/eaem-spa-short-urls/us/en/home.html, create the following etc/map entries (there are many ways to handle redirects; on publish generally the preferred way is to use dispatcher rewrites, dispatcher/src/conf.d/rewrites/rewrite.rules). However to keep things simple, adding an etc/map entry in eaem-spa-short-urls\ui.content\src\main\content\jcr_root\etc\map\https\author-p10961-e90064\.content.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
jcr:primaryType="sling:Mapping"
sling:internalRedirect="/content/eaem-spa-short-urls/us/"
sling:match="author-p10961-e90064.adobeaemcloud.com/us/"/>