Analyse du linting des composants Salesforce Lightning Web (LWC)

This page is not available in the language you requested. You have been redirected to the English version of the page.
Link to this page copied to clipboard

Construisez une configuration de composant étape par étape, en utilisant les composants Salesforce Lightning Web comme exemple concret

Free Trial
Not for use with personal data

Les modèles de composants Salesforce Lightning Web (LWC) sont des fichiers HTML construits à partir d'éléments personnalisés : des composants de base de Salesforce tels que <lightning-button> et <lightning-icon>, ainsi que les composants que vous créez vous-même dans l'espace de noms c-, tels que <c-my-image>. Axe DevTools Linter vérifie les éléments personnalisés dès que vous indiquez ce que ces éléments rendent, en utilisant l'option de configuration global-components.

Cet article construit une configuration LWC depuis zéro. LWC constitue un bon exemple pratique car il met en œuvre chaque partie de la syntaxe de mappage, y compris les composants qui ne rendent aucun élément en propre. La méthode s'applique à toute bibliothèque de composants : décrivez ce que chaque composant rend, vérifiez cette description par rapport à un fichier de test, puis corrigez le mappage chaque fois que les deux ne concordent pas.

Pour une introduction au mappage de composants personnalisés, voir Linting des composants personnalisés. Pour la référence complète de la syntaxe, voir Configuration de Axe DevTools Linter.

Avant de commencer

Ajoutez un fichier axe-linter.yml à la racine de votre projet. Chaque exemple ci-dessous se trouve dans ce fichier. Si vous utilisez le point de terminaison REST au lieu d'une extension d'éditeur, la même configuration se trouve dans l'objet config de la requête, comme indiqué dans Linting des composants personnalisés avec le point de terminaison REST de Axe DevTools Linter.

Un mappage décrit ce que le navigateur reçoit

C'est l'idée qui rend chaque autre décision simple : un mappage décrit l'élément que votre composant rend, et non la balise que vous écrivez dans le modèle.

<lightning-button label="Save"> rend un button dont le contenu textuel est « Enregistrer ». Écrit en tant que mappage, cela donne :

global-components:
  lightning-button:
    element: button
    attributes:
      - label: <text>

La valeur spéciale <text> indique que l'attribut label devient le contenu textuel de l'élément, ce qui donne à un bouton son nom accessible. Avec ce mappage en place, Axe DevTools Linter signale une violation de button-name pour <lightning-button> utilisé sans label, exactement comme il le ferait pour un <button> vide.

Étape 1 : Mapper les composants qui rendent un élément

Commencez par les composants qui se mappent directement sur un seul élément natif et ne mappez que les attributs contenant des informations d'accessibilité.

global-components:
  # Salesforce base components
  lightning-button:
    element: button
    attributes:
      - label: <text>
  lightning-icon:
    element: img
    attributes:
      - alternative-text: alt
  # Components you author yourself
  c-my-image:
    element: img
    attributes:
      - alternative-text: alt

Les noms de composants sont sensibles à la casse et correspondent à la balise telle que vous l'écrivez dans le modèle, donc les noms en kebab-case de LWC sont utilisés tels quels.

