Myapp prolonge ses vacances


Je suis sûr qu'il y aura ceux parmi le public respecté qui me comprendront. Le fait est que dans toute l'abondance des bibliothèques et des cadres populaires pour le frontend Web, je n'aime personnellement pas presque toutes les alternatives. Dans chacune des options, je me trouve des inconvénients importants qui m'empêchent de les utiliser calmement. Tout commence toujours de façon rose: un concept intéressant, le son, à première vue, le raisonnement en points «pour» ... Mais alors, tout, encore et encore, commence à se heurter à des dépendances redondantes, des entités superflues et tente de résoudre les problèmes créés par les développeurs eux-mêmes. On nous propose d'apprendre une nouvelle syntaxe, d'accepter de nouvelles idées, d'apprendre un tas de mots à la mode, d'installer de nombreux packages «nécessaires». Ok, j'aime tout ce qui est nouveau et j'aime les mots intelligents. Mais je suis très découragé quand ce qui peut être fait simplement, les gens commencent à se compliquer fractalement. Vous avez probablement déjà lu les confessions de ceux qui, comme moi, désespéraient de chercher le bon sens dans tout cela et ont décidé d'aller à l'autre extrême - d'écrire tout «à la vanille». Cela m'est arrivé lorsque j'ai été déçu par le projet Polymer , créé avec la participation active des développeurs de Google. Au début, j'aimais beaucoup tout, la devise de ce mouvement était la phrase «Utilisez la plateforme!», Qui signifiait pour moi: «vous ne devriez pas faire dans le code ce que le navigateur lui-même fera plus efficacement». L'équipe Polymer a fait beaucoup pour introduire de nouvelles normes et capacités au niveau de la plateforme, et merci beaucoup pour cela. Mais lorsque ces objectifs ont été atteints , ils ont eux-mêmes commencé à violer leurs propres principes. Et maintenant, leur nouvelle bibliothèque ( LitElement ) refuse déjà de travailler directement dans le navigateur sans installer un environnement spécial, car les gars ne suivent pas les normes ... Je continue de surveiller le développement de LitElement, et même de voir des signes évidents que ces personnes errantes retournent sur le vrai chemin, mais moi-même déjà Je ne vais pas l'utiliser, car maintenant j'ai quelque chose de mieux.

Quoi?


Holiday.js est une bibliothèque pour ceux qui ont besoin de tout ce dont ils ont besoin et qui n'ont besoin de rien de plus. Vacances - parce que travailler avec elle pour moi est un jour férié. Et aussi parce que je l'ai écrit, principalement en vacances ou en vacances. Néanmoins, il s'agit d'un projet très sérieux, avec l'aide duquel toute une série d'applications complexes sont en cours de développement pour l'entreprise très sanglante, que les gens aiment effrayer les débutants de la construction de vélos. J'écris également tous mes projets personnels sur Holiday.js.

Tout est basé sur un groupe d' éléments standard et de normes DOM Shadow , comme vous l'avez peut-être deviné, et si vous les connaissez déjà, il sera très facile de le comprendre.

Un peu de moi
J'ai 40 ans. Actuellement, je suis un développeur Web de premier plan et un ingénieur R&D dans une entreprise néerlandaise spécialisée dans les solutions d'intégration d'IBM. Nos clients sont de grandes entreprises: pétrole, gaz, pétroliers, chemins de fer - c’est tout. L'essence de mon travail consiste à étendre les capacités standard des systèmes d'entreprise grands et lents et à améliorer l'expérience utilisateur lorsque vous travaillez avec eux. D'un côté, j'ai des oncles liés, de l'autre - un vent frais de liberté de développement web moderne. C'est une combinaison intéressante, elle vous permet de voir beaucoup de choses sous un nouvel angle. Et j'aime ça. Plus tôt, j'ai essayé le rôle d'une startup, d'un ingénieur ux, d'un directeur artistique d'un petit studio de design, et bien d'autres, donc mon «expérience» globale est comme une courtepointe patchwork. Mais cela ne signifie pas que je sois superficiellement lié à tout, je trouve juste dans de nombreux types d'activités des principes d'ingénierie similaires qui m'intéressent avant tout.

À quoi ça sert?


Si je lis moi-même un article similaire pour ne pas perdre tout intérêt, j'aimerais voir un exemple de code composant. Le voici:

import {HdElement} from '../../holiday/core/hd-element.js'; class MyComponent extends HdElement { constructor() { super(); this.state = { imageURL: 'images/photo.jpg', firstName: 'John', secondName: 'Snow', }; } } MyComponent.template = /*html*/ ` <style> :host { display: block; padding: 10px; background - color: #fff; color: #000; } </style> <img bind="src: imageURL" /> <div bind="textContent: firstName"></div> <div bind="textContent: secondName"></div> `; MyComponent.is = 'my-component'; 

