Speed up your Maven AEM application build for AEM Cloud Manager using Gradle AEM Plugin.
A few months ago, AEM became publicly available as a Cloud Service. As a consequence, the future of the
Gradle AEM Plugin (GAP) - a tool that drastically improves developer
efficiency in AEM application development - became a little uncertain. This is because
Cloud Manager, the flagship automation tool of AEM as a
Cloud Service, does not support the Gradle build system. Only Maven
is supported. We understand this choice, but a lot of people who actually have a chance to work with Gradle & GAP value
those tools a lot. Build speed is n‑times faster, configuration capabilities are much richer due to the dynamic
nature of the build script concept used in Gradle, in contrast to static Maven pom.xml
files. The additional tools
around AEM application development improve the developer's daily routine by automation. For example, content
synchronization from and AEM instance takes seconds, not minutes, and downloaded JCR content is even normalized
on-the-fly. All of the improvements designed especially for
A Better AEM Developer Experience,
which was the topic of our talk at the adaptTo() 2018 Conference :)
Whoever does not try will not find out.
That's what I'm often saying to myself and my colleagues when we are trying something completely new. It's hard to come up with new things. It's even more difficult to defend ideas. As an example of such an unusual idea could be an approach for addressing the question - how to improve the developer's experience when they are using AEM Cloud Manager enforcing usage of Maven build tool? As proposing just switching build system from Maven to Gradle is not an option, how about using them both? At first, it could look a bit controversial, but… after deeper investigation and tests, that combination has strong benefits.
The first approach identified is the dual-build. It is about mixing the two build systems, adding Gradle build files to existing AEM projects while keeping them independent from existing Maven build files.
The second, more unusual approach is about splitting Maven build execution into steps - executing Maven for one module at a time, one after another. Let's call it the hybrid-build.
Comparison
Going further, let's compare new approaches with existing one based on own extended fork of Adobe AEM Archetype which allows to generate dual-build or hybrid-build projects interactively:
Task | Build trait | Maven build | Dual-build | Hybrid-build |
---|---|---|---|---|
Build and deploy packages | Command | mvn clean install ‑PautoInstallSinglePackage ‑PautoInstallSinglePackagePublish |
sh gradlew :all:packageDeploy |
sh gradlew :all:packageDeploy |
First time | 1m 11s | 1m 5s (1m 29s) | 1m 44s* (2m 52s) | |
Next time | 43-45s | 1-3s | 1-3s | |
JS/CSS change | 38-39s | 9s (15-16s) | 24s (31-35s) | |
Java change | 33-36s | 6s (14-15s) | 25s (30-32s) | |
Content change | 30-36s | 3s (11-12s) | 11s (16-18s) | |
Setup AEM environment | Command | N/A | sh gradlew setup |
sh gradlew setup |
Time | 30-90m | 5-7m | 5-7m | |
Clean AEM dispatcher cache | Command | N/A | sh gradlew environmentReload |
sh gradlew environmentReload |
Time | 1m | 3s | 3s | |
All-in-one | Command | N/A | sh gradlew develop |
sh gradlew develop |
Time | 30-90m | 6-8m | 7-9m |
Assumptions
- Measurements done on MacBook Pro 2019 (Core i5, 16 GB RAM),
- Using AEM as a Cloud Service SDK (version 2020.6.3800),
-
Building and deploying packages:
- using all assembly package,
- to both AEM author and publish instances,
-
Setting up AEM environment includes:
- downloading, configuring, turning on (with debug port opened) then awaiting stable AEM author and publish instance,
- deploying one extra dependent CRX package (Felix Search Web Console Plugin),
- configuring replication agents for fully operational pages activation and deactivation,
- downloading, configuring, turning on AEM dispatcher using Docker,
- Time value 30-90m proposed for setting up manually AEM environment is just estimation, effectively time depends on AEM developer experience,
- Cleaning AEM dispatcher cache includes also restarting Apache HTTPD Server,
- The All-in-one task encapsulates all tasks mentioned above - it sets up a complete local AEM environment from scratch.
Package deployments
Generally, dual and hybrid builds outperform pure Maven when it comes to execution time (with one exception explained later). This is especially true when helpful but time-consuming extra features of GAP (values in parentheses in the table) are disabled:
- Advanced AEM instance stability checking,
- OakPAL-based CRX package validation,
- Temporarily disabling the DAM update asset workflow during package deployment.
However, the best build performance is definitely the most important advantage of the dual-build approach. The hybrid-build approach also improves it, because of parallel Maven execution.
What's interesting about hybrid-builds is that CRX packages built by Maven are deployed by GAP. This leverages GAP's advanced features, designed for rock-solid AEM deployments, and helps a lot when some or all AEM instances are not stable for unknown reasons. GAP can detect and report precisely what is wrong with any of them. It is also worth mentioning that GAP deploys CRX packages to all instances in parallel, further saving time.
Not only the build times matter. When using Maven, people tend to execute the same command repeatedly, aiming to ensure that all packages and application changes are propagated to AEM instances correctly. However, Maven is not capable of caching the unchanged parts of an application. It is unable to:
- avoid running Node/Webpack when there are no changes in ui.frontend module,
- avoid compiling unchanged Java code in core module,
- and so on…
But Gradle does it all. The problem related with incremental builds is interesting also from even more generic perspective. In AEM projects, there are usually separate roles:
- AEM Frontend developer who is changing most often module ui.frontend,
- AEM Backend developer who is changing modules core, ui.apps etc
They most often perform changes in a single module and would like to build only that module (don't want to build other
modules). In that case, AEM developer needs to know alternative build commands when using Maven
(cd ui.apps && mvn clean install -PautoInstallPackage,autoInstallPackagePublish
). Changing a current working directory
and remembering these profiles with long names might be discouraging.
This well-known scenario plays much better with Gradle-powered AEM Maven builds. AEM Developer can use all the time the
same command - just sh gradlew
. Then Gradle detects changed parts of an application and rebuilds related modules only.
This really makes a big difference! The developer works more effectively because the shortest build time and application
consistency are guaranteed. There is no option to forget about rebuilding some modules - when trying to optimize build
time by building only changed modules by hand when using Maven. That's very comfortable and is protecting developer
against errors.
The little disadvantage related to hybrid-build seems to be only the first build time. As of Maven execution is split to parts, there could be a little overhead/time penalty here because of a need for running Maven process multiple times. However, effectively it might be faster because Gradle may execute Maven processes in parallel (especially when AEM project will contain more modules).
Automated local environment setup
Jokingly speaking, GAP fills the gap :) It offers:
-
Automated AEM environment setup:
- Adobe provides only guide describing the manual steps to be done.
- No official way for setting AEM environment in an automated manner.
-
Perfectly-integrated tools useful for AEM application development:
- Parallel & automatic AEM instances configuration - provisioning,
- Reporting detailed status of running instances,
- Interactively tracking errors in logs,
- Easy copying JCR content, between AEM instances,
- And more...
Recommendations
When to use each build approach?
-
Maven build:
- For deployments to higher environments e.g using Cloud Manager to ensure the best compatibility,
-
Dual-build:
- Having best build performance and developer experience is most valuable,
- Maintaining both build systems, effectively updating files build.gradle.kts and pom.xml is affordable,
-
Hybrid-build:
- It is valuable to improve build performance of existing AEM Maven build system,
- Maintaining two separate build systems as in dual-build approach may cost too much,
- Risk of having differences in built CRX packages by separate build systems because of misconfiguration is too high (when comparing to dual-build).
Summary
As the comparison shows, using Gradle/GAP could improve all AEM Maven builds. Mixing build systems may require additional skills, such as learning Gradle a little bit. However, if we consider:
- the time being wasted between incremental application changes done by AEM developers,
- the potential in allowing the team to focus on making software changes by providing them with immediate feedback,
then introducing a separate build system in existing AEM projects starts to sound less like a brave and crazy, bleeding-edge combination and more like a sensible move, translating to faster project delivery, happier content authors and better AEM sites.
To try and see how the dual or hybrid build works in practice, check out the ready-to-use AEM archetypes available on GitHub:
https://github.com/Cognifide/aem-project-archetype
P.S. If you find this topic interesting, make sure to see our live demo at adaptTo() 2020.
Hero image by Matthew Brodeur, opens in a new window
Featured image by Henrik Hansen, opens in a new window