Maison > interface Web > js tutoriel > Mises en garde auxquelles vous pourriez être confronté lorsque vous travaillez avec des composants Web

Mises en garde auxquelles vous pourriez être confronté lorsque vous travaillez avec des composants Web

Susan Sarandon
Libérer: 2024-12-09 03:19:11
original
764 Les gens l'ont consulté

Caveats You May Face While Working With Web Components

Les composants Web existent depuis un certain temps, promettant une manière standardisée de créer des éléments personnalisés réutilisables. Il est clair que même si les composants Web ont fait des progrès significatifs, les développeurs peuvent encore être confrontés à plusieurs mises en garde lorsqu'ils travaillent avec eux. Ce blog explorera 10 de ces mises en garde.

1. Problèmes spécifiques au cadre

Si vous décidez d'utiliser ou non des composants Web dans votre projet. Il est important de déterminer si les composants Web sont entièrement pris en charge dans le framework de votre choix, sinon vous risquez de rencontrer des mises en garde désagréables.

Angulaire

Par exemple, pour utiliser des composants Web dans Angular, il est nécessaire d'ajouter CUSTOM_ELEMENTS_SCHEMA à l'importation du module.

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le problème avec l'utilisation de CUSTOM_ELEMENTS_SCHEMA est qu'Angular désactivera la vérification de type et Intellisense pour les éléments personnalisés dans les modèles. (voir numéro)

Pour contourner ce problème, vous pouvez créer un composant wrapper angulaire.

Voici un exemple de ce à quoi cela ressemblerait.

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cela fonctionne mais ce n'est pas une bonne idée de les créer manuellement. Étant donné que cela crée beaucoup de maintenance et que nous pouvons rencontrer des problèmes de désynchronisation avec l'API. Pour rendre cela moins fastidieux. Lit (voir ici) et Stencil (voir ici) fournissent tous deux un cli pour les créer automatiquement. Cependant, la nécessité de créer ces composants wrapper en premier lieu entraîne une surcharge supplémentaire. Si le framework de votre choix prend correctement en charge les composants Web, vous ne devriez pas avoir à créer de composants wrapper.

Réagir

Un autre exemple est celui de React. Maintenant, React v19 vient de sortir et résout ces problèmes. Cependant, si vous utilisez toujours la version 18, notez simplement que la version 18 ne prend pas entièrement en charge les composants Web. Voici donc quelques problèmes que vous pourriez rencontrer lorsque vous travaillez avec des composants Web dans React v18. Ceci est tiré directement des documents Lit.

"React suppose que toutes les propriétés JSX correspondent aux attributs des éléments HTML et ne fournit aucun moyen de définir les propriétés. Cela rend difficile la transmission de données complexes (comme des objets, des tableaux ou des fonctions) aux composants Web."

"React suppose également que tous les événements DOM ont des "propriétés d'événement" correspondantes (onclick, onmousemove, etc.), et les utilise au lieu d'appeler addEventListener(). Cela signifie que pour utiliser correctement des composants Web plus complexes, vous devez souvent utiliser ref() et code impératif."

Pour React v18, Lit recommande d'utiliser leurs composants wrapper car ils résolvent les problèmes de définition des propriétés et d'écoute des événements pour vous.

Voici un exemple de composant wrapper React utilisant Lit.

import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Utilisation

<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Heureusement avec React v19, vous ne devriez plus avoir besoin de créer des composants wrapper. Ouais !

L'utilisation de composants Web dans les micro-frontends a révélé un défi intéressant :

2. Problèmes liés au registre mondial

Un problème important est la nature globale du registre des éléments personnalisés :

Si vous utilisez une micro-interface et prévoyez d'utiliser des composants Web pour réutiliser des éléments d'interface utilisateur dans chaque application, vous rencontrerez probablement cette erreur.

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Cette erreur se produit lorsque vous essayez d'enregistrer un élément personnalisé avec un nom déjà utilisé. Ceci est courant dans les micro-frontends car chaque application d'un micro-frontend partage le même fichier index.html et chaque application essaie de définir les éléments personnalisés.

Il existe une proposition pour résoudre ce problème appelée Registres d'éléments personnalisés à portée, mais il n'y a pas d'ETA, vous devrez donc malheureusement utiliser un polyfill.

Si vous n'utilisez pas le polyfill, une solution de contournement consiste à enregistrer manuellement les éléments personnalisés avec un préfixe pour éviter les conflits de noms.

Pour ce faire dans Lit, vous pouvez éviter d'utiliser le décorateur @customElement qui enregistre automatiquement l'élément personnalisé. Ajoutez ensuite une propriété statique pour le tagName.

Avant

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Après

import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ensuite, dans chaque application, vous définissez l'élément personnalisé avec un préfixe du nom de l'application.

<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Ensuite, pour utiliser l'élément personnalisé, vous l'utiliserez avec le nouveau préfixe.

Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry':
the name "foo-bar" has already been used with this registry
Copier après la connexion
Copier après la connexion

