Importazione dinamica in Svelte
Quando si codifica in Svelte, potrebbe essere necessario caricare i componenti solo su richiesta, quando sono effettivamente necessari. React ha risolto questo problema in modo abbastanza magistrale con la sua componente "Suspense". Se vuoi ottenere qualcosa di simile in Svelte, ho buone notizie per te.
Svelte "Suspense" senza suspense
Fondamentalmente ciò che è richiesto è utilizzare il meccanismo integrato di Svelte per attendere le chiamate di funzioni asincrone nel componente stesso. Il seguente semplice esempio mostra cosa intendo con questo.
<script>
// Dummy function, just so that we
// have some async stuff.
async function getData() {
await new Promise(res => setTimeout(res, 1000));
return { key: "value" };
}
</script>
{#await getData()}
<p>Fetching data...</p>
{:then res}
<p>Accessing data: "key": "{res.key}"</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
Come puoi vedere, attendiamo semplicemente il valore di ritorno della funzione e quindi lo utilizziamo nella nostra interfaccia utente. La stessa tecnica può essere utilizzata per importare interi moduli.
Importazione dinamica con Svelte
Usando l'"importazione" dinamica, disponibile in ES6, possiamo scrivere una semplice importazione di componenti pigri.
//
// Live demo:
// https://svelte.dev/repl/b7551180977d4e738b07d428f3172d5e?version=3.46.4
//
//
// App.svelte
//
<h1>App title</h1>
{#await import("./Content.svelte") then Module}
<Module.default subtitle="Subtilte as prop" />
{/await}
//
// Content.svelte
//
<script>
export let subtitle;
</script>
<article>
<h2>
Content title
</h2>
<h3>
{subtitle}
</h3>
<p>
Content body.
</p>
</article>
Basandosi su questa conoscenza, ora siamo in grado di caricare in modo pigro qualsiasi componente. Un esempio pratico che sto effettivamente utilizzando per spikze.club è l'implementazione di un singolo componente "Icona" che carica l'icona specifica su richiesta.
<!--
Source: https://carbon-icons-svelte.onrender.com/
-->
<script lang="ts">
// Using a link so that 'clsx' can eliminate
// all other variant compared to an enum, which
// should lead to a smaller size at runtime.
export let variant: "internal-link" | "external-link" | "section-link" | "close" | "add-circle";
let cn: string = undefined;
export { cn as class };
</script>
{#if variant === "external-link"}
{#await import("carbon-icons-svelte/lib/ArrowUpRight20") then Icon}
<Icon.default class={cn} />
{/await}
{/if}
{#if variant === "internal-link"}
{#await import("carbon-icons-svelte/lib/ArrowRight20") then Icon}
<Icon.default class={cn} />
{/await}
{/if}
{#if variant === "section-link"}
{#await import("carbon-icons-svelte/lib/ArrowDown20") then Icon}
<Icon.default class={cn} />
{/await}
{/if}
{#if variant === "close"}
{#await import("carbon-icons-svelte/lib/Close20") then Icon}
<Icon.default class={cn} />
{/await}
{/if}
{#if variant === "add-circle"}
{#await import("carbon-icons-svelte/lib/AddAlt20") then Icon}
<Icon.default class={cn} />
{/await}
{/if}
Incartare
Hai visto come utilizzare l'importazione dinamica da ES6 per importare semplicemente qualsiasi dato su richiesta. Poiché questo vale sia per i tuoi componenti che per le librerie di terze parti, non c'è nulla che ti impedisca di ridimensionare la tua prossima app Svelte.