Svelte es un marco de interfaz de usuario relativamente nuevo desarrollado por Rich Harris , quien también es el autor del generador de Rollup. Lo más probable es que Svelte parezca completamente diferente de lo que ha tratado antes, pero tal vez esto sea incluso bueno. Las dos características más impresionantes de este marco son la velocidad y la simplicidad. En este artículo, nos centraremos en el segundo.

Como mi principal experiencia de desarrollo está relacionada con Angular, es natural que esté tratando de aprender Svelte copiando los enfoques que ya me son familiares. Y esto es exactamente de lo que se tratará este artículo: cómo hacer las mismas cosas en Svelte que en Angular.
Nota: a pesar de que en algunos casos expresaré mi preferencia, el artículo no es una comparación de marcos. Esta es una introducción rápida y fácil a Svelte para las personas que ya usan Angular como su marco principal.
Spoiler de advertencia: Svelte es divertido.
Componentes
En Svelte, cada componente está asociado con el archivo donde está escrito. Por ejemplo, el componente Button
se creará nombrando el archivo Button.svelte
. Por supuesto, generalmente hacemos lo mismo en Angular, pero con nosotros es solo una convención. (En Svelte, el nombre del componente a importar también puede no coincidir con el nombre del archivo - nota del traductor)
Los componentes esbeltos son de un solo archivo y constan de 3 secciones: script
, style
y una plantilla que no necesita estar envuelta en ninguna etiqueta especial.
Creemos un componente muy simple que muestre "Hola mundo".

