Plus léger et plus rapide - Un guide du cadre Svelte

Publié: 2022-03-11

Les applications Web deviennent de plus en plus populaires de jour en jour. C'est un monde en pleine croissance que les gens choisissent pour sa simplicité, sa rapidité et sa disponibilité multiplateforme. Les applications à page unique (SPA) ont joué un rôle important dans ce processus. Des frameworks comme Angular, Vue.js et React aident les développeurs à offrir la meilleure expérience utilisateur en peu de temps, laissant le code supportable et extensible. Ces outils sont longtemps restés les plus populaires sur le terrain, avec de nombreux avantages par rapport aux packages nouvellement créés. Cela s'est ressenti comme un oligopole dans le monde SPA. Cependant, un groupe de développeurs tournés vers l'avenir ciblant ce marché pourrait entrer avec un concurrent sérieux, Svelte.

Svelte est une nouvelle approche de la création d'interfaces utilisateur. Plongeons-nous et explorons ce qui le rend si nouveau en créant un formulaire de connexion commun.

Architecture

Svelte est conçu pour être plus rapide que toute autre bibliothèque. Il est atteint en déplaçant l'étape de chargement d'un framework pour construire un DOM virtuel. Au lieu d'utiliser un outil pendant le processus d'exécution, il est compilé en vanille JS au stade de la construction, de sorte que l'application ne nécessite aucune dépendance pour démarrer.

Svelte Autres bibliothèques SPA (React, Vue.js, Angular, etc.)

1. Ouvrir un site Web
2. Rendez la page en utilisant du JS pur

1. Ouvrir un site Web
2. Attendez que le code de construction d'un DOM virtuel soit chargé
3. Rendre la page à l'aide de la bibliothèque

Le tableau ci-dessus décrit pourquoi Svelte est un gagnant absolu en matière de performances de démarrage. Cela n'est gagné par aucune sorte d'optimisation, mais en utilisant le compilateur JavaScript du navigateur disponible au lieu d'un compilateur secondaire.

Installation

L'installation de Svelte est incroyablement facile, ce qui rend son utilisation très agréable. La première étape consiste à télécharger le modèle du projet :

 npx degit sveltejs/template svelte-login-form

Remplir la commande ci-dessus signifie que nous avons un modèle de projet Svelte. Il est vide pour le moment et les packages NPM requis ne sont pas encore installés. Réparons ça.

 cd svelte-login-form npm install

L'application est maintenant prête à démarrer en utilisant la commande suivante :

 npm run dev

Structure

Tout composant Svelte peut contenir les sections suivantes :

  • Scénario
  • Style
  • Modèle

Regardons l'exemple dans le fichier src/App.svelte .

 <script> export let name; </script> <style> h1 { color: purple; } </style> <h1>{name}</h1>

Le code ci-dessus contient exactement trois sections :

  1. balise de script , qui est un bloc JavaScript facultatif avec les déclarations de variables et de fonctions qui doivent être utilisées à l'intérieur du composant.

  2. balise de style , qui est un autre bloc facultatif. C'est un peu comme une balise de style HTML commune, à l'exception d'une différence importante. Les règles décrites dans ce bloc ne concernent que ce composant. L'application d'un style à un élément p n'affectera pas tous les paragraphes de la page. C'est fantastique car vous n'avez pas à trouver de noms de classe et vous ne remplacerez jamais accidentellement une autre règle.

  3. Le dernier et le seul bloc requis est un bloc de modèle - dans ce cas, une balise h1 . C'est une présentation/vue de votre composant. Il est étroitement lié aux blocs de style et de script car ils déterminent le style de la vue et son comportement.

Svelte est une bibliothèque essayant d'apporter de la modularité dans le jeu frontal. Il conserve cette modularité non seulement en séparant différents composants, mais également en isolant la logique, la vue et le modèle.

