Динамический импорт в Svelte
При написании кода в Svelte у вас может возникнуть требование загружать компоненты только по запросу, когда они действительно необходимы. React довольно мастерски решил эту проблему со своим компонентом «Suspense». Если вы хотите добиться чего-то подобного в Svelte, у меня для вас хорошие новости.
Svelte "Саспенс" без саспенса
В основном требуется использовать встроенный механизм Svelte для ожидания вызовов асинхронных функций в самом компоненте. Следующий простой пример показывает, что я имею в виду.
<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}
Как видите, мы просто ждем возвращаемого функцией значения, а затем используем его в нашем пользовательском интерфейсе. Тот же метод можно использовать для импорта целых модулей.
Динамический импорт с помощью Svelte
Используя динамический «импорт», доступный в ES6, мы можем написать простой ленивый импорт компонента.
//
// 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>
Опираясь на эти знания, мы теперь можем лениво загружать любой компонент. Практический пример, который я фактически использую для spikze.club, — это реализация одного компонента «Иконка», который загружает конкретную иконку по запросу.
<!--
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}
Заворачивать
Вы видели, как использовать динамический импорт из ES6, чтобы просто импортировать любые данные по запросу. Поскольку это относится как к вашим компонентам, так и к сторонним библиотекам, ничто не мешает вам масштабировать ваше следующее приложение Svelte.