Comment Sling résout une requête vers un composant AEM
Comment Sling transforme une URL en Resource puis en composant AEM via sling:resourceType, les search paths /apps et /libs, et pourquoi sling:resourceSuperType est le bon moyen d'étendre les Core Components.
Quand AEM affiche une page, ce qui se passe réellement en dessous est une
résolution Sling en deux étapes : d’abord une URL devient une Resource,
puis cette Resource devient un composant — un script HTL ou un servlet —
qui décide du HTML renvoyé. Comprendre ce pipeline explique pourquoi
/apps peut prendre le pas sur /libs, pourquoi les Core Components
s’étendent via sling:resourceSuperType plutôt que d’être directement
écrasés, et pourquoi un sélecteur mal placé peut casser le cache du
Dispatcher.
De l’URL à la Resource
Quand une requête comme /content/monsite/fr/accueil.html arrive, Sling
découpe le chemin en resource path, sélecteurs et extension, puis utilise
le ResourceResolver pour associer /content/monsite/fr/accueil à un
véritable nœud JCR. Dans un projet AEM, ce nœud est généralement une page
(cq:Page), mais ce qui compte réellement pour le rendu, c’est son nœud
jcr:content (ou celui d’un composant enfant), car c’est là que vit la
propriété sling:resourceType.
De la Resource au composant : sling:resourceType
sling:resourceType n’est pas un chemin absolu : c’est un chemin relatif
que Sling recherche dans une liste ordonnée de search paths. Par
exemple, si un composant a :
sling:resourceType = "monprojet/components/hero"
Sling recherche un script (.html, compilé de HTL vers du Java en
coulisses) ou un servlet dont le chemin, relatif à l’un des search paths,
correspond à monprojet/components/hero.
Les search paths de Sling : pourquoi /apps passe avant /libs
La configuration par défaut de Sling (resource.resolver.searchpath) est
["/apps", "/libs"]. Cela signifie que pour un même sling:resourceType,
Sling essaie toujours le script trouvé sous /apps avant celui trouvé
sous /libs. C’est le mécanisme technique derrière l’« overlay »
classique d’AEM : si une ressource produit se trouve dans
/libs/quelquechose/composant et que vous placez un script dans
/apps/quelquechose/composant, c’est le vôtre qui l’emporte.
Sur AEM as a Cloud Service, /libs est totalement immuable — vous n’y
déploierez jamais rien. Cet overlay par search path reste réel pour
certaines ressources de plateforme encore présentes sous /libs (des
parties de Granite UI ou de la console OSGi, par exemple), mais ce n’est
pas le mécanisme à utiliser pour étendre les AEM Core Components — et
c’est une erreur fréquente.
Pourquoi les Core Components ne s’overlay pas : sling:resourceSuperType
Les AEM Core Components (core/wcm/components/...) sont livrés comme
dépendance de votre projet et finissent installés sous /apps, pas sous
/libs. Comme ils sont déjà dans /apps, vous ne pouvez pas les
« battre » en plaçant quelque chose sur le même sling:resourceType sous
/apps sans remplacer entièrement le composant produit — perdant ainsi
toute amélioration future publiée par Adobe.
Le bon modèle est l’héritage de composants via sling:resourceSuperType :
<!-- /apps/monprojet/components/text/.content.xml -->
<jcr:root
jcr:primaryType="cq:Component"
jcr:title="Text"
sling:resourceSuperType="core/wcm/components/text/v2/text"/>
Avec cela, votre composant monprojet/components/text hérite de tout ce
que vous ne surchargez pas explicitement (dialogue, script HTL, Sling
Model) depuis le resourceSuperType. Si votre script HTL ne définit pas
un bloc donné, Sling remonte la chaîne de resourceSuperType jusqu’à le
trouver dans le Core Component. C’est ce qui permet de ne personnaliser
que les 10 % dont vous avez besoin sans dupliquer les 90 % restants.
Les sélecteurs et l’extension changent aussi le script choisi
Les sélecteurs et l’extension de la requête (.html, .json, un
sélecteur comme .print) entrent aussi dans la résolution : Sling
recherche d’abord un script spécifique à cette combinaison
(text.print.html) avant de retomber sur le script par défaut
(text.html). C’est exactement ce qu’utilise le JSON Exporter d’AEM
(.model.json) pour servir la représentation Sling Model d’un composant
sans toucher au script de rendu normal.
Où cela compte dans un vrai projet AEM
- Débogage du rendu : si un composant n’utilise pas votre script,
soupçonnez d’abord le search path (votre script est-il vraiment sous
/apps?) puissling:resourceSuperType(votre composant hérite-t-il du bonresourceType, et de la bonne version — par exempletext/v2/text, pastext/v1/text?). - Mises à jour des Core Components : comme vous étendez par héritage et non par overlay, monter de version les Core Components ne vous oblige pas à réconcilier un fork complet du composant.
- Cache du Dispatcher : chaque combinaison distincte de sélecteur/extension utilisée par votre projet doit être prise en compte dans les règles de cache du Dispatcher ; un sélecteur « de débogage » oublié en production peut générer des entrées de cache inutiles ou, pire, du contenu non mis en cache là où il devrait l’être.