Più leggero e più veloce - Una guida al quadro snello

Pubblicato: 2022-03-11

Le applicazioni Web stanno diventando sempre più popolari di giorno in giorno. Sono un mondo in crescita che le persone scelgono per la sua semplicità, velocità e disponibilità multipiattaforma. Le applicazioni a pagina singola (SPA) hanno avuto un ruolo enorme in questo processo. Framework come Angular, Vue.js e React aiutano gli sviluppatori a offrire la migliore esperienza utente in un breve periodo, lasciando il codice supportabile ed estensibile. Questi strumenti sono rimasti a lungo i più popolari nel campo, con molti vantaggi rispetto ai pacchetti appena creati. È sembrato un oligopolio nel mondo delle SPA. Tuttavia, un gruppo di sviluppatori lungimiranti che si rivolgono a questo mercato potrebbe entrare con un serio concorrente: Svelte.

Svelte è un nuovo approccio alla creazione di interfacce utente. Immergiamoci ed esploriamo ciò che lo rende così fresco creando un modulo di accesso comune.

Architettura

Svelte è progettato per essere più veloce di qualsiasi altra libreria. Si raggiunge spostando la fase di caricamento di un framework per la creazione di un DOM virtuale. Invece di utilizzare uno strumento durante il processo in esecuzione, viene compilato in JS vanilla in fase di creazione, quindi l'applicazione non richiede dipendenze per l'avvio.

Svelto Altre librerie SPA (React, Vue.js, Angular, ecc.)

1. Apri un sito web
2. Eseguire il rendering della pagina utilizzando JS puro

1. Apri un sito web
2. Attendi il caricamento del codice per la creazione di un DOM virtuale
3. Eseguire il rendering della pagina utilizzando la libreria

La tabella sopra descrive perché Svelte è un vincitore assoluto nelle prestazioni di avvio. Ciò non si ottiene con alcun tipo di ottimizzazione, ma utilizzando il compilatore JavaScript del browser disponibile anziché un compilatore laterale.

Installazione

L'installazione snella è incredibilmente facile, rendendo il suo utilizzo molto piacevole. Il primo passo è scaricare il template del progetto:

 npx degit sveltejs/template svelte-login-form

Il completamento del comando precedente significa che abbiamo un modello di progetto Svelte. Per il momento è vuoto e i pacchetti NPM richiesti non sono ancora installati. Risolviamolo.

 cd svelte-login-form npm install

Ora l'applicazione è pronta per essere avviata utilizzando il seguente comando:

 npm run dev

Struttura

Qualsiasi componente Svelte può contenere le seguenti sezioni:

  • copione
  • Stile
  • Modello

Diamo un'occhiata all'esempio nel file src/App.svelte .

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

Il codice sopra contiene esattamente tre sezioni:

  1. script , che è un blocco JavaScript opzionale con le variabili e le dichiarazioni delle funzioni che dovrebbero essere utilizzate all'interno del componente.

  2. style tag, che è un altro blocco opzionale. È molto simile a un comune tag di stile HTML tranne per un'importante differenza. Le regole descritte all'interno di questo blocco hanno come ambito solo questo componente. L'applicazione di uno stile a un elemento p non influirà su tutti i paragrafi della pagina. È fantastico poiché non devi inventare i nomi delle classi e non annullerai mai accidentalmente un'altra regola.

  3. L'ultimo e unico blocco richiesto è un blocco modello, in questo caso un tag h1 . È una presentazione/vista del tuo componente. È strettamente legato allo stile e ai blocchi di script poiché determinano lo stile della vista e il modo in cui si comporterà.

Svelte è una libreria che cerca di portare la modularità nel gioco front-end. Mantiene quella modularità non solo nel separare i diversi componenti, ma anche nell'isolare la logica, la vista e il modello.

Tornando al form di login che stiamo costruendo, creiamo un nuovo file LoginForm.svelte all'interno della cartella src con il seguente contenuto:

 <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>

