Convertendo uma aplicação angular em sveltejs-pt.1
Apresentando o framework.
Como descrito no artigo explicativo, o svelte trata-se de framework ou biblioteca, como queiram denominar, para construção de componentes assim como os seus três maiores “concorrentes”: vue, react e angular. Porém, se destaca, por trabalhar de forma diferente dos outros frameworks, compilando o código escrito para Javascript puro sem levar o próprio do framework para o bundler final, ou seja, o svelte trabalha em tempo de compilação, não necessitando levar alguma dependência própria para funcionar. Por exemplo, o react necessita de dependências básicas para funcionar: react.js +react.dom.js(links).
Vejamos a tabela abaixo:
Devido a esta característica, o framework vem ganhado notoriedade sendo utilizado em ambientes bem limitados em recursos, como pouca memória e pouco espaço de armazenamento. Um case conhecido é o gateway de pagamentos stone, que tem um toolkit de componentes desenvolvidos com svelte, que é utilizado para as interface visual da máquina de cartões.
No bestofjs, que classifica as bibliotecas Javascript pelo número de estrelas no github, o svelte já aparece no top 5 de tendências por média de estrelas/dia adicionadas anualmente.
No stateofjs2018, o svelte ficou no topo das menções na secção “Outros frameworks” no item Front-end Frameworks. Acredito que na pesquisa de 2019, o svelte venha a aparecer em uma posição mais contundente nas próximas pesquisas, um mero palpite da minha parte.
A estrutura de um componente svelte é bem simples separando a parte Javascript dentro de uma tag <script> , o css dentro da tag <style> e após ou entre estas tags o html, algo parecido com os single file components do vuejs.
<script>
let name = ‘world’;
</script><h1>Hello {name}!</h1><style>
h1 {
color: red;
}
</style>
O que vamos construir?
Como o título do artigo sugere, vamos reescrever uma aplicação feita em angular.
PS. Fiz esta aplicação em angular quando estava aprendendo sobre a tecnologia, e ao longo do tempo fui incrementando o projeto e recentemente atualizei a versão do estável do angular(8.0). Tentei escrever em outros frameworks, mas não consegui por falta de tempo.
A proposta é simples, fazer uma pokedex utilizando a PokéAPI. A PokéAPI é uma API aberta, não é necessário fazer contas e conseguir APIKEYS para consumo da API, como é uma API “open” ela não é tão performática e não é tão bem estruturada, mas para serve muito bem para esta propósta que é construir uma aplicação simples.
O que vamos utilizar.
Para explicar a escolha do ParcelJs como module bundler(empacotador), vou começar pela escolha do TailwindCSS como biblioteca utilitária para o css. O tailwindcss é um utilitário para estilizar nossos componentes e páginas do projeto, o tailwind diferente das outras bibliotecas utilitárias(Bootstrap, Foundation, MaterialializeCSS) fornece classes básicas para tratar tamanhos(width, height), fontes, cores, espaçamento(padding, margin) e com essas classes contruir e estilizar componentes básicos como card e formulário, enquanto que seus concorrentes já nos disponibiliza um toolkit de componentes “prontos”.
Para compilar o tailwind com o svelte, é necessário a utilização de um pré-processador css, na documentação do tailwind é recomendado o uso do PostCSS, mas esta não é a única forma de se trabalhar com o tailwindcss.
O postcss é um “pre-processador” css, que permite a utilização de plugins para processar o css, como exemplo, foi utilizado no projeto o PurgeCSS que tem como objetivo remover o css inutilizado otimizando o css final gerado.
Explicado isso, vamos para o porquê do parceljs.
No guia de como iniciar com svelte uma das recomendações é utilizar o Degit como ferramenta para começar novos projetos, algo parecido com o create react app, temos como opções para module bundler(empacotadores) o rollup ou webpack. Mas durante as pesquisas e o desenvolvimento da aplicação, apesar de serem boas ferramentas para empacotamento do Javascript, optei por utilizar uma terceira opção para começar a “codar”, o parceljs. Tanto com o rollup quanto com o webpack, não consegui configurar ou pelo menos achar uma configuração para se utilizar o postcss para processar o css com o código do svelte. Existe um plugin do svelte para ser utilizado com o parceljs.
Para utilizar o parceljs não necessita de um arquivo de configuração(entrypoint) para compilar o projeto assim como no rollup e webpack, sendo necessário só apontar o index.html dentro do scripts dev ou build no package.json.
E dentro do index.html importar nosso arquivo de entrada Javascript.
Por nossa aplicação ser uma SPA(Single Page Application), é preciso uma biblioteca para trabalhar com rotas, e para isso utilizaremos o svero, que é desenvolvida pela comunidade do svelte, e acredito que seja umas das poucas para o svelte que fazem roteamento, e o svero tem uma abordagem parecida com o react router.
Iniciando o projeto
Feita as escolhas, vamos iniciar a construção da nossa pokedex. Para isso é primordial como primeiro requisito instalar ou ter instalado o nodejs. Após instalar, uma sugestão é instalar o yarn gerenciador de pacotes sendo uma alternativa ao npm que já vem com o nodejs.
Agora vamos criar uma pasta com o nome “svelte-parcel”, após isto, abrir o terminal, navegar até o diretório criado e executar o comando npm init e preencher as informações para iniciar um novo package.json. Para não preencher muitas informções basta executar npm init -y.
Agora vamos instalar nossas dependências, por o svelte se tratar de um compilador, nossas dependências serão instaladas como “devDependencies” e assim não as levando para o build final por isso a adição da flag -D.
yarn add parcel-bundler parcel-plugin-svelte parcel-plugin-svg-sprite svelte tailwindcss @fullhuman/postcss-purgecss -D
Por fim vamos adicionar a biblioteca para trabalhar com rotas na nossa aplicação.
yarn add svero
Para a estrutura de pastas do nosso projeto, primeiro vamos criar a pasta src onde ficará todos nossos componentes. Dentro da pasta src vamos criar os arquivos index.html, main.js, main.css e App.svelte e criar as pastas.
- assets(pasta que armazena as imagens), dentro do assets criar as pastas img e icons(svg’s)
- components(pasta com os componentes globais da aplicação), dentro da pasta components criar as pastas common(components genéricos que podem ser utilizados em outras partes do projeto) e custom (componentes customizados para uma necessidade específica)pages(pasta com as páginas da aplicação),
- services(pastas com os serviços para consgumo da API)
- pages(pasta com os componentes que serão as páginas de home e details)
Agora iremos escrever nossos arquivos de “entry point”(entrada) que são o index.html, main.js e main.css, como vamos trabalhar com o parcel apontando para o index.html como arquivo principal de entrada, inserir no html os arquivos main.css e main.js.
E agora vamos escrever o main.css, com as dependências do tailwind, para não complicar muito vamos extrair as opções default que o tailwind nos oferece.
E agora o main.js, que será a entrada para o arquivo principal do svelte o App.svelte.
Finalizando a configuração do projeto, vamos criar o postcss.config.js que são as configurações tanto para gerar as classes do tailwind que foram declaradas no nosso main.css e para processar os estilos feitos nos nossos componentes svelte, para isso basta apontar para os arquivos “.html” e “.svelte” da nossa aplicação. Esse arquivo é criado na raiz da pasta do projeto no mesmo nível do package.json.
Para executar o projeto, no package.json dentro da propriedade “scripts” vamos criar duas opções:
- Dev para executar o projeto enquanto desenvolvemos
- Build para gerar o arquivos finais para deploy da aplicação
“scripts”: {
“dev”: “parcel src/index.html”,
“build”: “parcel build — no-source-maps src/index.html”,
“test”: “echo \”Error: no test specified\” && exit 1"
},
Estrutura da Aplicação
A aplicação terá um layout bem simples, com um Header, Main com o conteúdo da aplicação e um Footer, e terá uma página incial e uma de detalhes.
Pela simplicidade optei por utilizar o css grid mesmo o flexbox tendo um suporte maior, o sistema de grid é bem robusto e mais organizado. O roteamento será feito no nosso main, que fica no App.svelte. Para fazer a função de roteamento utilizaremos o svero, que é a biblioteca escolhida para trabalhar com rotas.
Estrutura do App.svelte
<div class="grid-box"><!-- Container da App -->
<header>App header</header>
<main>
<Router>
<!--
conteúdo da aplicação com a utilização das rotas
-->
</Router>
</main>
<footer>App footer</footer>
</div>
Os nossos arquivos de página, ou melhor componentes, ficaram na pasta pages e lá criaremos a Detail.svelte e a Home.svelte
A estrutura da home terá um componente de search para procura dos pokemons e uma grid com pokemons aleatórios, por uma limitação da API, para fazer a procura é necessário procurar pelo número ou o nome exato do pokemon. Para isso vamos fazer uma service que faz a procura do pokemon pelo nome ou número. Na pasta src/services vamos criar o PokeService.js, para o consumo da API. Optei por utilizar o fetch, mesmo não tendo um suporte bem abrangente em todos os navegadores é nativo do Javascript não necessitando dependências externas para consumo de API’s
Nos serviços temos:
- getPkmn : Retorno com as informações do pokemon consultado pelo id ou nome completo do pokemon
- getEvolutions: Retorno com as informações sobre a linha evolutória do pokemon consultado pelo id da evolução
- getSpecies: Retorno auxiliar que contem o id da linha de evoluções do pokemon consultado pelo id do pokemon
Página Home
Na home(pages/Home.svelte) vamos utilizar dois recursos do svelte, um é o “await block”, em que podemos exibir conteúdos pelo estado de uma promise, ou seja enquanto uma promise não é resolvida exibimos um conteúdo como um loader, por exemplo e quando for resolvida exibimos os resultados na página e tem até um bloco para tratamento dos erros. Este é um recurso bem interessante e vamos explorar bastante na nossa aplicação.
<script>
let promise = getPromise(); async function getPromise() {
const result = await httpRequest();
return Promise.resolve(result);
}
</script><div>
{#await promise}
<p>Loading …</p>
{:then result}
<p>{ result }</p>
{:catch error}
<p>
Ocorreu um erro ao consultar a API: {error}
</p>
{/await}
</div>
E o outro é o “each block”, que utilizaremos para iterar os resultados da consulta a API, já que é retornado um array de objetos com as informações dos pokemon como nome, imagens, tipos, id, e exibiremos na tela através de um card, o each é um recurso bem comum nos frameworks front-end e aqui não tem muitos mistérios.
PS: temos alguns componentes que serão explicados mais para frente como o Card e o Search que são utilizados na home.
Página de detalhes
Na página de detalhes(pages/Detail.svelte) teremos um card com a imagem de frente e verso do pokemon com nome, uma pequena descrição, tipo e por fim, a linha de evolução. Neste componente utilizaremos também os recursos do await e each block. Para exibir a linha evolutória teremos um componente especial para isso e utilizaremos outros serviços.
Vamos finalizar por aqui e na parte 2 do artigos iremos conhecer os componentes desenvolvidos e finalizar o projeto.
Parte 2 do artigo