Pour les autres valeurs spéciales (aria-* pour passer les attributs ARIA, <element> pour laisser un attribut choisir l'élément émis, et default pour déclarer une valeur que le composant rend toujours), consultez le guide dans Linting des composants personnalisés avec l'extension Axe Accessibility Linter pour VS Code ou le plugin JetBrains.

Étape 2 : Déclarer les wrappers qui ne rendent rien

LWC utilise <template> pour l'élément racine d'un composant et à nouveau pour les boucles et conditions :

<template>
  <ul>
    <template for:each={items} for:item="item">
      <li key={item.id}>{item.name}</li>
    </template>
  </ul>
</template>

En HTML, le contenu d'un élément <template> est inerte : le navigateur ne le rend pas et la technologie d'assistance ne peut pas l'atteindre. Axe DevTools Linter évalue le balisage qu'un utilisateur obtient réellement, donc il ne signale pas le contenu à l'intérieur d'un <template>. LWC utilise le même nom de balise pour une instruction au moment de la compilation qui ne produit aucun élément du tout, donc l'analyseur doit savoir ce que ces wrappers deviennent. Le balisage ci-dessus atteint le navigateur comme suit :

<ul>
  <li></li>
  <li></li>
</ul>

Déclarer template dans votre configuration est ce qui permet à l'analyseur de passer au-delà de ces wrappers pour atteindre le balisage à l'intérieur. Étant donné qu'un mappage doit nommer un élément, et qu'un mappage s'applique partout où la balise apparaît, l'élément que vous choisissez est important. Travailler avec deux choix avec la liste ci-dessus montre pourquoi.

Essayer un conteneur générique

Un div est la première hypothèse naturelle, car un wrapper ressemble à un conteneur générique :

global-components:
  template: div

Axe DevTools Linter évalue maintenant la liste comme si vous aviez écrit le <template> en tant que div :

<ul>
  <div>
    <li></li>
  </div>
</ul>

Et il signale une violation sur la ligne <ul> :

list: <ul> and <ol> must only directly contain <li>, <script> or <template> elements

Le rapport est correct concernant le balisage qui lui a été donné, mais ce balisage n'est pas ce que le navigateur reçoit. LWC supprime le wrapper, donc la liste rendue contient directement des éléments de liste et est parfaitement valide. La violation provient de l'élément de substitution, pas de votre modèle.

Faire correspondre la relation rendue

Maintenant, mappez template à l'élément que le navigateur trouve réellement à l'intérieur de la liste :

global-components:
  template: li

L'analyseur évalue la même liste comme suit :

<ul>
  <li>
    <li></li>
  </li>
</ul>

Aucune violation de list n'est signalée, car le <ul> contient directement un li, qui est l'un des éléments autorisés par le message de règle ci-dessus, et c'est également la relation que le navigateur obtient. Le double li n'existe que dans la vue de l'analyseur de votre fichier : il représente un wrapper qui ne rend rien, et vous ne l'écrivez jamais dans un modèle.

note

L'absence de template dans votre configuration évite également la violation, mais alors rien à l'intérieur de vos modèles n'est évalué, ce qui est le problème que l'étape 2 visait à résoudre.

Les deux choix vérifient le contenu intérieur

L'élément de substitution n'affecte que comment le wrapper lui-même apparaît à l'analyseur. Le balisage interne est évalué dans tous les cas. Ajoutez une image sans texte alternatif à la même liste :

<template>
  <ul>
    <template for:each={items} for:item="item">
      <li key={item.id}><img src={item.url}></li>
    </template>
  </ul>
</template>

Les deux template: div et template: li signalent l'absence de texte alternatif sur l'image :

image-alt: Images must have alternative text

Avec template: div vous obtenez ce résultat plus la violation list artificielle, qui est la différence pratique entre les deux. Comme le parcours des éléments de liste est l'utilisation la plus courante de <template>, le mapper à li correspond le plus souvent à la sortie rendue, et c'est le point de départ recommandé.

note

Trois règles vérifient qu'un conteneur contient le bon type d'enfant direct : list pour <ul> et <ol>, definition-list pour <dl>, et summary-name pour <details>. Lorsqu'un <template> se trouve directement à l'intérieur de l'un de ces quatre conteneurs, votre élément de substitution prend sa place, donc ces trois règles peuvent ne pas signaler ce qu'elles feraient pour l'équivalent en HTML simple. Aucune autre règle n'est affectée, et le contenu à l'intérieur du modèle est toujours entièrement vérifié.

Étape 3 : Vérifiez votre configuration

Ne supposez pas qu'un mappage se comporte comme vous l'aviez prévu. La vérification la plus fiable consiste à écrire deux fois le même balisage, une fois avec vos composants et une fois en tant que HTML brut que vous attendez qu'ils rendent, et à confirmer que les deux produisent les mêmes résultats.

Créez un petit fichier de test, scratch.html, n'importe où dans le projet que Axe DevTools Linter vérifie :

<template>
  <c-my-image src="cat.jpg"></c-my-image>
  <lightning-button></lightning-button>
</template>

Ensuite, créez son équivalent en pur HTML, scratch-expected.html, contenant le balisage que vous attendez que ces composants rendent :

<img src="cat.jpg">
<button></button>

Avec les mappings des étapes 1 et 2 en place, les deux fichiers rapportent les mêmes deux violations : image-alt pour l'image sans texte alternatif, et button-name pour le bouton sans nom accessible. Des résultats concordants signifient que les mappings décrivent correctement vos composants. Une violation dans un fichier mais pas dans l'autre pointe vers la configuration plutôt que vers votre balisage.

Cette paire montre également pourquoi la vérification vaut la peine d'être faite. Sans le mappage template de l'étape 2, scratch.html ne signale rien du tout tandis que scratch-expected.html signale les deux violations, et cette discordance est le signe que quelque chose manque dans la configuration.

Il y a trois moyens pratiques de voir les résultats :

Ajouter le nom du composant à chaque résultat rend les configurations plus grandes beaucoup plus faciles à déboguer, car cela montre quelle correspondance a produit une violation. Voir Analyse des violations de composant personnalisé.

Décider ce qu'une correspondance doit exiger

Certains composants rendent un balisage différent selon comment ils sont utilisés, et les mapper est une décision politique plutôt qu'une simple traduction. <lightning-icon> est un bon exemple : une icône sans alternative-text est décorative, tandis qu'une icône avec alternative-text transmet du sens.

Mapper <lightning-icon> sur img signifie que le linter demande à chaque icône de déclarer son texte alternatif. Une valeur explicitement vide satisfait à cette demande :

<!-- Reported: an image with no alternative text -->
<lightning-icon icon-name="utility:check"></lightning-icon>

<!-- Not reported: explicitly decorative -->
<lightning-icon icon-name="utility:check" alternative-text=""></lightning-icon>

C'est une convention utile, car cela rend visible l'intention de chaque icône dans le modèle au lieu d'être implicite par omission. Si vous préférez ne pas l'adopter, laissez <lightning-icon> en dehors de votre configuration et le linter ne l'évaluera pas.

Lorsqu'un composant rend toujours la même valeur pour un attribut, comme un role fixe, utilisez default pour enregistrer cette valeur. Un default prend effet uniquement lorsque la valeur n'est pas vide, et un default peut définir un attribut mais ne peut pas fournir de contenu <text>. Voir Attributs par défaut.

important

Mappez uniquement les attributs qui portent des informations d'accessibilité, et confirmez ce que chaque composant rend avant de le mapper. Les exemples de cet article suivent le balisage produit par les composants de base Salesforce, mais vos propres composants, ainsi que tout composant que vous encapsulez, nécessitent la même vérification.

Appliquer cela à vos propres composants

Les étapes ci-dessus se généralisent à toute bibliothèque de composants :

  1. Listez les composants qui rendent un élément interactif ou significatif, comme les boutons, les liens, les images, les contrôles de formulaire et les en-têtes. Ceux-ci vous offrent le plus de valeur pour le moins de configuration.
  2. Pour chacun, notez ce qu'il rend et quels attributs portent des informations d'accessibilité, puis mappez uniquement ces attributs.
  3. Déclarez les enveloppes qui ne rendent rien de leur propre, en choisissant un élément de remplacement qui préserve la relation que voit le navigateur.
  4. Vérifiez chaque correspondance par rapport à son équivalent HTML brut avant de vous y fier.
  5. Revisitez la configuration lorsque vos composants changent. Une correspondance ne reflète que le comportement d'un composant le jour où la correspondance a été écrite.

Si votre bibliothèque fait partie des bibliothèques que l'Axe DevTools Linter connaît déjà, vous pouvez passer la plupart de ce travail. Voir Bibliothèques de composants préconfigurées.

Voir aussi