È un componente in stile stupido che renderemo più intelligente in seguito. Per vedere questo componente sul nostro sito dovremmo renderizzarlo all'interno del componente root - App. Andiamo a modificare src/App.svelte in modo che assomigli a questo:

 <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>

Se tutto è stato eseguito correttamente e l'applicazione è ancora in esecuzione, il nostro modulo apparirà su localhost:5000 . Aumentiamo di livello le nostre abilità Svelte rendendo il modulo più intelligente.

Andando con stato

Qualsiasi componente in Svelte può avere il suo stato. Lo stato è una variabile speciale o un gruppo di variabili speciali che possono essere utilizzate all'interno del modello. Perché dico "speciale"? Ogni volta che una tale variabile viene modificata, il modello ne viene informato e rende il contenuto con lo stato più recente. Ciò consente all'applicazione di reagire molto velocemente alle interazioni dell'utente.

Dichiareremo le variabili di stato dell'e- email e della password in cui verranno archiviati i valori del modulo per i campi appropriati. Significa che le nostre variabili email e password saranno sempre sincronizzate con i valori del modulo, quindi saremo pronti a inviare questi valori in qualsiasi momento senza timore di avere differenze tra i valori di invio e i valori effettivi nel modulo.

 <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>

Le variabili di stato sembrano variabili JavaScript comuni ma per sincronizzarle con i valori del modulo (associarle ai campi del modulo), è necessario utilizzare la direttiva bind:value . Ci sono anche un paio di cose sconosciute:

  • on:submit|preventDefault è un'abbreviazione per prevenire il comportamento degli eventi predefiniti. È più comodo in questo modo che dover scrivere e.preventDefault() ogni volta.

  • {#if isLoading}Logging in...{:else}Log in {/if} è una parte della sintassi del modello di Svelte. Poiché non esiste JS nel blocco del modello, esiste una sintassi speciale per l'utilizzo di ifs, loop, ecc.

Infine, utilizziamo le opzioni disponibili utilizzando lo stato per aggiungere la convalida al nostro modulo. Può essere ottenuto creando un'altra variabile di stato errors , che verrà riempita con errori quando il modulo viene inviato con valori non validi.

 <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> 
Errore nel modulo di accesso

Il modulo è quasi completo. L'unica cosa che rimane è un messaggio di successo dopo l'autenticazione riuscita.

Creiamo una variabile di stato per tenere traccia degli invii riusciti che è false per impostazione predefinita. Dopo aver inviato correttamente un modulo, il valore di questa variabile deve essere impostato su true .

 let isSuccess = false;

Anche la funzione che gestisce l'invio del modulo deve essere modificata per seguire la logica della commutazione isSuccess dopo un'operazione riuscita.

 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); } };

Questa modifica fa passare il modulo in stato di successo non appena l'invio è completo.

Ma se controlli il tuo server di sviluppo, non troverai alcun cambiamento nel comportamento del modulo. Abbiamo cambiato il codice ma non abbiamo ancora toccato il template. Dobbiamo aggiungere istruzioni al modello per mostrare un messaggio di successo quando un utente ha effettuato l'accesso con successo. La sintassi del modello di Svelte ci consente di implementarlo facilmente:

 <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>

Estratto con proprietà

Abbiamo risolto tutto sullo stato del componente interno. Ora è il momento di esaminare le dipendenze esterne chiamate proprietà o "props". Gli oggetti di scena sono input o argomenti passati al componente per descrivere al componente cosa dovrebbe apparire o come dovrebbe comportarsi il componente.

La dichiarazione di una proprietà è simile allo stato, fatta eccezione per la parola chiave export .

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

Riguarda le proprietà. Dichiara e passa: tutto ciò che devi sapere per usare gli oggetti di scena.

Ma come si applicano queste proprietà al componente del modulo di accesso? Gli oggetti di scena possono rendere il nostro modulo di accesso più generico estraendo la funzione di invio in una proprietà. Ti consentirà di utilizzare questo componente con qualsiasi azione di invio di cui hai bisogno (richiesta a un server di prova, richiesta a un server effettivo, ecc.). Questo prop sarà chiamato submit e sarà una funzione che restituisce una promessa risolta se l'azione di invio è riuscita e una promessa rifiutata se si verifica un errore. Dichiariamo il prop con l'esempio sopra riportato:

 export let submit;