Revenant au formulaire de connexion que nous construisons, créons un nouveau fichier LoginForm.svelte dans le dossier src avec le contenu suivant :

 <style> form { background: #fff; padding: 50px; width: 250px; height: 400px; display: flex; flex-direction: column; justify-content: center; align-items: center; box-shadow: 0px 20px 14px 8px rgba(0, 0, 0, 0.58); } label { margin: 10px 0; align-self: flex-start; font-weight: 500; } input { border: none; border-bottom: 1px solid #ccc; margin-bottom: 20px; transition: all 300ms ease-in-out; width: 100%; } input:focus { outline: 0; border-bottom: 1px solid #666; } button { margin-top: 20px; background: black; color: white; padding: 10px 0; width: 200px; border-radius: 25px; text-transform: uppercase; font-weight: bold; cursor: pointer; transition: all 300ms ease-in-out; } button:hover { transform: translateY(-2.5px); box-shadow: 0px 1px 10px 0px rgba(0, 0, 0, 0.58); } h1 { margin: 10px 20px 30px 20px; font-size: 40px; } </style> <form> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" /> <label>Password</label> <input name="password" type="password" placeholder="password" /> <button type="submit">Log in </button> </form>

C'est un composant de style stupide que nous rendrons plus intelligent plus tard. Pour voir ce composant sur notre site, nous devons le rendre à l'intérieur du composant racine - App. Allons éditer le src/App.svelte pour qu'il ressemble à ceci :

 <script> import LoginForm from "./LoginForm.svelte"; </script> <style> section { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; background: linear-gradient(to right, #cd76e2, #e358ab); } </style> <section> <LoginForm /> </section>

Si tout a été fait correctement et que l'application est toujours en cours d'exécution, notre formulaire apparaîtra à localhost:5000 . Améliorons nos compétences Svelte en rendant le formulaire plus intelligent.

Aller avec état

Tout composant dans Svelte peut avoir son état. L'état est une variable spéciale ou un groupe de variables spéciales qui peuvent être utilisées à l'intérieur du modèle. Pourquoi dis-je "spécial" ? Chaque fois qu'une telle variable est modifiée, le modèle en est informé et affiche le contenu avec l'état le plus récent. Cela permet à l'application de réagir très rapidement aux interactions des utilisateurs.

Nous déclarerons des variables d'état d' email et de password de passe où les valeurs de formulaire pour les champs appropriés seront stockées. Cela signifie que nos variables d'e- email et de password de passe seront toujours synchronisées avec les valeurs du formulaire, nous serons donc prêts à soumettre ces valeurs à tout moment sans craindre d'avoir des différences entre les valeurs de soumission et les valeurs réelles du formulaire.

 <script> let email = ""; let password = ""; let isLoading = false; const handleSubmit = () => { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); }; </script> <style> /* Style is unchanged */ </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> {#if isLoading}Logging in...{:else}Log in {/if} </form>

Les variables d'état ressemblent à des variables JavaScript courantes, mais pour les synchroniser avec les valeurs du formulaire (les lier aux champs du formulaire), il est nécessaire d'utiliser la directive bind:value . Il y a aussi quelques choses inconnues :

  • on:submit|preventDefault est un raccourci pour empêcher le comportement des événements par défaut. C'est plus confortable de cette façon que d'avoir à écrire e.preventDefault() à chaque fois.

  • {#if isLoading}Logging in...{:else}Log in {/if} est un élément de la syntaxe du modèle de Svelte. Comme il n'y a pas de JS dans le bloc de modèle, il existe une syntaxe spéciale pour utiliser des ifs, des boucles, etc.

Enfin, utilisons les options disponibles en utilisant l'état pour ajouter une validation à notre formulaire. Cela peut être réalisé en créant une autre variable d'état errors , qui sera remplie d'erreurs lorsque le formulaire est soumis avec des valeurs non valides.

 <script> let email = ""; let password = ""; let isLoading = false; let errors = {}; const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; // Authorize the user }, 1000); } }; </script> <style> // Previous styles unchanged .errors { list-style-type: none; padding: 10px; margin: 0; border: 2px solid #be6283; color: #be6283; background: rgba(190, 98, 131, 0.3); } </style> <form on:submit|preventDefault={handleSubmit}> <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} </form> 
Erreur de formulaire de connexion

Le formulaire est presque complet. La seule chose qui reste est un message de réussite lors de l'authentification réussie.

Créons une variable d'état pour suivre les soumissions réussies qui est false par défaut. Après la soumission réussie d'un formulaire, la valeur de cette variable doit être définie sur true .

 let isSuccess = false;

La fonction gérant la soumission du formulaire doit également être modifiée pour suivre la logique de basculement de isSuccess après une opération réussie.

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; // Simulate network request setTimeout(() => { isLoading = false; isSuccess = true; // Authorize the user }, 1000); } };

Cette modification fait passer le formulaire en état de réussite dès que la soumission est terminée.

Mais si vous vérifiez votre serveur de développement, vous ne trouverez aucun changement dans le comportement du formulaire. Nous avons changé le code mais n'avons pas encore touché au modèle. Nous devons ajouter des instructions au modèle pour afficher un message de réussite lorsqu'un utilisateur s'est connecté avec succès. La syntaxe du modèle de Svelte nous permet de l'implémenter facilement :

 <form on:submit|preventDefault={handleSubmit}> {#if isSuccess} <div class="success"> <br /> You've been successfully logged in. </div> {:else} <h1></h1> <label>Email</label> <input name="email" placeholder="[email protected]" bind:value={email} /> <label>Password</label> <input name="password" type="password" bind:value={password} /> <button type="submit"> {#if isLoading}Logging in...{:else}Log in {/if} </button> {#if Object.keys(errors).length > 0} <ul class="errors"> {#each Object.keys(errors) as field} <li>{field}: {errors[field]}</li> {/each} </ul> {/if} {/if} </form>

Résumé avec propriétés

Nous avons tout réglé sur l'état du composant interne. Il est maintenant temps de passer en revue les dépendances externes appelées propriétés ou "accessoires". Les accessoires sont des entrées ou des arguments transmis au composant pour décrire au composant ce qui doit apparaître ou comment le composant doit se comporter.

La déclaration d'une propriété ressemble à l'état, à l'exception du mot-clé export .

 <script> export let answer; </script> <p>The answer is {answer}</p>
 <script> import Nested from './Nested.svelte'; </script> <Nested answer={42}/>

Tout est question de propriétés. Déclarer et passer - tout ce que vous devez savoir pour utiliser les accessoires.

Mais comment ces propriétés s'appliquent-elles au composant de formulaire de connexion ? Les accessoires peuvent rendre notre formulaire de connexion plus générique en extrayant la fonction de soumission dans une propriété. Cela vous permettra d'utiliser ce composant avec n'importe quelle action de soumission dont vous avez besoin (demande à un serveur de test, demande à un serveur réel, etc.). Ce prop s'appellera submit et sera une fonction qui retournera une promesse résolue si l'action submit a réussi et une promesse rejetée s'il y a une erreur. Déclarons la prop par l'exemple donné ci-dessus :

 export let submit;

Le gestionnaire de soumission dans le formulaire de connexion doit également être modifié pour utiliser la nouvelle propriété submit .

 const handleSubmit = () => { errors = {}; if (email.length === 0) { errors.email = "Field should not be empty"; } if (password.length === 0) { errors.password = "Field should not be empty"; } if (Object.keys(errors).length === 0) { isLoading = true; submit({ email, password }) .then(() => { isSuccess = true; isLoading = false; }) .catch(err => { errors.server = err; isLoading = false; }); } };

Le composant semble prêt. Cependant, si vous revenez au formulaire et essayez de le soumettre, vous remarquerez que l'état du bouton n'a pas changé depuis le chargement. De plus, il existe une exception dans la console : Uncaught TypeError: submit is not a function . Bien sûr, nous avons déclaré l'accessoire mais nous avons oublié de le passer. Déclarons une fonction dans le composant app et transmettons-la au formulaire de connexion.

 const submit = ({ email, password }) => new Promise((resolve, reject) => setTimeout(resolve, 1000));
 <section> <LoginForm submit={submit} /> </section>

Maintenant, le formulaire fonctionne comme prévu. Il peut à la fois afficher des erreurs et informer l'utilisateur si la connexion a réussi.

Formulaire de connexion réussi

Partage de contexte

Il semble que tout ce qui est nécessaire pour construire une application soit listé. Avec les propriétés et l'état intérieur, nous sommes prêts à partir. Ce n'est que partiellement vrai, cependant. Ces deux généralités permettent de concevoir des SPA de grande complexité. Cependant, si vous essayez de partager des données entre de nombreux composants différents, vous trouverez cela très difficile.

L'exemple le plus simple est d'avoir une variable user accessible globalement. De nombreux composants doivent modifier leur comportement par rapport à l'utilisateur, en fonction du rôle, de l'âge, du statut, etc. de l'utilisateur. Cependant, il n'est pas DRY de nous répéter en transmettant l'utilisateur à chaque composant de l'application à l'aide d'accessoires.

Svelte a une solution pour cela : l'API de contexte.

L'API de contexte fournit un mécanisme permettant aux composants de "se parler" sans transmettre de données et de fonctions en tant qu'accessoires ni envoyer de nombreux événements. C'est une fonctionnalité avancée mais utile.

Ajoutons le contexte utilisateur au formulaire de connexion que nous concevons. Créez un fichier userContext.js dans le dossier src avec le contenu suivant :

 export const key = "userContext"; export const initialValue = null;

key est un identifiant unique pour le contexte car une application peut avoir un nombre illimité de contextes différents qui doivent rester accessibles. initialValue est juste une valeur par défaut pour le contexte avant qu'il ne soit défini.

L'étape suivante consiste à ajouter le contexte à notre application. Accédez au fichier App.svelte et ajoutez 2 instructions d'importation :

 import { onMount, setContext } from "svelte"; import { key as userContextKey, initialValue as userContextInitialValue } from "./userContext";

En regardant le code ci-dessus, vous vous demandez peut-être ce que nous importons du package svelte . onMount est une fonction d'assistance nécessitant une fonction de rappel comme argument. Ce callback sera exécuté lors du montage du composant courant (au tout début du chargement du composant). setContext est une fonction de définition pour un contexte. Il nécessite la clé du contexte et une nouvelle valeur comme arguments.

Utilisons la fonction onMount pour définir la valeur par défaut du contexte :

 onMount(() => { setContext(userContextKey, userContextInitialValue); });

Et modifiez la fonction submit pour définir le contexte utilisateur :

 const submit = ({ email, password }) => new Promise((resolve, reject) => { setTimeout(() => { setContext(userContextKey, { name: "Foo", lastName: "Bar", email: "[email protected]" }); resolve(); }, 1000); });

C'est ça. Une soumission réussie changera le contexte utilisateur en un faux objet utilisateur accessible par un getter de contexte getContext :

 <script> import { getContext } from 'svelte'; import { key as userContextKey } from "./userContext"; const user = getContext(key); </script>

Sommaire

Svelte est un outil puissant capable de hautes performances et doté d'une API flexible. Outre les bases couvertes dans cet article, Svelte a les fonctionnalités suivantes prêtes à l'emploi :

  • Déclarations et déclarations réactives
  • Attendre les blocs de modèle
  • Reliure de dimension
  • Un magasin mondial comme Redux
  • Aides à l'animation et à la transition
  • Une aide au débogage

En résumé, Svelte est une grande bibliothèque qui répond à tous les besoins pour la construction de SPA, et plus encore. Il peut rivaliser avec les plus grands acteurs du marché, et même gagner. Ce qu'il pourrait utiliser en ce moment, cependant, c'est le soutien de la communauté des développeurs frontaux.

Remarque : tout le code de cet article se trouve dans le dépôt GitHub teimurjan/svelte-login-form . La démo du formulaire de connexion est disponible ici.