Cela fonctionne comme une solution rapide à court terme, mais vous remarquerez peut-être que ce n'est pas la meilleure expérience de développeur, il est donc recommandé d'utiliser le polyfill Scoped Custom Element Registry.

3. Styles hérités

Le Shadow DOM, tout en assurant l'encapsulation, comporte son propre ensemble de défis :

Shadow dom fonctionne en fournissant une encapsulation. Cela empêche les styles de s'échapper du composant. Cela empêche également les styles globaux de cibler les éléments dans le shadow dom du composant. Cependant, les styles extérieurs au composant peuvent toujours s'infiltrer si ces styles sont hérités.

Voici un exemple.

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  render() {
    return html`<p>Hello world!</p>`;
  }
}
Copier après la connexion
Copier après la connexion
export class SimpleGreeting extends LitElement {
  static tagName = 'simple-greeting';

  render() {
    return html`<p>Hello world!</p>`;
  }
}
Copier après la connexion
Copier après la connexion

Lorsque nous cliquons sur le le bouton émet un événement composé qui bouillonne.

composant-a

[SimpleGreeting].forEach((component) => {
  const newTag = `app1-${component.tagName}`;
  if (!customElements.get(newTag)) {
    customElements.define(newTag, SimpleGreeting);
  }
});
Copier après la connexion
Copier après la connexion

Puisque l'événement provient du composant-b, vous pourriez penser que la cible serait le composant-b ou le bouton. Cependant, l'événement est reciblé de sorte que la cible devient le composant-a.

Donc, si vous avez besoin de savoir si un événement provient du ou vous devrez vérifier le chemin composé de l'événement.

6. Rechargements pleine page

Si les liens sont utilisés dans le shadow dom car dans cet exemple, cela déclenchera un rechargement complet de la page dans votre application.

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class MyModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

C'est parce que le routage est géré par le navigateur et non par votre framework. Les frameworks doivent intervenir sur ces événements et gérer le routage au niveau du framework. Cependant, comme les événements sont reciblés dans le domaine fantôme, cela rend la tâche plus difficile pour les frameworks car ils n'ont pas un accès facile à l'élément d'ancrage.

Pour contourner ce problème, nous pouvons configurer un gestionnaire d'événements sur le cela arrêtera la propagation sur l'événement et émettra un nouvel événement. Le nouvel événement devra bouillonner et être composé. Aussi dans les détails, nous avons besoin d'un accès
au
instance que nous pouvons obtenir à partir du e.currentTarget.

@Component({
  selector: 'some-web-component-wrapper',
  template: '<some-web-component [someProperty]="someClassProperty"></some-web-component>
})
export class SomeWebComponentWrapper {
  @Input() someClassProperty: string;
}