Anche il gestore di invio all'interno del modulo di accesso deve essere modificato per utilizzare la nuova proprietà di 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; }); } };

Il componente sembra essere pronto. Tuttavia, se torni al modulo e provi a inviarlo, noterai che lo stato del pulsante non è cambiato rispetto al caricamento. Inoltre, c'è un'eccezione nella console: Uncaught TypeError: submit is not a function . Naturalmente, abbiamo dichiarato l'elica ma ci siamo dimenticati di passarla. Dichiariamo una funzione nel componente dell'app e la passiamo al modulo di accesso.

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

Ora il modulo funziona come previsto. Può sia mostrare errori che informare l'utente se l'accesso è andato a buon fine.

Modulo di accesso riuscito

Condivisione del contesto

Sembra che sia elencato tutto il necessario per creare un'applicazione. Con le proprietà e lo stato interiore, siamo pronti per partire. Questo è vero solo in parte, però. Questi due punti generali consentono di progettare SPA ad alta complessità. Tuttavia, se provi a condividere i dati tra molti componenti diversi, lo troverai molto difficile.

L'esempio più semplice è avere una variabile user accessibile a livello globale. Molti componenti dovrebbero cambiare il loro comportamento in relazione all'utente, a seconda del ruolo, dell'età, dello stato dell'utente, ecc. Tuttavia, non è DRY ripetersi passando l'utente a ciascun componente nell'app usando gli oggetti di scena.

Svelte ha una soluzione per questo: l'API di contesto.

L'API di contesto fornisce un meccanismo per consentire ai componenti di "parlare" tra loro senza passare dati e funzioni come oggetti di scena o inviare molti eventi. È una funzionalità avanzata ma utile.

Aggiungiamo il contesto utente al modulo di accesso che stiamo progettando. Crea un file userContext.js all'interno della cartella src con il seguente contenuto:

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

key è un identificatore univoco per il contesto in quanto un'applicazione può avere un numero illimitato di contesti diversi che devono rimanere accessibili. initialValue è solo un valore predefinito per il contesto prima che venga impostato.

Il passaggio successivo consiste nell'aggiungere il contesto alla nostra applicazione. Passare al file App.svelte e aggiungere 2 istruzioni di importazione:

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

Guardando il codice sopra, potresti chiederti cosa stiamo importando dal pacchetto svelte . onMount è una funzione di supporto che richiede una funzione di callback come argomento. Questa richiamata verrà eseguita durante il montaggio del componente corrente (all'inizio del caricamento del componente). setContext è una funzione setter per un contesto. Richiede la chiave del contesto e un nuovo valore come argomenti.

Usiamo la funzione onMount per impostare il valore predefinito per il contesto:

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

E modifica la funzione di submit per impostare il contesto dell'utente:

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

Questo è tutto. Un invio riuscito cambierà il contesto utente in un oggetto utente falso a cui è possibile accedere da un getter di contesto getContext :

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

Sommario

Svelte è un potente strumento capace di prestazioni elevate e con un'API flessibile. Oltre alle nozioni di base trattate in questo post, Svelte ha le seguenti caratteristiche pronte all'uso:

  • Dichiarazioni e dichiarazioni reattive
  • Attendi blocchi modello
  • Rilegatura dimensionale
  • Un negozio globale come Redux
  • Aiutanti di animazione e transizione
  • Un aiuto per il debug

Per riassumere, Svelte è una grande libreria che soddisfa tutte le esigenze per la costruzione di SPA e altro ancora. Può competere con i più grandi attori del mercato e persino vincere. Ciò che potrebbe utilizzare in questo momento, tuttavia, è il supporto nella comunità degli sviluppatori front-end.

Nota: tutto il codice in questo articolo può essere trovato nel repository GitHub teimurjan/svelte-login-form . La demo per il modulo di accesso è disponibile qui.