Ici, nous voyons que le composant a un certain état et un modèle avec des attributs étranges des éléments " bind ". Ces attributs sont la magie principale: ils vous permettent d'analyser le modèle et d'enregistrer une copie du résultat en mémoire pour une utilisation ultérieure (clonage) SANS traitement supplémentaire de la chaîne de modèle dans l'exécution JS, ce qui donne des performances élevées lors du rendu initial lorsque chaque composant est instancié. Contrairement à de nombreuses bibliothèques modernes dans lesquelles la partie DOM dont le composant est responsable est déterminée par la fonction de l'état, dans Holiday.js, un modèle est un produit semi-fini qui définit la structure initiale et permet de lier des données plus tard, en utilisant l'API DOM habituelle, et ça marche très vite. Nous reviendrons sur la question de la vitesse.

Je vais énumérer d'autres avantages:

  • Proximité maximale avec les API natives, minimum d'abstractions supplémentaires
  • Syntaxe de modèle natif: vous n'avez pas besoin d'apprendre de nouveaux HTML et CSS
  • Pour commencer, vous n'avez pas besoin d'installer quoi que ce soit supplémentaire, votre projet peut ne pas avoir de dossier node_modules du tout
  • Facilité: vous n'obligerez pas les utilisateurs à attendre longtemps pour les téléchargements
  • Le kit comprend la gestion globale de l'état, le routage, une bibliothèque d'interface utilisateur: vous ne vous sentirez pas dans le désert

La documentation principale du projet: https://holiday-js.web.app/

Cycle de vie