@NgModule({
    declarations: [SomeWebComponentWrapper],
    exports: [SomeWebComponentWrapper],
    schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class WrapperModule {}
Copier après la connexion
Copier après la connexion
Copier après la connexion

Du côté consommateur, vous pouvez configurer un écouteur d'événement global pour écouter cet événement et gérer le routage en appelant des fonctions de routage spécifiques au framework.

7. Doms d'ombre imbriqués

Lors de la création de composants Web. Vous pouvez soit prendre la décision d’insérer d’autres composants Web, soit les imbriquer dans un autre. Voici un exemple.

icône fendue

import React from 'react';
import { createComponent } from '@lit/react';
import { MyElement } from './my-element.js';

export const MyElementComponent = createComponent({
  tagName: 'my-element',
  elementClass: MyElement,
  react: React,
  events: {
    onactivate: 'activate',
    onchange: 'change',
  },
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

icône imbriquée

<MyElementComponent
  active={isActive}
  onactivate={(e) => setIsActive(e.active)}
  onchange={handleChange}
/>
Copier après la connexion
Copier après la connexion
Copier après la connexion

Si vous décidez d'imbriquer le composant, cela peut rendre plus difficile l'interrogation des composants imbriqués. Surtout si vous avez une équipe d'assurance qualité qui doit créer des tests de bout en bout, car elle devra cibler des éléments spécifiques sur la page.
Par exemple, pour accéder à une icône, nous devons d'abord accéder à une bannière en saisissant sa racine fantôme, puis créer une nouvelle requête à l'intérieur de cette racine fantôme.

Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry':
the name "foo-bar" has already been used with this registry
Copier après la connexion
Copier après la connexion

Cela peut paraître simple, mais cela devient de plus en plus difficile à mesure que vos composants sont profondément imbriqués. De plus, si vos composants sont imbriqués, cela peut rendre plus difficile le travail avec les info-bulles. Surtout si vous devez cibler un élément profondément imbriqué afin de pouvoir afficher l'info-bulle en dessous.

Ce que j'ai découvert, c'est que l'utilisation d'emplacements rend nos composants plus petits et plus flexibles, ce qui est également plus maintenable. Alors préférez les slots, évitez d'imbriquer les shadow doms.

8. Limité :: Sélecteur à fente

Les emplacements permettent de composer des éléments d'interface utilisateur, mais ils présentent des limites dans les composants Web.

Le sélecteur ::slotted s'applique uniquement aux enfants directs d'un slot, limitant son utilité dans des scénarios plus complexes.

Voici un exemple.

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  render() {
    return html`<p>Hello world!</p>`;
  }
}
Copier après la connexion
Copier après la connexion
export class SimpleGreeting extends LitElement {
  static tagName = 'simple-greeting';

  render() {
    return html`<p>Hello world!</p>`;
  }
}
Copier après la connexion
Copier après la connexion
[SimpleGreeting].forEach((component) => {
  const newTag = `app1-${component.tagName}`;
  if (!customElements.get(newTag)) {
    customElements.define(newTag, SimpleGreeting);
  }
});
Copier après la connexion
Copier après la connexion

10. Adoption plus lente des fonctionnalités

Les composants Web sont souvent à la traîne des frameworks populaires comme Vue, React, Svelte et Solid dans l'adoption de nouvelles fonctionnalités et des meilleures pratiques.
Cela peut être dû au fait que les composants Web reposent sur des implémentations et des normes de navigateur, dont l'évolution peut prendre plus de temps que les cycles de développement rapides des frameworks JavaScript modernes.
En conséquence, les développeurs pourraient se retrouver à attendre certaines fonctionnalités ou à devoir mettre en œuvre des solutions de contournement facilement disponibles dans d'autres frameworks.

Quelques exemples de ceci est Lit utilisant CSS dans JS comme option par défaut pour le style. On sait depuis longtemps que CSS dans les frameworks JS avait des problèmes de performances
car ils introduisaient souvent une surcharge d’exécution supplémentaire. Nous avons donc commencé à voir des CSS plus récents dans les frameworks JS qui sont passés à des solutions basées sur un temps d'exécution nul.
La solution CSS dans JS de Lit est toujours basée sur le runtime.

Un autre exemple est celui des signaux. Actuellement, le comportement par défaut dans Lit est que nous ajoutons de la réactivité aux propriétés de classe en ajoutant le décorateur @property.
Cependant, lorsque la propriété est modifiée, le rendu de l'ensemble du composant est déclenché. Avec les signaux, seule une partie du composant qui repose sur le signal sera mise à jour.
Ceci est plus efficace pour travailler avec les interfaces utilisateur. Si efficace qu'il y a une nouvelle proposition (TC39) pour l'ajouter à JavaScript.
Désormais, Lit fournit un package pour utiliser Signals mais ce n'est pas la réactivité par défaut alors que d'autres frameworks comme Vue et Solid le font déjà depuis des années.
Nous ne verrons probablement pas les signaux comme la réactivité par défaut avant quelques années jusqu'à ce que les signaux fassent partie des standards du Web.

Encore un autre exemple qui se rapporte à ma mise en garde précédente "9. Les éléments slottés sont toujours dans le dom". Rich Harris le créateur de Svelte en a parlé
dans son article de blog il y a 5 ans intitulé "Pourquoi je n'utilise pas de composants Web".
Il explique comment ils ont adopté l'approche des normes Web pour le rendu rapide du contenu à emplacements dans Svelte v2. Cependant, ils ont dû s'en éloigner
dans Svelte 3 parce que c'était un gros point de frustration pour les développeurs. Ils ont remarqué que la plupart du temps, vous souhaitez que le contenu slotté s'affiche paresseusement.

Je peux trouver plus d'exemples, par exemple dans les composants Web, il n'y a pas de moyen simple de transmettre des données aux emplacements alors que d'autres frameworks comme Vuejs le prennent déjà en charge. Mais le principal point à retenir ici est que
Les composants Web puisqu'ils s'appuient sur les standards du Web adoptent des fonctionnalités beaucoup plus lentes que les frameworks qui ne s'appuient pas sur les standards du Web.
En ne nous appuyant pas sur les standards du Web, nous pouvons innover et proposer de meilleures solutions.

Conclusion

Les composants Web offrent un moyen puissant de créer des éléments personnalisés réutilisables et encapsulés. Cependant, comme nous l'avons exploré, les développeurs peuvent être confrontés à plusieurs mises en garde et défis lorsqu'ils travaillent avec eux. Tels que l'incompatibilité du framework, l'utilisation dans les micro-frontends, les limitations du Shadow DOM, les problèmes de reciblage d'événements, les emplacements et l'adoption lente des fonctionnalités sont autant de domaines qui nécessitent un examen attentif.

Malgré ces défis, les avantages des composants Web, tels qu'une véritable encapsulation, la portabilité et l'indépendance du framework, en font un outil précieux dans le développement Web moderne. À mesure que l'écosystème continue d'évoluer, nous pouvons nous attendre à voir des améliorations et de nouvelles solutions qui répondent à ces mises en garde.

Pour les développeurs qui envisagent les composants Web, il est essentiel de peser le pour et le contre et de rester informé des dernières avancées dans le domaine. Avec la bonne approche et la bonne compréhension, les composants Web peuvent être un ajout puissant à votre boîte à outils de développement.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal