Svelte é uma estrutura de interface do usuário relativamente nova, desenvolvida por Rich Harris , que também é o autor do construtor Rollup. Provavelmente, o Svelte parecerá completamente diferente do que você já lidou antes, mas talvez isso seja bom. Os dois recursos mais impressionantes dessa estrutura são velocidade e simplicidade. Neste artigo, focaremos o segundo.

Como minha principal experiência de desenvolvimento está relacionada ao Angular, é natural que eu esteja tentando aprender o Svelte copiando as abordagens que já me são familiares. E é exatamente sobre isso que este artigo será: como fazer as mesmas coisas no Svelte e no Angular.
Nota: Apesar de, em alguns casos, expressar minha preferência, o artigo não é uma comparação de estruturas. Esta é uma introdução rápida e fácil ao Svelte para pessoas que já usam o Angular como sua estrutura principal.
Spoiler de aviso: Svelte é divertido.
Componentes
No Svelte, cada componente é associado ao arquivo em que está gravado. Por exemplo, o componente Button
será criado nomeando o arquivo Button.svelte
. É claro que geralmente fazemos o mesmo no Angular, mas conosco é apenas uma convenção. (No Svelte, o nome do componente a ser importado também pode não coincidir com o nome do arquivo - observação do tradutor)
Os componentes Svelte são de arquivo único e consistem em 3 seções: script
, style
e um modelo que não precisa ser envolvido em nenhuma tag especial.
Vamos criar um componente muito simples que mostra "Hello World".

Importar componentes
Em geral, isso é semelhante à importação de um arquivo JS, mas com algumas ressalvas:
- você deve especificar explicitamente a
.svelte
arquivo do componente .svelte
- componentes são importados dentro da
<script>
<script> import Todo from './Todo.svelte'; </script> <Todo></Todo>
Com os snippets acima, é óbvio que o número de linhas para criar um componente no Svelte é incrivelmente pequeno. Obviamente, existem algumas implicações e limitações, mas ao mesmo tempo tudo é simples o suficiente para se acostumar rapidamente.
Sintaxe básica
Interpolação
As interpolações no Svelte são mais semelhantes às do React do que no Vue ou Angular:
<script> let someFunction = () => {...} </script> <span>{ 3 + 5 }</span> <span>{ someFunction() }</span> <span>{ someFunction() ? 0 : 1 }</span>
Eu estou acostumado a usar chaves duplas, então às vezes estou trancado, mas talvez eu só tenha esse problema.
Atributos
Passar atributos para componentes também é bastante simples. As aspas são opcionais e qualquer expressão Javascript pode ser usada:
//Svelte <script> let isFormValid = true; </script> <button disabled={!isFormValid}></button>
Eventos
A sintaxe para os manipuladores de eventos é: on:={}
.
<script> const onChange = (e) => console.log(e); </script> <input on:input={onChange} />
Ao contrário de Angular, não precisamos usar parênteses após o nome da função para chamá-lo. Se você precisar passar argumentos para o manipulador, use a função anônima:
<input on:input={(e) => onChange(e, 'a')} />
Minha opinião sobre a legibilidade desse código:
- Temos que imprimir menos, porque não precisamos de aspas e colchetes - isso é bom mesmo assim.
- Leia mais. Eu sempre gostei da abordagem Angular em vez de React, então para mim e Svelte é mais difícil de adotar. Mas esse é apenas meu hábito e minha opinião é um tanto tendenciosa.
Diretivas estruturais
Diferentemente das diretivas estruturadas no Vue e Angular, o Svelte oferece uma sintaxe especial para loops e ramificações dentro de modelos:
{#if todos.length === 0} {:else} {#each todos as todo} <Todo {todo} /> {/each} {/if}
Eu realmente gosto disso. Nenhum elemento HTML adicional é necessário e, em termos de legibilidade, isso parece incrível. Infelizmente, o símbolo #
no layout de teclado britânico do meu Macbook está em um local inacessível, e isso afeta negativamente minha experiência com essas estruturas.
Propriedades de entrada
Definir propriedades que podem ser passadas para um componente (análogo ao @Input
em Angular) é tão fácil quanto exportar uma variável de um módulo JS usando a palavra-chave export
. Talvez a princípio possa ser confuso - mas vamos escrever um exemplo e ver como é realmente simples:
<script> export let todo = { name: '', done: false }; </script> <p> { todo.name } { todo.done ? '✓' : '✕' } </p>
- Como você pode ver, inicializamos a propriedade
todo
junto com o valor: será o valor da propriedade por padrão, caso não seja transmitida do componente pai
Agora crie um contêiner para este componente, que transmitirá dados para ele:
<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}
Semelhante aos campos em um objeto JS comum, todo={todo}
pode ser reduzido e reescrito da seguinte maneira:
<Todo {todo}></Todo>
A princípio me pareceu estranho, mas agora acho que é brilhante.
Propriedades de saída
Para implementar o comportamento da diretiva @Output
, por exemplo, quando o componente pai @Output
notificações do filho, usaremos a função createEventDispatcher
, disponível no Svelte.
- Importe a função
createEventDispatcher
e atribua seu valor de retorno à variável de dispatch
- A função de
dispatch
possui dois parâmetros: o nome do evento e os dados (que caem no campo de detail
do objeto de evento) markDone
dispatch
dentro da função markDone
, chamada pelo 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>
No componente pai, você precisa criar um manipulador para o evento done
, para poder marcar os objetos necessários na matriz todo
.
- Crie a função
onDone
- Atribuímos essa função ao manipulador de eventos chamado no componente filho, da seguinte maneira:
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 acionar a detecção de uma alteração em um objeto, não modificamos o objeto em si. Em vez disso, atribuímos à variável todos
uma nova matriz, onde o objeto da tarefa desejada já será alterado para concluído.
Portanto, Svelte é considerado verdadeiramente reativo : com a atribuição usual de um valor a uma variável, a parte correspondente da representação também mudará.
ngModel
O Svelte possui uma sintaxe de bind:<>={}
especial bind:<>={}
para vincular variáveis específicas aos atributos de um componente e sincronizá-las entre si.
Em outras palavras, permite organizar a ligação de dados bidirecional:
<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>
Expressões Reativas
Como vimos anteriormente, o Svelte responde à atribuição de valores a variáveis e redesenha a exibição. Você também pode usar expressões reativas para responder a alterações no valor de uma variável e atualizar o valor de outra.
Por exemplo, vamos criar uma variável que deve nos mostrar que, na matriz todos, todas as tarefas são marcadas como concluídas:
let allDone = todos.every(({ done }) => done);
No entanto, a exibição não será redesenhada quando a matriz for atualizada, porque o valor da variável allDone
atribuído apenas uma vez. Usaremos uma expressão reativa, que ao mesmo tempo lembrará a existência de "labels" em Javascript:
$: allDone = todos.every(({ done }) => done);
Parece muito exótico. Se lhe parecer que existe "muita mágica", lembro que as tags são Javascript válido .
Uma pequena demonstração explicando o acima:

Injeção de conteúdo
Para incorporar conteúdo, também são usados os slots que são colocados no lugar certo dentro do componente.
Para exibir simplesmente o conteúdo que foi transferido dentro do elemento componente, um elemento de slot
especial é usado:
// 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>
Nesse caso, a ""
substituirá o elemento <slot></slot>
.
Os slots nomeados precisarão ser nomeados:
// 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
O Svelte oferece 4 ganchos de ciclo de vida importados do pacote svelte
.
- onMount - chamado quando um componente é montado no DOM
- beforeUpdate - chamado antes de atualizar o componente
- afterUpdate - chamado após a atualização do componente
- onDestroy - chamado quando um componente é removido do DOM
A função onMount
usa como parâmetro uma função de retorno de chamada que será chamada quando o componente for colocado no DOM. Simplificando, é semelhante à ngOnInit
gancho ngOnInit
.
Se a função de retorno de chamada retornar outra função, ela será chamada quando o componente for removido do 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>
É importante lembrar que, ao chamar onMount
todas as propriedades incluídas nele já devem estar inicializadas. Ou seja, no fragmento acima, todo
já deve existir.
Gestão estatal
Gerenciar seu estado em Svelte é incrivelmente simples, e talvez essa parte da estrutura simpatize comigo mais do que qualquer outra pessoa. Você pode esquecer a verbosidade do código ao usar o Redux. Por exemplo, criaremos armazenamento em nosso aplicativo para gerenciamento de armazenamento e tarefas.
Vaults graváveis
Primeiro, você precisa importar o writable
armazenamento writable
do pacote svelte/store
e informar o valor inicial initialState
import { writable } from 'svelte/store'; const initialState = [{ name: " Svelte", done: false }, { name: " Vue", done: false }]; const todos = writable(initialState);
Normalmente, eu coloco código semelhante em um arquivo separado como todos.store.js
e exporto a variável de armazenamento a partir dele para que o componente onde eu o importe possa trabalhar com ele.
Obviamente, o objeto todos
agora se tornou um repositório e não é mais uma matriz. Para obter o valor do armazenamento, usaremos um pouco de mágica no Svelte:
- Ao adicionar o caractere
$
ao nome da variável de armazenamento, obtemos acesso direto ao seu valor!
Assim, simplesmente substituímos no código todas as referências à variável todos
por $todos
:
{#each $todos as todo} <Todo todo={todo} on:done={onDone}></Todo> {/each}
Configuração de estado
O novo valor do armazenamento gravável pode ser especificado chamando o método set
, que altera imperativamente o estado de acordo com o valor passado:
const todos = writable(initialState); function removeAll() { todos.set([]); }
Atualização de status
Para atualizar o armazenamento (no nosso caso, todos
), com base em seu estado atual, é necessário chamar o método de update
e passar uma função de retorno de chamada que retornará o novo estado para o armazenamento.
onDone
função onDone
que criamos anteriormente:
function onDone(event) { const name = event.detail; todos.update((state) => { return state.map((todo) => { return todo.name === name ? {...todo, done: true} : todo; }); }); }
Aqui eu usei um redutor diretamente no componente, o que é uma má prática. Nós o movemos para um arquivo em nosso repositório e exportamos uma função que simplesmente atualiza o estado.
Assinatura de alteração de status
Para descobrir que o valor no repositório mudou, você pode usar o método de subscribe
. Lembre-se de que o repositório não é um objeto observable
, mas fornece uma interface semelhante.
const subscription = todos.subscribe(console.log); subscription();
Observáveis
Se essa parte causou a maior empolgação para você, recomendo que, não muito tempo atrás, o suporte ao RxJS tenha sido adicionado ao Svelte e o Observable for ECMAScript tenha sido introduzido.
Como desenvolvedor Angular, já estou acostumado a trabalhar com programação reativa, e a falta de uma contrapartida de tubo assíncrono seria extremamente inconveniente. Mas Svelte me surpreendeu aqui também.
Vejamos um exemplo de como essas ferramentas funcionam juntas: exiba uma lista de repositórios no Github, encontrada pela palavra-chave "Svelte"
.
Você pode copiar o código abaixo e executá-lo diretamente no 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}
Basta adicionar o símbolo $
ao nome da variável observável repos$
e o Svelte exibirá automaticamente seu conteúdo.
Minha lista de desejos para Svelte
Suporte para texto datilografado
Como entusiasta do texto datilografado, não posso deixar de desejar a possibilidade de usar tipos no Svelte. Estou tão acostumado a isso que às vezes me empolgo e organizo tipos no meu código, que depois preciso remover. Eu realmente espero que o Svelte em breve adicione suporte ao Typescript. Acho que este item estará na lista de desejos de quem quiser usar o Svelte com experiência com o Angular.
Acordos e diretrizes
A renderização na representação de qualquer variável do bloco <script>
é um recurso muito poderoso da estrutura, mas, na minha opinião, pode levar à confusão de códigos. Espero que a comunidade Svelte trabalhe com várias convenções e diretrizes para ajudar os desenvolvedores a escrever um código de componente limpo e compreensível.
Apoio comunitário
O Svelte é um projeto grandioso que, com o maior esforço da comunidade para escrever pacotes de terceiros, manuais, artigos de blog e muito mais, pode decolar e se tornar uma ferramenta reconhecida no incrível mundo do desenvolvimento Frontend que temos hoje.
Em conclusão
Apesar de não ser fã da versão anterior do framework, o Svelte 3 me impressionou bastante. É simples, pequeno, mas pode fazer muito. É tão diferente de tudo que me rodeia que me lembrou a emoção que senti quando mudei do jQuery para o Angular.
Independentemente de qual estrutura você está usando agora, é provável que o aprendizado do Svelte demore apenas algumas horas. Depois de aprender o básico e entender as diferenças com o que você está acostumado a escrever, será muito fácil trabalhar com o Svelte.
No canal em russo do Telegram @sveltejs, você certamente encontrará desenvolvedores com experiência em várias estruturas e prontos para compartilhar suas histórias, pensamentos e dicas sobre o Svelte.