Importar componentes
En general, esto es similar a importar un archivo JS, pero con un par de advertencias:
- debe especificar explícitamente la
.svelte
archivo del componente .svelte
- los componentes se importan dentro de la
<script>
<script> import Todo from './Todo.svelte'; </script> <Todo></Todo>
De los fragmentos anteriores, es obvio que el número de líneas para crear un componente en Svelte es increíblemente pequeño. Por supuesto, hay algunas implícitas y limitaciones, pero al mismo tiempo todo es lo suficientemente simple como para acostumbrarse rápidamente.
Sintaxis básica
Interpolación
Las interpolaciones en Svelte son más similares a las de React que en Vue o Angular:
<script> let someFunction = () => {...} </script> <span>{ 3 + 5 }</span> <span>{ someFunction() }</span> <span>{ someFunction() ? 0 : 1 }</span>
Estoy acostumbrado a usar llaves dobles, así que a veces estoy sellado, pero tal vez solo tengo este problema.
Atributos
Pasar atributos a los componentes también es bastante simple. Las comillas son opcionales y se pueden usar todas las expresiones Javascript:
//Svelte <script> let isFormValid = true; </script> <button disabled={!isFormValid}></button>
Eventos
La sintaxis para los controladores de eventos es: on:={}
.
<script> const onChange = (e) => console.log(e); </script> <input on:input={onChange} />
A diferencia de Angular, no necesitamos usar paréntesis después del nombre de la función para llamarlo. Si necesita pasar argumentos al controlador, simplemente use la función anónima:
<input on:input={(e) => onChange(e, 'a')} />
Mi opinión sobre la legibilidad de dicho código:
- Tenemos que imprimir menos, porque no necesitamos comillas ni corchetes; de todos modos, esto es bueno.
- Lee más fuerte. Siempre me ha gustado el enfoque angular en lugar de reaccionar, por lo que para mí y Svelte es más difícil de tomar. Pero este es solo mi hábito y mi opinión es algo parcial.
Directivas estructurales
A diferencia de las directivas estructuradas en Vue y Angular, Svelte ofrece una sintaxis especial para bucles y ramas dentro de las plantillas:
{#if todos.length === 0} {:else} {#each todos as todo} <Todo {todo} /> {/each} {/if}
Me gusta mucho No se necesitan elementos HTML adicionales, y en términos de legibilidad, esto se ve increíble. Desafortunadamente, el símbolo #
en el diseño de teclado británico de mi Macbook está en un lugar inaccesible, y esto afecta negativamente mi experiencia con estas estructuras.
Propiedades de entrada
Definir propiedades que se pueden pasar a un componente (análogo a @Input
en Angular) es tan fácil como exportar una variable desde un módulo JS utilizando la palabra clave export
. Quizás al principio puede ser confuso, pero escribamos un ejemplo y veamos lo simple que es en realidad:
<script> export let todo = { name: '', done: false }; </script> <p> { todo.name } { todo.done ? '✓' : '✕' } </p>
- Como puede ver, inicializamos la propiedad de
todo
junto con el valor: será el valor de la propiedad por defecto, en caso de que no se pase del componente principal
Ahora cree un contenedor para este componente, que le transmitirá datos:
<script> import Todo from './Todo.svelte'; const todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; </script> {#each todos as todo} <Todo todo={todo}></Todo> {/each}
Similar a los campos en un objeto JS normal, todo={todo}
se puede acortar y reescribir de la siguiente manera:
<Todo {todo}></Todo>
Al principio me pareció extraño, pero ahora creo que es brillante.
Propiedades de salida
Para implementar el comportamiento de la directiva @Output
, por ejemplo, cuando el componente padre @Output
notificaciones del hijo, utilizaremos la función createEventDispatcher
, que está disponible en Svelte.
- Importe la función
createEventDispatcher
y asigne su valor de retorno a la variable de dispatch
- La función de
dispatch
tiene dos parámetros: el nombre del evento y los datos (que se incluirán en el campo de detail
del objeto de evento) - Ponemos
dispatch
dentro de la función markDone
, que se llama mediante el evento click ( on:click
)
<script> import { createEventDispatcher } from 'svelte'; export let todo; const dispatch = createEventDispatcher(); function markDone() { dispatch('done', todo.name); } </script> <p> { todo.name } { todo.done ? '✓' : '✕' } <button on:click={markDone}></button> </p>
En el componente principal, debe crear un controlador para el evento done
para que pueda marcar los objetos necesarios en la matriz de todo
.
- Crea la función
onDone
- Asignamos esta función al controlador de eventos que se llama en el componente secundario, de la siguiente manera:
on:done={onDone}
<script> import Todo from './Todo.svelte'; let todos = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; function onDone(event) { const name = event.detail; todos = todos.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); } </script> {#each todos as todo} <Todo {todo} on:done={onDone}></Todo> {/each}
Nota: para activar la detección de un cambio en un objeto, no mutamos el objeto en sí. En su lugar, asignamos a la variable todos
una nueva matriz, donde el objeto de la tarea deseada ya se cambiará a completado.
Por lo tanto, Svelte se considera verdaderamente reactivo : con la asignación habitual de un valor a una variable, la parte correspondiente de la representación también cambiará.
ngModel
Svelte tiene una sintaxis de bind:<>={}
especial bind:<>={}
para vincular variables específicas a los atributos de un componente y sincronizarlas entre sí.
En otras palabras, le permite organizar el enlace de datos bidireccional:
<script> let name = ""; let description = ""; function submit(e) { </script> <form on:submit={submit}> <div> <input placeholder="" bind:value={name} /> </div> <div> <input placeholder="" bind:value={description} /> </div> <button> </button> </form>
Expresiones reactivas
Como vimos anteriormente, Svelte responde a la asignación de valores a las variables y vuelve a dibujar la vista. También puede usar expresiones reactivas para responder a cambios en el valor de una variable y actualizar el valor de otra.
Por ejemplo, creemos una variable que debería mostrarnos que en la matriz todos
todas las tareas se marcan como completadas:
let allDone = todos.every(({ done }) => done);
Sin embargo, la vista no se volverá a dibujar cuando se actualice la matriz, porque el valor de la variable allDone
asigna solo una vez. Utilizaremos una expresión reactiva, que al mismo tiempo nos recordará la existencia de "etiquetas" en Javascript:
$: allDone = todos.every(({ done }) => done);
Se ve muy exótico. Si le parece que hay "demasiada magia", le recuerdo que las etiquetas son Javascript válido .
Una pequeña demostración que explica lo anterior:

Inyección de contenido
Para incrustar contenido, también se utilizan ranuras que se colocan en el lugar correcto dentro del componente.
Para mostrar simplemente el contenido que se transfirió dentro del elemento componente, se utiliza un elemento de slot
especial:
// Button.svelte <script> export let type; </script> <button class.type={type}> <slot></slot> </button> // App.svelte <script> import Button from './Button.svelte'; </script> <Button> </Button>
En este caso, la línea ""
tomará el lugar del elemento <slot></slot>
.
Las ranuras con nombre deberán nombrarse:
// Modal.svelte <div class='modal'> <div class="modal-header"> <slot name="header"></slot> </div> <div class="modal-body"> <slot name="body"></slot> </div> </div> // App.svelte <script> import Modal from './Modal.svelte'; </script> <Modal> <div slot="header"> </div> <div slot="body"> </div> </Modal>
Ganchos de ciclo de vida
Svelte ofrece 4 ganchos de ciclo de vida que se importan del paquete Svelte.
- onMount: se llama cuando un componente está montado en el DOM
- beforeUpdate: llamado antes de actualizar el componente
- afterUpdate: llamado después de la actualización del componente
- onDestroy: se llama cuando un componente se elimina del DOM
La función onMount
toma como parámetro una función de devolución de llamada que se llamará cuando el componente se coloque en el DOM. En pocas palabras, es similar a la ngOnInit
.
Si la función de devolución de llamada devuelve otra función, se llamará cuando el componente se elimine del DOM.
<script> import { onMount, beforeUpdate, afterUpdate, onDestroy } from 'svelte'; onMount(() => console.log('', todo)); afterUpdate(() => console.log('', todo)); beforeUpdate(() => console.log(' ', todo)); onDestroy(() => console.log('', todo)); </script>
Es importante recordar que al invocar onMount
todas las propiedades incluidas en él ya deben estar inicializadas. Es decir, en el fragmento anterior, todo
ya debería existir.
Gestión del estado
Administrar su estado en Svelte es increíblemente simple, y tal vez esta parte del marco me simpatiza más que nadie. Puede olvidarse de la verbosidad del código cuando usa Redux. Por ejemplo, crearemos almacenamiento en nuestra aplicación para el almacenamiento y la gestión de tareas.
Bóvedas grabables
Primero debe importar el writable
almacenamiento writable
desde el paquete svelte/store
y decirle el valor inicial initialState
import { writable } from 'svelte/store'; const initialState = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; const todos = writable(initialState);
Por lo general, pongo un código similar en un archivo separado como todos.store.js
y exporto la variable de almacenamiento para que el componente donde lo importo pueda trabajar con él.
Obviamente, el objeto todos
ahora se ha convertido en un repositorio y ya no es una matriz. Para obtener el valor de almacenamiento, utilizaremos un poco de magia en Svelte:
- Al agregar el carácter
$
al nombre de la variable de almacenamiento, obtenemos acceso directo a su valor.
Por lo tanto, simplemente reemplazamos en el código todas las referencias a la variable todos
con $todos
:
{#each $todos as todo} <Todo todo={todo} on:done={onDone}></Todo> {/each}
Ajuste de estado
El nuevo valor del almacenamiento grabable puede especificarse llamando al método set
, que cambia imperativamente el estado de acuerdo con el valor pasado:
const todos = writable(initialState); function removeAll() { todos.set([]); }
Actualización de estado
Para actualizar el almacenamiento (en nuestro caso, todos
), en función de su estado actual, debe llamar al método de update
y pasarle una función de devolución de llamada que devolverá el nuevo estado para el almacenamiento.
Reescribimos la función onDone
que creamos anteriormente:
function onDone(event) { const name = event.detail; todos.update((state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); }
Aquí utilicé un reductor directamente en el componente, lo cual es una mala práctica. Lo movemos a un archivo con nuestro repositorio y exportamos una función que simplemente actualizará el estado.
Suscripción de cambio de estado
Para descubrir que el valor en el repositorio ha cambiado, puede usar el método de subscribe
. Tenga en cuenta que el repositorio no es un objeto observable
, sino que proporciona una interfaz similar.
const subscription = todos.subscribe(console.log); subscription();
Observables
Si esta parte le causó la mayor emoción, entonces me apresuro a complacer que no hace mucho tiempo, se agregó el soporte RxJS a Svelte y se introdujo el Observable para ECMAScript.
Como desarrollador angular, ya estoy acostumbrado a trabajar con programación reactiva, y la falta de una contraparte de tubería asíncrona sería extremadamente inconveniente. Pero Svelte también me sorprendió aquí.
Veamos un ejemplo de cómo funcionan juntas estas herramientas: muestre una lista de repositorios en Github, que se encuentra con la palabra clave "Svelte"
.
Puede copiar el código a continuación y ejecutarlo directamente en REPL :
<script> import rx from "https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"; const { pluck, startWith } = rx.operators; const ajax = rx.ajax.ajax; const URL = `https://api.github.com/search/repositories?q=Svelte`; const repos$ = ajax(URL).pipe( pluck("response"), pluck("items"), startWith([]) ); </script> {#each $repos$ as repo} <div> <a href="{repo.url}">{repo.name}</a> </div> {/each}
Simplemente agregue el símbolo $
al nombre de la variable observable repos$
y Svelte mostrará automáticamente su contenido.
Mi lista de regalos para Svelte
Soporte de mecanografía
Como entusiasta de Typecript, no puedo evitar desear la posibilidad de usar tipos en Svelte. Estoy tan acostumbrado que a veces me dejo llevar y organizo los tipos en mi código, que luego tengo que eliminar. Realmente espero que Svelte pronto agregue soporte para Typecript. Creo que este artículo estará en la lista de deseos de cualquiera que quiera usar Svelte con experiencia en Angular.
Acuerdos y lineamientos
Representar en la representación de cualquier variable del bloque <script>
es una característica muy poderosa del marco, pero en mi opinión, puede conducir al desorden de código. Espero que la comunidad Svelte trabaje a través de una serie de convenciones y pautas para ayudar a los desarrolladores a escribir código de componentes limpio y comprensible.
Apoyo comunitario
Svelte es un proyecto grandioso que, con un mayor esfuerzo de la comunidad para escribir paquetes de terceros, manuales, artículos de blog y más, puede despegar y convertirse en una herramienta reconocida en el increíble mundo de desarrollo Frontend que tenemos hoy.
En conclusión
A pesar de que no era fanático de la versión anterior del framework, Svelte 3 me causó una buena impresión. Es simple, pequeño, pero puede hacer mucho. Es tan diferente de todo lo que me recuerda la emoción que experimenté cuando cambié de jQuery a Angular.
Independientemente del marco que esté utilizando ahora, es probable que aprender Svelte demore solo un par de horas. Una vez que aprenda los conceptos básicos y comprenda las diferencias con lo que está acostumbrado a escribir, trabajar con Svelte será muy fácil.
En el canal de Telegram en ruso @sveltejs seguramente encontrará desarrolladores que tienen experiencia con varios marcos y están listos para compartir sus historias, pensamientos y consejos sobre Svelte.