AEM Guide

Comment un projet Maven AEM construit réellement un package déployable

Comment le pom.xml parent et les modules core, ui.apps, ui.content, ui.config et all d'un projet AEM se combinent pour produire un unique package déployable, et pourquoi le module all est la véritable unité de déploiement.

mavenarchetypecloud-managerci-cdpackaging

Un projet AEM généré avec l’AEM Project Archetype ne produit pas un seul artefact : il en produit une demi-douzaine. La confusion habituelle pour quelqu’un qui découvre un projet AEM n’est pas “que fait Maven”, mais “lequel de tous ces pom.xml est réellement déployé sur l’instance”. La réponse courte : presque aucun individuellement — ce qui est déployé est le résultat d’un module précis, all, qui assemble tous les autres.

La structure multimodule générée par l’archetype

En générant un projet avec com.adobe.aem:aem-project-archetype, on obtient un pom.xml parent (agrégateur) à la racine et plusieurs modules enfants, chacun avec son propre pom.xml et son propre type d’empaquetage. Les modules standards sont :

Les détails internes de ui.apps et ui.frontend méritent leur propre article — ce qui compte ici, c’est la façon dont tous les modules s’assemblent pour produire le package final, pas leur fonctionnement interne respectif.

Deux types d’empaquetage : bundle vs. content-package

core est le seul module avec un empaquetage jar classique : c’est un bundle OSGi comme un autre, compilé et empaqueté avec le plugin de bundle habituel. Les autres modules producteurs de contenu (ui.apps, ui.content, ui.config, all) utilisent l’empaquetage content-package, construit par le filevault-package-maven-plugin (org.apache.jackrabbit). Ce plugin a remplacé l’ancien content-package-maven-plugin d’Adobe/Day et est actuellement le seul supporté sur AEM as a Cloud Service.

Chaque module de type content-package déclare également un packageType dans la configuration du plugin :

Cette classification n’est pas cosmétique : la validation de packages de Cloud Manager s’en sert pour rejeter les builds où, par exemple, un package marqué application touche des chemins /content qui ne lui appartiennent pas.

Le module all : comment le package final est assemblé

Le pom.xml de all déclare des dépendances de type zip (ou jar pour core) vers les autres modules, et la configuration du filevault-package-maven-plugin utilise <embeddeds> pour indiquer à quel chemin d’installation chacun doit être embarqué dans le package conteneur. C’est l’approche actuelle ; l’ancien mécanisme <subPackages> est déprécié.

<!-- all/pom.xml (fragment) -->
<plugin>
  <groupId>org.apache.jackrabbit</groupId>
  <artifactId>filevault-package-maven-plugin</artifactId>
  <extensions>true</extensions>
  <configuration>
    <group>com.myproject</group>
    <packageType>container</packageType>
    <embeddeds>
      <embedded>
        <groupId>com.myproject</groupId>
        <artifactId>myproject.core</artifactId>
        <type>jar</type>
        <target>/apps/myproject-packages/application/install</target>
      </embedded>
      <embedded>
        <groupId>com.myproject</groupId>
        <artifactId>myproject.ui.apps</artifactId>
        <type>zip</type>
        <target>/apps/myproject-packages/application/install</target>
      </embedded>
      <embedded>
        <groupId>com.myproject</groupId>
        <artifactId>myproject.ui.content</artifactId>
        <type>zip</type>
        <target>/apps/myproject-packages/content/install</target>
      </embedded>
    </embeddeds>
  </configuration>
</plugin>

Chaque <embedded> nécessite une <dependency> correspondante dans le même pom.xml, pointant vers la version de l’artefact du module frère (normal dans un reactor Maven, où ${project.version} garde tous les modules synchronisés).

Pourquoi c’est important : un artefact déployable unique

Exécuter mvn clean install sur le module all produit un unique .zip installable. Plutôt que d’uploader manuellement quatre ou cinq packages dans le bon ordre vers Package Manager, ou de coordonner plusieurs étapes dans un pipeline de déploiement, le pipeline Cloud Manager (ou tout script de déploiement direct) upload et active un seul package. Ce package unique est ce qui définit réellement quelle version du code et du contenu tourne sur une instance AEM à un instant donné.

C’est aussi ce qui rend le build déterministe : l’agrégateur racine du projet liste les modules sous <modules>, mais c’est le graphe de dépendances déclaré dans chaque pom.xml — pas l’ordre de cette liste — que Maven utilise pour calculer l’ordre réel de construction du reactor.

Où cela se manifeste en pratique