Tengo alrededor de 80 íconos SVG personalizados que estoy importando a una aplicación frontal de Svelte. Basado en https://github.com/sveltejs/template , está construido con Rollup e incluye Typescript, Tailwind y todas las ventajas modernas.
El dilema es cómo agregar los íconos a la aplicación. Como SVG, los íconos son cadenas cortas de texto XML que no exceden los 2kB.
foo.svg en public/assets/icons .<Icon type="foo' /> que muestre un ícono usando <img src="foo.svg> .Este enfoque significa que los íconos no son parte del código.
Beneficios : los íconos se pueden cargar dinámicamente mediante el código de interfaz a pedido. No es necesario agrupar todos los íconos en el código de la aplicación.
Contras : carga lenta de la página si hay muchos íconos nuevos y el navegador tiene que buscar una docena de archivos de 1kB. Implementar la aplicación como PWA significa que debemos indicarle manualmente que almacene en caché los íconos de antemano.
import Home from './icons/home.svg';Aquí, los íconos se agrupan como cadenas de texto con la propia aplicación.
Beneficios : los íconos se entregan como parte del paquete de aplicaciones. El almacenamiento en caché es innecesario. Es posible modificar dinámicamente algunos de los códigos de iconos, por ejemplo, colores, viewBox, etc. en la carga.
Contras : no es necesario incluir todos los íconos en la aplicación para reducir el tiempo hasta el primer byte. No se puede dividir el paquete, etc. sin agregar más complejidad. Hace que la representación sea más lenta porque el código Javascript primero necesita convertir una cadena en un SVG en lugar de simplemente cargar una imagen.
Una solución funcional es mantener los SVG en un IconService.js separado:
export const chevron_down = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-down\"><polyline points=\"6 9 12 15 18 9\"></polyline></svg>"; export const chevron_right = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-chevron-right\"><polyline points=\"9 18 15 12 9 6\"></polyline></svg>";Esto se puede importar y usar fácilmente dentro de la función svelte @html.
<script> import {chevron_down, chevron_right} from 'IconService'; </script> {@html chevron_down}El siguiente enfoque tiene estas ventajas:
Tenga una configuración de componente Icon.svelte dedicada como esta:
<script> export let name; export let width = "1rem"; export let height = "1rem"; export let focusable = false; let icons = [ { box: 24, name: "save", svg: `<g stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><path d="M17 21v-8H7v8"/><path d="M7 3v5h8"/></g>` }, { box: 32, name: "trash", svg: `<path d="M12 12h2v12h-2z" /><path d="M18 12h2v12h-2z" /><path d="M4 6v2h2v20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8h2V6zm4 22V8h16v20z" /><path d="M12 2h8v2h-8z" />` } ]; let displayIcon = icons.find((e) => e.name === name); </script> <svg class={$$props.class} {focusable} {width} {height} viewBox="0 0 {displayIcon.box} {displayIcon.box}">{@html displayIcon.svg}</svg>Luego puedes usarlo así:
<Icon name="trash" class="this-is-optional" />Simplemente puede cambiar la extensión del archivo a .svelte e importar un SVG como un componente normal.
otra forma es usar un archivo de definición de símbolos (por ejemplo, icons.svg) en su carpeta pública. luego en tu código haz algo como esto:
Icono.esbelto
<script> export let name; export let width = "1.5rem"; export let height = "1.5rem"; export let focusable = false; </script> <svg class={$$props.class} {focusable} {width} {height}> <use href={`/icons.svg#${name}`} /> </svg>iconos.svg
<svg aria-hidden="true" style="position: absolute; width: 0; height: 0; overflow: hidden;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <symbol id="icon-warning" viewBox="0 0 20 20"> <path d="M19.511 17.98l-8.907-16.632c-0.124-0.215-0.354-0.348-0.604-0.348s-0.481 0.133-0.604 0.348l-8.906 16.632c-0.121 0.211-0.119 0.471 0.005 0.68 0.125 0.211 0.352 0.34 0.598 0.34h17.814c0.245 0 0.474-0.129 0.598-0.34 0.124-0.209 0.126-0.469 0.006-0.68zM11 17h-2v-2h2v2zM11 13.5h-2v-6.5h2v6.5z"> </path> </symbol> </defs> </svg>App.esbelta
<Icon name="icon-warning" />de esta manera, usa una llamada http para cargar el archivo svg. y luego solo use la parte que necesita en el marcado.
Usar como {@html SVG_CODE} para representar un código svg de otro componente o variable es una mala elección . Esto da riesgo de XSS y otros ataques. comprobar: https://github.com/sveltejs/svelte/issues/2545
Creo que usar un complemento como rollup-plugin-svelte-svg ( https://www.npmjs.com/package/rollup-plugin-svelte-svg ) sería una mejor opción
npm i -D rollup-plugin-svelte-svg
export default { plugins: [ svelteSVG({ // optional SVGO options // pass empty object to enable defaults svgo: {} }), ], ... } <script> import Logo from "./logo.svg"; </script> <Logo width=20 />