Regardons les étapes du cycle de vie des composants:

 import {HdElement} from '../../holiday/core/hd-element.js'; class LifecycleExample extends HdElement { constructor() { super(); //   : this.state = { name: '', bigName: '', }; /*   ,      DOM  "   ",       .    ,      "defineAccessor": */ this.defineAccessor('name', (name) => { // Some accessor code: this.setStateProperty('name', name); }); /*    ,      DOM               . */ } connectedCallback() { super.connectedCallback(); /*  .    DOM.               . */ } stateUpdated(path) { /*        : */ if (path === 'name') { this.setStateProperty('bigName', this.state.name.toUpperCase()); } } attributeChangedCallback(attributeName, oldValue, newValue) { /*  .      . */ super.attributeChangedCallback(attributeName, oldValue, newValue); } disconnectedCallback() { /*  .    DOM.              */ } } LifecycleExample.template = /*html*/ ` <div bind="textContent: name"></div> <div bind="textContent: bigName"></div> `; /*  HTML-,     : */ LifecycleExample.logicAttributes = [ //   ,         'name', ]; /*     CustomElements: */ LifecycleExample.is = 'lifecycle-example'; 

Patterns


Étant donné que les modèles dans Holiday.js ne sont que des littéraux de modèle standard, vous avez une totale liberté sur la façon de les placer dans le projet et de former leur contenu. Vous pouvez les placer dans des modules séparés, vous pouvez les définir avec le code du composant ou vous pouvez les générer à la volée à partir des données. Vous pouvez utiliser des expressions et des résultats de fonction dans des modèles. Tout cela donne de grandes opportunités et une liberté d'expression. Par exemple, vous pouvez importer des styles communs dans un modèle, utiliser des variables et calculer des valeurs en CSS sans utiliser de préprocesseurs et avec une grande commodité, assembler des modèles à partir de pièces prêtes à l'emploi.

Les emplacements sont une partie importante des modèles de composants Web. Les emplacements vous permettent de désigner des emplacements spéciaux dans le DOM "fantôme" de votre composant, dans lesquels ses descendants directs seront affichés dans l'arborescence DOM générale. Un exemple:

 <header> <slot name="header"></slot> </header> <div class="toolbar"> <slot name="toolbar"></slot> </div> <div class="content"> <slot></slot> </div> <footer> <slot name="footer"></slot> </footer> 

Placement dans les créneaux horaires:

 <my-component> <div slot="header">Header content</div> <toolbar-component slot="toolbar"></toolbar-component> <div>Content of the default slot...</div> <div slot="footer">Footer content...</div> </my-component> 

Comme vous l'avez peut-être deviné, cela vous permet de créer des dispositions de composants, où les modules souhaités peuvent être facilement triés en cellules.

Comme mentionné ci-dessus, pour lier dynamiquement des données et des gestionnaires, l'attribut «bind» est utilisé:

 <div bind="textContent: content; onclick: on.clicked"></div> 

Pour lier des valeurs d'attribut, utilisez le symbole "@" au début du nom de la propriété:

 <div bind="@style: style">Content...</div> 

Vous pouvez trouver plus de détails dans la section correspondante de la documentation: https://holiday-js.web.app/?templates

Gestion de l'État


A l'intérieur du composant:

 class MyComponent extends HdElement { constructor() { super(); //        : this.state = { content: 'Initial Content', style: 'color: #f00', on: { clicked: () => { console.log('Clicked!'); }, }, }; //       "setStateProperty": window.setTimeout(() => { //   : this.setStateProperty('content', 'Updated Content'); //   : this.setStateProperty({ 'content': 'Updated Content', 'style': 'color: #00f', }); }, 1000); } } 

Pour contrôler l'état au niveau de l'application entière, le module HdState est utilisé.
Exemple d'utilisation:

 import {HdState} from '../../holiday/core/hd-state.js'; //   : HdState.subscribe('ui.loading', (val) => { console.log(val); }); //   : HdState.publish('ui.loading', true); // : HdState.publish({ 'ui.loading': true, 'ui.sidePanelActive': true, }); 

Pour travailler avec l'état global, vous devez d'abord déterminer son schéma général:

 HdState.applyScheme({ ui: { loading: { /*      ,       : */ type: Boolean, //    : value: false, }, sidePanelActive: { type: Boolean, value: false, }, }, user: { authorized: { type: Boolean, value: false, }, name: { type: String, value: null, //          : cache: true, }, }, }); 

Le circuit peut également être commodément divisé en blocs logiques séparés.

Pour éviter les fuites de mémoire, les abonnements non pertinents doivent être supprimés:

 let subscription = HdState.subscribe('ui.loading', (val) => { console.log(val); }); window.setTimeout(() => { // Unsubscribe: subscription.remove(); }, 10000); 

Documentation d'État: https://holiday-js.web.app/?state

Outils de développement


Le plus petit ensemble pour commencer est un éditeur de texte et un navigateur. Oui, c'est suffisant pour essayer. Il convient de noter que dans cette configuration, le navigateur doit être exactement Firefox. Il peut charger des modules ES sans utiliser de serveur local.

Pour un travail plus complet, vous aurez besoin de git et de tout serveur Web que vous avez aimé (pour travailler avec des modules ES dans d'autres navigateurs).

Pour mettre en évidence la syntaxe HTML et l'auto-complétion dans les littéraux de modèle, j'utilise l'extension pour VS Code, initialement conçue pour fonctionner avec lit-html: https://github.com/pushqrdx/vscode-inline-html

Pour créer le code avant la publication, vous pouvez utiliser n'importe quel compilateur populaire, tel que webpack ou rollup .

Performances


Les repères pour les frameworks ne sont pas faciles à écrire. Pour une comparaison représentative, vous devez vous assurer que vous comparez des choses comparables et, dans la mesure du possible, en minimisant les effets des effets secondaires. Ainsi, ils devraient avoir une idée claire de ce qui se passe «sous le capot» dans chaque cas. Tout d'abord, vous devez décider des paramètres que nous mesurerons. Pour notre cas, il est important pour nous:

  1. Temps de démarrage de l'exécution du programme principal (téléchargement)
  2. Temps de rendu initial du composant
  3. Il est temps de mettre à jour ces composants et de les redessiner

Malheureusement, nous n'avons pas de moyen fiable de savoir à quel moment le navigateur a exécuté le programme et terminé le rendu. Au niveau du navigateur, il y a beaucoup de nos propres optimisations, qui pour nous sont quelque chose comme une «boîte noire» et peuvent différer selon les moteurs. Ce que nous pouvons utiliser: API de performance , requestAnimationFrame et méthode requestIdleCallback non standard, qui ne fonctionne que dans Chrome et Firefox. Assez pour la première fois.

À quoi comparerons-nous Holiday.js? J'ai commencé avec deux bibliothèques: React (où sans elle) et LitElement (technologies similaires au cœur). Vous pouvez trouver du code de référence dans ces référentiels:

https://github.com/foxeyes/holiday-benchmark
https://github.com/foxeyes/lit-benchmark
https://github.com/foxeyes/react-benchmark

Malheureusement, je n'ai pas encore fini de tester l'automatisation, et ce n'est pas facile non plus, car l'automatisation ne devrait pas créer par elle-même des effets secondaires. Pour le moment, je continue de travailler sur ce problème et je prépare un outil approprié en utilisant Puppeteer (une chose très utile, je recommande). En attendant, vous pouvez essayer les tests en mode manuel (Chrome / Firefox) et vérifier les résultats dans la console du navigateur. Vous verrez que Holiday.js est un leader confiant dans tous les cas .

Vous pouvez remarquer que dans le cas de React, un conteneur div supplémentaire est créé lorsque les composants sont affichés, ce qui permet de niveler le nombre d'éléments DOM créés. J'ai décidé que ce serait vrai, car un composant Web est toujours un élément DOM et un conteneur, et la correspondance des structures arborescentes DOM dans différents tests est très importante. De plus, il est possible de supprimer l'imbrication inutile dans Holiday.js et d'afficher les données de la même manière que dans React. Cependant, si ce problème vous semble controversé, faites tout d'abord attention à la rapidité des mises à jour.

Prise en charge du navigateur


Non, Internet Explorer n'est pas pris en charge. Cela aurait pu être réalisé avec certains efforts (pour la 11e version), mais le rejet du soutien est une position de principe. Premièrement, je pense qu'IE devrait mourir longtemps et en notre pouvoir d'y contribuer. Deuxièmement, les personnes qui préconisent la prise en charge d'IE font souvent une grave erreur logique: la part d'IE dans le trafic total, selon les données actuelles, est d'environ 1,6% pour toutes les versions trouvées. Et le navigateur le plus populaire, qui devance largement les autres, est Chrome pour mobile (~ 35%). Ainsi, en prenant en charge IE, vous refusez consciemment d'utiliser un grand nombre de technologies qui sont simplement nécessaires pour implémenter une adaptabilité et une mobilité complètes dans vos applications, c'est-à-dire, pour le bien d'une petite minorité, compliquer la vie d'une grande majorité de ses utilisateurs. Ou augmentez considérablement le coût de développement et de maintenance de vos produits. Troisièmement, Microsoft a, ces derniers temps, forcé activement les utilisateurs à abandonner Windows 7, de sorte que la proportion du trafic IE dans un avenir proche diminuera de plus en plus rapidement. J'admets qu'il y a des cas où le support d'IE ne peut pas être contourné, mais de tels cas sont beaucoup plus rares que nous ne le pensions.

Le 15 janvier de cette année, Microsoft a publié une version finale du nouveau Edge , sur le moteur Chromium. À partir de ce moment, nous pouvons supposer que Holiday.js est nativement pris en charge dans toutes les versions actuelles des navigateurs populaires. Pour les anciens Edge, un polyfill est requis. La possibilité de travailler avec des polyfills est implémentée dans Holiday.js, mais le script lui-même doit être connecté séparément.

Minimalisme


Le concept de Holiday.js est basé sur la simplicité et le minimalisme. L'une des étapes importantes dans le travail sur ce projet a été pour moi la suppression de la fonctionnalité , que j'ai hâte de mettre en œuvre, mais j'ai réalisé plus tard que je pouvais m'en passer. Par conséquent, s'il vous semble que quelque chose manque vraiment, posez-vous une question, est-ce vraiment le cas? J'ai répondu par moi-même comme ceci: si quelque chose d'autre est vraiment nécessaire, il vaut mieux créer une classe étendue séparément, avec héritage de la principale. Jusqu'à présent, cette approche ne m'a pas échoué. Holiday.js, dans son état actuel, a été testé au combat et s'est révélé très positif au travail.

Plans


Si vous lisez à cet endroit, alors mes efforts ont déjà été dépensés en vain. Même si vous ne souhaitez pas utiliser Holiday.js, vous pouvez au moins obtenir quelque chose d'intéressant en travaillant avec des composants Web en tant que tels. Je serai très heureux si ce matériel marque le début de la construction communautaire. Je serai très heureux d'avoir une discussion constructive, des critiques, des rapports de bugs, des pullrequests et, bien sûr, des étoiles sur GitHub. Bien sûr, je ne pourrais pas aborder tous les aspects, et je serai heureux de répondre à vos questions. Veuillez prendre en compte que jusqu'à présent, j'ai travaillé seul sur cette bibliothèque, et faire tout seul, y compris la documentation, les tests et les outils associés, en parallèle avec les principaux travaux et projets pour animaux de compagnie, est difficile.

Cependant, dans un avenir proche:

  • Plus de comparaisons avec d'autres bibliothèques et frameworks populaires.
  • Outil de test PingPong minimaliste et flexible basé sur Puppeteer
  • Générateur de projet de base avec des exemples (Starter Kit)
  • Développement de la documentation

Je croise les doigts, appuie sur "Publier" ...

Source: https://habr.com/ru/post/fr485688/


All Articles