AEM Guide

Ce qui appartient vraiment au module ui.apps (et ce qui n'y appartient pas)

Un guide pratique de ce que le module Maven ui.apps d'un projet AEM doit contenir — composants, clientlibs, dictionnaires i18n — et pourquoi le contenu rédigé par les auteurs n'y a jamais sa place, avec les règles filter.xml de FileVault qui décident ce qui est écrasé ou supprimé à chaque déploiement.

ui.appsfilevaultmavencontent-packagecloud-manager

ui.apps est le module Maven d’un projet AEM qui construit un package de contenu FileVault s’installant dans /apps. Ça, tout développeur AEM le sait. Ce qui provoque de vrais incidents est moins évident : quels nœuds exactement ont le droit d’y vivre, et ce que fait le filter.xml du package avec tout ce qu’il trouve d’autre sous ces chemins au moment du déploiement. Si le périmètre est mal défini, un déploiement ui.apps de routine peut supprimer silencieusement du contenu qui n’a rien à voir avec votre changement.

Cet article suppose que vous connaissez déjà la structure multimodule standard (core, ui.apps, ui.content, ui.frontend…) — il se concentre uniquement sur ce que ui.apps doit contenir et sur la façon dont son filtre FileVault contrôle ce qui se passe à l’installation.

Ce que ui.apps livre réellement

ui.apps est un package de contenu de type packageType=application. Sur AEM as a Cloud Service, un package de type application ne peut toucher qu’à /apps — jamais /content, /conf, ni aucune autre zone modifiable au runtime. Ce qui appartient sous /apps est, par définition, du code et de la configuration écrits par des développeurs et livrés via CI/CD, pas du contenu rédigé par des éditeurs dans l’interface AEM :

Une chose qui surprend les équipes qui pensent tout en termes de /apps : les définitions de templates éditables et leurs policies ne sont pas livrées depuis ui.apps, même si elles ressemblent à du “code”. Un cq:Template et ses nœuds cq:Policy vivent sous /conf/mysite/settings/wcm/..., et /conf est un chemin mutable, modifiable par les auteurs — les policies en particulier sont régulièrement modifiées par les auteurs via l’interface “Edit Template” en production. Comme un package application ne peut toucher qu’à /apps, les templates et les policies doivent être livrés depuis un package de type content (généralement ui.content, ou un module dédié de configuration/structure), typiquement avec mode="merge" pour qu’un redéploiement n’écrase pas les réglages de policy qu’un auteur a faits après la mise en production. Ce qui appartient réellement à ui.apps dans le monde des templates, c’est le code du composant de structure — le HTL/Java derrière le layout container — pas le nœud de template ni celui de la policy.

Pourquoi le contenu rédigé ne doit jamais vivre dans ui.apps

Les pages sous /content, les assets DAM sous /content/dam, et les tags utilisés pour classer ce contenu relèvent de ui.content, jamais de ui.apps — et ce n’est pas qu’une question de style, c’est imposé par AEM as a Cloud Service : un même package de contenu ne peut pas déployer à la fois vers /apps et vers une zone modifiable au runtime comme /content. Mais même en dehors de cette règle stricte, mélanger les deux cause de vrais dégâts :

filter.xml : ce qu’un filter root contrôle réellement

Chaque package de contenu — ui.apps compris — déclare son périmètre dans META-INF/vault/filter.xml via des éléments <filter root="...">. Un filter root n’est pas une indication de “là où ce package met généralement ses fichiers” ; selon la documentation d’Apache Jackrabbit FileVault, il définit le sous-arbre que le package possède aux fins de l’import :

Ce seul fait — les chemins déclarés mais non couverts par le contenu du package sont supprimés, pas ignorés — est le mécanisme derrière presque tous les incidents du type « un déploiement a effacé du contenu qui n’avait rien à voir avec mon changement ».

Un filter.xml réaliste pour ui.apps

<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
    <filter root="/apps/mysite/components"/>
    <filter root="/apps/mysite/clientlibs"/>
    <filter root="/apps/mysite/i18n"/>
</workspaceFilter>

Trois roots étroits et explicites — chacun correspondant exactement au sous-arbre dont ce module est responsable. Rien ici ne revendique /apps en bloc, et rien ici n’atteint /conf ou /content.

L’erreur du root trop large

<filter root="/apps"/>

Ça ressemble à un raccourci inoffensif — « on possède /apps/mysite, et /apps/mysite est sous /apps, alors pourquoi pas ». Mais le filter root est /apps lui-même. À l’installation, FileVault considère désormais que tout l’arbre /apps — y compris les Core Components d’AEM eux-mêmes sous /apps/core, le package d’une autre équipe sous /apps/othersite, n’importe quoi — est couvert par ce package. Comme le jcr_root de votre package ne contient réellement que apps/mysite/..., tout le reste sous /apps est « couvert mais non contenu », et est supprimé à l’import. C’est exactement comme ça qu’un déploiement ui.apps de routine met à terre les Core Components ou une application voisine sur une instance AEM partagée.

L’erreur du root trop étroit

<filter root="/apps/mysite/components"/>
<!-- quelqu'un ajoute /apps/mysite/templates/structure localement
     et oublie d'ajouter un filter root pour ce chemin -->

Le content-package-maven-plugin construit le package strictement à partir de ce que couvre filter.xml. Un dossier ajouté sous jcr_root qui n’est sous aucun filter root déclaré est simplement exclu du package construit — sans avertissement, sans échec de build. Il est committé dans git, il existe sur disque, et il n’atteint jamais l’instance cible. C’est le mode d’échec le plus silencieux : rien ne casse visiblement, une fonctionnalité n’apparaît tout simplement jamais, et la correction est généralement « quelqu’un a oublié d’ajouter une ligne <filter root> ».

Où cela se manifeste en pratique