Как настроить использование svg файла в sveltekit?

Чтобы импортировать и использовать файл svg в sveltekit, я обращаюсь к этой статье https://riez.medium.com/svelte-kit-importing-svg-as-svelte-component-781903fef4ae Кстати, когда я наконец ввожу код

      <svelte:component this={Logo} />

Я получил ошибку, как показано ниже

      <svelte:component this={...}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules

Желаю, чтобы кто-нибудь помог мне с этой проблемой.

4 ответа

Проблема

Я знаю, что это старый вопрос, но, к сожалению, я тоже сталкиваюсь с той же ошибкой, и ответ здесь не очень помогает.

  1. используя<img>отлично, если стили svg являются автономными, но как только вам нужно будет изменить их размер или цвет относительно родительского элемента (например, перестанет работать)
  2. Создание нового файла Svelte может быть отличным решением, но я предпочитаю, чтобы мои ресурсы находились в одной папке, как обычно.
    почему?
    • для читабельности: // для ресурсов. и реальные компоненты с
    • цели производительности: /questions/62736767/kuda-pomestit-izobrazheniya-s-pomoschyu-svelte-kit/62954162#62954162
    • отнимает много времени : для добавления каждого актива: вам нужно вручную создать новый файл.svelteи вставьте код. это легко сделать для 2/3 значков, но что произойдет, если у вас будет 50/80+ значков? отнимает много времени.
  3. использовать для этого внешнюю библиотеку не обязательно,
    потому что мы можем реализовать это самостоятельно, используя меньше кода и собственный код vite/svelte.

    Итак, давайте сделаем это ниже

Решение

Как я уже сказал, ребята не устанавливают эту библиотеку, потому что sveltekit+ viteобрабатывает это изначально легко (если вам это не нужно)

  1. Сейчас вlib/создайте папку под названиемassets/куда вы будете вставлять все свои.svg/.png/.jpg(не внутриstatic/из соображений производительности, потому что если внутриlibVite Bundler будет обрабатывать кеширование)

  2. допустим, мы хотим импортировать myIcon.svg:

      <script>
  import myIcon from "$lib/assets/myIcon.svg?raw"
</script>

{@html myIcon}

?rawвозвращает нам текст внутри файла (см. https://vitejs.dev/guide/features.html#static-assets)
вместо URL-ссылки, как это происходило раньше (для возврата ресурсов по умолчанию укажите?urlприглашать)

Как видите, используйте две строки собственного svelte-кода, чтобы все работало нормально.

это работает также, когда вы вкладываете свой SVG в другой и используетеcurrentColor

в большинстве случаев этот @html великолепен.
Но если ваши изображения поступают из ввода, не используйте @html, иначе вас могут взломать
(или используйте его, но с очищенными входными значениями)


РЕДАКТИРОВАТЬ:

  • если вы хотите сделать это как библиотеку компонентов, используйте этот код для своего компонента:
      <script>
  export let src;

  $: isSvg = !!src.endsWith(".svg");                             // we use $: because you may dynamically change the src so the component needs to be reactive. if you are sure that it won't be changed it will be great to use instead `const`
  $: svgRoute = isSvg ? src.replace(".svg", ".svg?raw") : null;  // you can also do `${src}?raw`
</script>

{#if isSvg}
  {#await import(svgRoute)}
    <div>loading...</div>       <!-- default fallback, can be a loading spinner or anything else that the user will see while waiting for the loading -->
  {:then value}
    {@html value.default}       <!-- the svg code will be inject here -->
  {/await}
{:else}
  <img src={Gsrc} />            <!-- if the src is only a normal photo then use native html `<img>`'s src attribute -->
{/if}
  • если вы хотите еще больше упростить этоimport myIcon from "$lib/assets/myIcon.svg?raw"вы можете использовать другой мой ответ по этой теме

Как я могу упростить импорт при использовании SvelteKit с упаковщиком Vite, например $lib/?

поэтому, используя этот компонент, это будет так:

      <script>
  import Icon from "$lib/Icon.svelte"
</script>

<Icon src="$assets/foo.svg" />
<Icon src="$assets/bar.svg" />
<Icon src="$assets/hello.png" />

<div class="text-blue-500">
  <Icon src="$assets/nested.svg" />
</div>

РЕДАКТИРОВАТЬ: ⚠️ исправление последней ошибки vitjs.

в последнее время вышеуказанное решение больше не будет работать при использованииnpm run buildвыдав эту ошибку:

Ошибка типа: не удалось получить динамически импортированный модуль.

https://github.com/vitejs/vite/issues/11804

поэтому используйте это вместо SVG-части

      <script lang="ts">
  export let src: string;

  $: isSvg = !!src.endsWith(".svg");         
  $: svgRoute = `${src}?raw`;

  function fetchSvg(svgRoute: string) {
    return new Promise((resolve) => {
      fetch(svgRoute)
      .then(response => response.text())
      .then(svg => resolve(svg))
    })
  }
</script>

{#if isSvg}
   {#await fetchSvg(svgRoute)}
     <div>loading...</div>
   {:then value}
     {@html value}
   {/await}
{:else}
  <img src={Gsrc} />
{/if}

Существует плагин SvelteKit для встраивания SVG:s. Вы можете использовать плагин тремя разными способами:

  1. Как изящный компонент
  2. Как URL (например, для использования в теге img)
  3. В виде необработанного текста (например, для использования в {@html rawText})

https://www.npmjs.com/package/@poppanator/sveltekit-svg

В svelte-kit Исправить можно, попробовав

<img src={YourSVGComponent} />

У меня это сработало.

Просматривая статью, кажется, что она решает проблему, которой не существует, гораздо более сложным, чем необходимо.

В Svelte можно сделать .svelte компонент, который содержит только разметку SVG (встроенный), затем используйте svelte:component теги, как и с любым другим контентом.

Parent.svelte

      <script>
  import Circle from './Circle.svelte'
</script>

<svelte:component this={Circle} />

Circle.svelte

      <svg viewbox="0 0 200 200">
  <circle cx="100" cy="100" r="20"/>
</svg>

Вот REPL, показывающий, как переключаться между компонентами, в которых есть только SVG.

Вы даже можете добавить что-то к компонентам SVG, чтобы сделать их динамическими, поскольку это просто разметка, как показано в этом REPL .

Другие вопросы по тегам