<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Gabriel Galdino - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Gabriel Galdino - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:32 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/author/gabrielgaldino/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Por que eu amo o Vim: recursos não tão conhecidos que fazem dele uma ferramenta incrível ]]>
                </title>
                <description>
                    <![CDATA[ Escrito por: Amit Kulkarni Desde que comecei a usar o Vim, em 2016, descobri várias funcionalidades menos conhecidas que ele oferece nativamente, sem a necessidade de plug-ins. Você pode falar de algumas noções básicas antes de começar a explicar sobre essas coisas novas? Ah, com certeza! Antes de copiar e ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/por-que-eu-amo-o-vim-recursos-nao-tao-conhecidos-que-fazem-dele-uma-ferramenta-incrivel/</link>
                <guid isPermaLink="false">6484ff963aab28058e38196d</guid>
                
                    <category>
                        <![CDATA[ Vim ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Tue, 27 Jun 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/1_w9dLy2njrrkNUQVugpF-6g.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/learn-linux-vim-basic-features-19134461ab85/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Why I love Vim: It’s the lesser-known features that make it so amazing</a>
      </p><p>Escrito por: Amit Kulkarni</p><p>Desde que comecei a usar o Vim, em 2016, descobri várias funcionalidades menos conhecidas que ele oferece nativamente, sem a necessidade de <em>plug-ins</em>.</p><h4 id="voc-pode-falar-de-algumas-no-es-b-sicas-antes-de-come-ar-a-explicar-sobre-essas-coisas-novas">Você pode falar de algumas noções básicas antes de começar a explicar sobre essas coisas novas?</h4><p>Ah, com certeza! Antes de copiar e colar alguns comandos de uma folha de dicas, vou fazer uma suposição ousada: você não estaria lendo isso se quisesse uma folha de dicas e se já conhecesse o básico do Vim.</p><p>Você pode ter acabado de ouvir que as distribuições do Linux são fornecidas com um editor de texto de linha de comando padrão chamado Vim – e pode ser que você queira apenas experimentá-lo.</p><p>Então, vamos supor que você seja completamente novo nesse jogo e vamos começar apenas com o básico que precisamos entender (sem história/teoria entediante).</p><blockquote>OBSERVAÇÃO: se você já conhece o básico, <a href="https://www.freecodecamp.org/news/learn-linux-vim-basic-features-19134461ab85/#9b6b">clique aqui para pular essa parte</a>.</blockquote><h4 id="qual-o-seu-diferencial-aqui-em-compara-o-a-muitos-outros-artigos-sobre-o-vim">Qual é o seu diferencial aqui em comparação a muitos outros artigos sobre o Vim?</h4><p><br>A maioria dos artigos introdutórios sobre o Vim começa com os modos: inserir, salvar e sair. Se você estiver realmente com disposição para aprender perfeitamente a teoria dos modos, sinta-se à vontade para ler o que for útil para você nos <a href="https://en.wikibooks.org/wiki/Learning_the_vi_Editor/Vim/Modes" rel="noopener">wikibooks</a> (texto em inglês).</p><p>Também existem ótimos livros e artigos que explicam que há uma filosofia por trás da maneira como o Vim funciona e que os comandos no VI/Vim são destinados a serem combinados. É absolutamente verdade – e tenho certeza de que você apreciará isso assim que se acostumar com o editor e com o poder que ele oferece.</p><h4 id="j-ouvi-hist-rias-engra-adas-e-vi-imagens-engra-adas-sobre-a-curva-de-aprendizado-do-vim-isso-verdade-realmente-t-o-ruim-assim">Já ouvi histórias engraçadas e vi imagens engraçadas sobre a curva de aprendizado do Vim. Isso é verdade? É realmente tão ruim assim?</h4><p>Bem, sempre existirão os <em>haters</em>, certo? No entanto, na minha opinião, a imagem que representa um pouco melhor o Vim é a seguinte:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/1_w9dLy2njrrkNUQVugpF-6g-1.jpeg" class="kg-image" alt="1_w9dLy2njrrkNUQVugpF-6g-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/1_w9dLy2njrrkNUQVugpF-6g-1.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/1_w9dLy2njrrkNUQVugpF-6g-1.jpeg 800w" sizes="(min-width: 720px) 720px" width="800" height="600" loading="lazy"></figure><p>A maioria dos artigos sobre o Vim se refere à <em>curva</em> de aprendizado como uma <em>parede</em> de aprendizado, mas vamos ver a situação positivamente: olhe para o outro lado da parede!</p><p>Para iniciantes, é literalmente uma parede, pois eles nunca fizeram nada parecido antes para usar um editor na linha de comando. O que mais me atraiu quando comecei como iniciante foi a onipresença do Vim.</p><p>Faça login em qualquer máquina (exceto no Windows) a partir de qualquer terminal e você literalmente pode ter um editor digitando <em>vi</em> de olhos fechados. O editor aparecerá na sua frente!</p><p>Outra coisa que me atraiu foi a capacidade de trabalhar sem um mouse e sem perder tempo produtivo com o <em>touchpad </em>ou tendo de conseguir um mouse para o laptop.</p><p>Eu sei, eu sei! Já consigo ouvir alguns de vocês gritando "Emacs! Emacs!". Eu entendo. Ocorre que, desde que me envolvi com o Vim, nunca tive realmente interesse no emacs (talvez por causa da instalação necessária). Então, sim, o emacs também é ótimo, suponho. Sinta-se à vontade para mudar antes de começar essa bela jornada com o VI(m).</p><h4 id="acabei-de-abrir-meu-terminal-digitei-vi-e-pressionei-a-tecla-enter-tudo-o-que-vejo-uma-tela-de-boas-vindas-n-o-consigo-digitar-e-n-o-sei-como-sair-disso-tem-certeza-de-que-um-editor-poderoso-com-recursos">Acabei de abrir meu terminal, digitei vi e pressionei a tecla Enter. Tudo o que vejo é uma tela de boas-vindas. Não consigo digitar e não sei como sair disso. Tem certeza de que é um editor poderoso com recursos?</h4><p>Tenho 100% de certeza. O comportamento que você acabou de presenciar é a "parede" que mencionamos antes. Acredite em mim. O VI(m) pode fazer muitas outras coisas. Ele apenas tem suas próprias maneiras de ser usado. Você pode editar arquivos, abrir abas, dividir a tela horizontal ou verticalmente, navegar no sistema de arquivos, executar comandos Linux sem sair do arquivo, iniciar compilações a partir do seu código-fonte sem sair do arquivo, marcar diretórios e até mesmo linhas de um arquivo, buscar e substituir palavras, copiar e colar (logicamente), e muito mais.</p><h4 id="sim-como-se-fosse-uma-grande-coisa-para-um-editor-suportar-esses-recursos-todo-mundo-faz-isso-qual-a-novidade">Sim, como se fosse uma grande coisa para um editor suportar esses recursos. Todo mundo faz isso. Qual é a novidade?</h4><p>Não há uma novidade. A vantagem que vejo é a capacidade de focar no seu arquivo/código sem precisar sair do teclado. Sério, se você não se importa em usar um mouse, vá em frente e abra seu MS Word ou outro editor com interface gráfica qualquer e faça todas as edições que desejar.</p><h4 id="entendi-por-que-n-o-usar-um-ide-para-fazer-alguns-trabalhos">Entendi. Por que não usar um IDE para fazer alguns trabalhos?</h4><p>Ok, então você é um desenvolvedor e gosta/ama um IDE. Não, o VI(m) não substitui o seu IDE incrível. O VI(m) não possui os recursos incríveis de fábrica que o seu IDE possui. O VI(m) é apenas pequeno em tamanho (pacote e instalação) em comparação com os IDEs robustos e está disponível para uso sem precisar de configuração ou instalações. Sério, o VI(m) não se compara às ótimas coisas que seu IDE oferece.</p><h4 id="chega-de-conversa-mostre-me-o-b-sico-">Chega de conversa! Mostre-me o básico.</h4><p>Claro. Antes de começar, tenha em mente que qualquer usuário do Vim basicamente lida com o modo de comando e o modo de inserção. Não há escapatória (literalmente – a tecla Esc não serve para "escapar").</p><p>Vamos supor que você esteja usando algum editor e queira excluir uma função longa na linguagem C. Os passos simples que você faz são: posicione o cursor no início da linha e pressione Shift + seta para baixo até o final ou use o mouse. Essa ação que você teve que fazer para selecionar essas linhas exigiu que você <em>parasse</em> de digitar e pressionasse teclas. Não é verdade? Não me diga que você estava digitando algo e ao mesmo tempo pressionou teclas para selecionar magicamente o corpo da sua função.</p><blockquote>Seja razoável. Você pausou a digitação e fez o trabalho de seleção para dizer ao seu editor que você quer fazer algo com esse texto (copiar/recortar/negrito/itálico/qualquer coisa).</blockquote><p>Essa pausa que você fez é equivalente a estar no modo de comando no VI(m). Este é o momento em que você diz ao VI(m) que deseja fazer algumas ações em algumas linhas/palavra/qualquer coisa e você não vai digitar. Agora, VI(m) lança você para fora do modo de inserção e você está bloqueado para não digitar texto em seu arquivo. Obviamente, o outro modo no qual você pode realmente digitar em seu arquivo é o modo de inserção.</p><p>Aliás, se você estava se perguntando como selecionar o corpo da função sem selecionar o texto ou usar o mouse, eu faço isso colocando o cursor nas chaves de abertura e usando as teclas: <code>d%</code></p><p>Sim, isso exclui o conteúdo do corpo da sua função. Não, não é uma combinação assustadora de teclas para lembrar! <code>d</code> indica que você quer excluir algo (do inglês, <em>delete</em>). <code>%</code> vai mover o cursor para o final da chave correspondente.</p><p>Agora que estabelecemos os modos básicos, vamos mergulhar no básico do VI(m).</p><p>Se você conhece o nome do arquivo que está escrevendo:</p><pre><code class="language-bash">$ vi meuarquivo.c</code></pre><p>Se você não tem certeza do nome do arquivo e quer começar a digitar:</p><pre><code class="language-bash">$ vi</code></pre><p>Assim que você abrir o vi, estará no modo de comando. Para entrar no modo de inserção, pressione <code>i</code> . Digite o que desejar. Pressione <code>Esc</code> para voltar ao modo de comando. Agora você tem algumas opções para sair, dependendo de como abriu o vi.</p><p>Se você deu um nome de arquivo: <code>:w</code> gravará essas alterações com segurança no disco. <code>:q</code> sairá do editor. &nbsp;Você pode combinar essas ações com &nbsp;<code>:wq</code> &nbsp;e a tecla <code>Return</code>.</p><p>Se você não deu um nome de arquivo: <code>:wq nomedoarquivo.c</code> gravará o conteúdo no arquivo <code>nomedoarquivo.c</code> e sairá do editor. Se você não estiver interessado no texto que escreveu e desejar sair sem salvar nada: <code>:q!</code> e pronto! O <code>!</code> é necessário no final para dizer: "Sim, tenho certeza de que não quero salvar o conteúdo e quero sair urgentemente".</p><p><strong><strong>[DEMO] </strong></strong><a href="https://asciinema.org/a/wLpVX8lUuaK5mfG4tyVCk61qD"><strong>Uso básico do Vim</strong></a></p><p>Pronto! Você acabou de criar, editar e salvar (ou talvez não) seu primeiro arquivo vi. Parabéns!</p><p>Como mencionei anteriormente, esta não é uma introdução para iniciantes ao VI(m). Existem muitos outros artigos (fornecerei referências no final do artigo) para começar. Eu incluí essa introdução apenas para que você não se decepcione ao chegar nesta página e não encontrar nada para aprender.</p><blockquote>Esta é a linha onde os iniciantes se despedem dos usuários intermediários e vão para a seção de referência em busca de mais artigos introdutórios brilhantes.</blockquote><p>Boas-vindas aos usuários intermediários. Essas são algumas capacidades legais do VI(m) das quais eu não estava ciente, mas que, agora, uso diariamente para ser mais produtivo.</p><p>Para aqueles que preferem um resumo:</p><ul><li>Abas</li><li>Sessões</li><li>Números de linha (+ marcas) e copiar/colar</li><li>Dobramento </li><li>Indentação com <code>=</code></li><li>Completar ao inserir</li><li>Netrw</li><li>Divisões/janelas</li><li><code>:!</code> e um pouquinho sobre <code>:make</code></li></ul><h4 id="abas-no-vim"><strong>Abas no Vim</strong></h4><h4 id="voc-mencionou-abas-no-vim-eu-n-o-sabia-que-isso-existia-">Você mencionou abas no Vim? Eu não sabia que isso existia!</h4><p>Eu sei, não é incrível? Uma <a href="http://vimdoc.sourceforge.net/htmldoc/tabpage.html#tab-page-intro">aba</a> é uma página com uma ou mais janelas com um rótulo no topo.</p><p>Se você tiver interesse em saber mais sobre janelas, <em>buffers </em>e abas: <a href="http://vimdoc.sourceforge.net/htmldoc/windows.html#windows-intro">detalhes técnicos</a>.</p><p>Dê uma olhada:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/2iMvCsKGk8iMrERGtswmB-s59dhc6A5soBD0.png" class="kg-image" alt="2iMvCsKGk8iMrERGtswmB-s59dhc6A5soBD0" width="504" height="128" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/ec7MggpObT5GhBjZS9-XtZ4bDzjj5SUxhtlj.png" class="kg-image" alt="ec7MggpObT5GhBjZS9-XtZ4bDzjj5SUxhtlj" width="496" height="124" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Hvd4DnXCni865974XxISsJuQlkMVCAPclhxk.png" class="kg-image" alt="Hvd4DnXCni865974XxISsJuQlkMVCAPclhxk" width="496" height="126" loading="lazy"><figcaption>Abas do Vim em ação</figcaption></figure><p>Passo a passo:</p><ul><li>Abra o Vim com qualquer arquivo ou apenas com o Vim: <code>$ vim file1</code>.</li><li>Digite o conteúdo do arquivo e entre no modo de comando (pressione <code>Esc</code>).</li><li><code>:tabedit file2</code> abrirá uma nova aba e o levará para editar o <code>file2</code>.</li><li><code>:tabedit file3</code> abrirá uma nova aba e o levará para editar o <code>file3</code>.</li><li>Para navegar entre essas abas, você pode estar no modo normal e digitar: <code>gt</code> para ir para a próxima aba ou <code>gT</code> para ir para a aba anterior. Você também pode navegar até uma aba específica usando <code>{i}gt</code>, onde i é o índice da sua aba. Exemplo: <code>2gt</code> leva você para a segunda aba.</li><li>Para ir diretamente para a primeira ou última aba, você pode digitar o seguinte no modo de comando: <code>:tabfirst</code> ou <code>:tablast</code> para a primeira ou para a última aba, respectivamente. Para avançar e voltar: <code>:tabn</code> para a próxima aba e <code>:tabp</code> para a aba anterior.</li><li>Você pode listar todas as abas abertas usando: <code>:tabs</code>.</li><li>Para abrir vários arquivos em abas: <code>$ vim -p source.c source.h</code>.</li><li>Para fechar uma única aba: <code>:tabclose</code>. Para fechar todas as outras abas, exceto a atual: <code>:tabonly</code>. Use o sufixo <code>!</code> para ignorar as alterações de arquivos não salvos.</li></ul><p><strong><strong>[DEMO] </strong></strong><a href="https://asciinema.org/a/ZMUyM27ZTc04yctzH7S9JyNLo"><strong>Abas no<strong> VIM</strong></strong></a></p><p>Acho que essa funcionalidade nos permite economizar tempo efetivamente, compartilhando o <em>buffer </em>entre as abas e nos permitindo copiar/colar entre as abas e manter várias sessões de abas diferentes para cada categoria de trabalho. Por exemplo: você pode ter uma aba de terminal com todas as abas do Vim contendo apenas arquivos de código-fonte C e outra aba de terminal com todas as abas do Vim contendo arquivos de cabeçalho (.h).</p><h4 id="as-abas-fornecem-tanta-conveni-ncia-para-manter-todos-os-meus-arquivos-abertos-e-acess-los-quando-eu-quiser-no-entanto-n-o-um-inc-modo-ter-que-abrir-todas-as-abas-toda-vez-que-reinicio-ou-fecho-e-abro-o-terminal">As abas fornecem tanta conveniência para manter todos os meus arquivos abertos e acessá-los quando eu quiser. No entanto, não é um incômodo ter que abrir todas as abas toda vez que reinicio ou fecho e abro o terminal?</h4><p>Com certeza! Todos nós gostamos de ter nossas próprias sessões de trabalho nas quais trabalhamos com um conjunto de arquivos e gostaríamos que o Vim restaurasse a sessão de abas do jeito que a deixamos. O Vim nos permite salvar e restaurar essas sessões de abas! ✋</p><p>Passo a passo:</p><ul><li>Abra quantas abas você quiser trabalhar.</li><li>A partir de qualquer aba, pressione <code>Esc</code> e entre no modo de comando.</li><li>Digite: <code>:mksession header-files-work.vim</code> e pressione Enter.</li><li>Sua sessão atual de abas abertas será armazenada em um arquivo chamado <code>header-files-work.vim</code>.</li><li>Para ver a restauração em ação, feche todas as abas e o Vim.</li><li>Inicie o vim com sua sessão usando: <code>$ vim -S header-files-work.vim</code> ou abra o vim com qualquer outro arquivo e entre no modo de comando para digitar: <code>:source header-files-work.vim</code> e pronto! Todas as suas abas serão abertas exatamente como você as salvou!</li><li>Se você alterar as abas da sessão (fechar/abrir novas), você pode salvá-las novamente usando: <code>:mks!</code> enquanto estiver na sessão.</li></ul><p><strong><strong>[DEMO]</strong></strong><a href="https://asciinema.org/a/NLn3NjxfBavV4mnURQWF2GlUg"><strong><strong> S</strong>essões no Vim</strong></a></p><h3 id="posso-copiar-cortar-colar-sem-precisar-saber-os-n-meros-das-linhas">Posso copiar/cortar/colar sem precisar saber os números das linhas?</h3><p>Ah, sim! Antes, eu costumava ver os números das linhas (<code>:set nu</code>)das funções que queria copiar/cortar. Digamos que eu queira copiar/cortar as linhas de 34 a 65. Eu usava <code>:34,65y</code> (Copiar/Obter) ou <code>:34,65d</code> (Cortar/Excluir).</p><blockquote>Claro que contar as linhas e usar <code>{n}yy</code> ou <code>{n}dd</code> (onde <code>n</code> é o número de linhas) não é uma opção quando estamos falando de centenas de linhas, certo?</blockquote><p>Pode haver algumas funções que se estendem por várias páginas e você não quer descer apenas para depois esquecer qual era o número da primeira linha. Há uma maneira simples de se fazer isso sem se preocupar com os números das linhas!</p><p>Passo a passo:</p><ul><li>Entre no modo normal, vá para a linha de início.</li><li>Digite <code>mk</code> (marcação de um ponto com a letra 'k' ou com qualquer outra letra).</li><li>Mova para baixo (page down ou qualquer outro) e vá para a linha final.</li><li><code>y'k</code> copiará todas as linhas do início ao fim.</li><li><code>d'k</code> cortará/excluirá todas as linhas do início ao fim.</li></ul><h4 id="eu-tenho-algumas-fun-es-longas-irritantes-no-topo-do-meu-arquivo-e-n-o-quero-perder-tempo-rolando-ou-pulando-para-determinadas-linhas-sei-que-pode-ser-muito-pedir-isso-porque-n-o-uma-ide-mas-por-acaso-podemos-fazer-o-dobramento-dos-blocos-de-c-digo">Eu tenho algumas funções longas irritantes no topo do meu arquivo e não quero perder tempo rolando ou pulando para determinadas linhas. Sei que pode ser muito pedir isso, porque não é uma IDE, mas, por acaso, podemos fazer o "dobramento" dos blocos de código?</h4><p>Com certeza! Digamos que você queira pular a etapa de lembrar os números das linhas e andar por aí com seu novo amor, <em>os marcadores</em>. Vá para o início do corpo da função e digite <code>mb</code>. Agora, vá para o final do corpo da função usando <code>%</code> (correspondência de chaves) ou qualquer outra técnica conveniente e pressione <code>zf'b</code> e pronto!</p><p>Antes e depois:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/pQwngYKhoq7uH095IKSfMJnhsupztCrys20q.png" class="kg-image" alt="pQwngYKhoq7uH095IKSfMJnhsupztCrys20q" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/pQwngYKhoq7uH095IKSfMJnhsupztCrys20q.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/pQwngYKhoq7uH095IKSfMJnhsupztCrys20q.png 800w" sizes="(min-width: 720px) 720px" width="800" height="568" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Rs9pkL4XAD5wiAOgWZlN8enMjeWXICv54R67.png" class="kg-image" alt="Rs9pkL4XAD5wiAOgWZlN8enMjeWXICv54R67" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/Rs9pkL4XAD5wiAOgWZlN8enMjeWXICv54R67.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/Rs9pkL4XAD5wiAOgWZlN8enMjeWXICv54R67.png 800w" sizes="(min-width: 720px) 720px" width="800" height="186" loading="lazy"><figcaption>Antes e depois</figcaption></figure><p>Se você se sentir confortável usando os números de linha, o comando é ainda mais fácil de lembrar: <code>:5,16fo</code> (fo significa "code fold" – "dobramento" de código). Depois de "dobrar" o seu código, é fácil alternar entre as visualizações abertas e fechadas usando <code>zo</code> (abrir a dobra de código) e <code>zc</code> (fechar a dobra de código). Não se preocupe tanto com isso. Basta usar <code>za</code> para alternar entre dobras abertas e fechadas.</p><p>Digamos que você tenha gasto bastante tempo dobrando suas funções em um arquivo grande. Obviamente, você vai querer manter essas dobras todas as vezes que abrir o arquivo, certo? Por que você gastaria sua energia dobrando-as se não fosse assim? Portanto, há uma solução direto no seu <code>~/.vimrc</code>. Insira as seguintes linhas no seu<code>~/.vimrc</code> e suas dobras de código serão salvas e restauradas:</p><pre><code class="language-bash">autocmd BufWinLeave *.* mkview
autocmd BufWinEnter *.* silent loadview</code></pre><h4 id="normalmente-eu-me-preocupo-com-minha-indenta-o-mas-s-vezes-tenho-que-editar-o-c-digo-de-outra-pessoa-que-n-o-teve-a-mesma-preocupa-o-com-a-indenta-o-existem-atalhos-m-gicos-para-fazer-isso-acontecer">Normalmente, eu me preocupo com minha indentação, mas, às vezes, tenho que editar o código de outra pessoa que não teve a mesma preocupação com a indentação. Existem atalhos mágicos para fazer isso acontecer?</h4><p>Claro! É tão simples quanto: <code>=i{</code> . É isso mesmo! (<strong><em>i</em></strong> significa objeto interno)</p><p><strong><strong>[DEMO]</strong> </strong><a href="https://asciinema.org/a/34MuR5ZxuRTWNmSZBuce1mwRK"><strong>Indentação no Vim</strong></a></p><p>Antes e depois:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/eTijXdqLGj8P4sipH3Sa7t5Kf8-rR6Ea7vik.png" class="kg-image" alt="eTijXdqLGj8P4sipH3Sa7t5Kf8-rR6Ea7vik" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/eTijXdqLGj8P4sipH3Sa7t5Kf8-rR6Ea7vik.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/eTijXdqLGj8P4sipH3Sa7t5Kf8-rR6Ea7vik.png 800w" sizes="(min-width: 720px) 720px" width="800" height="507" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/V8qnKIyQxly71eRewU4tcruxI-UCF1w-3G8F.png" class="kg-image" alt="V8qnKIyQxly71eRewU4tcruxI-UCF1w-3G8F" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/V8qnKIyQxly71eRewU4tcruxI-UCF1w-3G8F.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/V8qnKIyQxly71eRewU4tcruxI-UCF1w-3G8F.png 800w" sizes="(min-width: 720px) 720px" width="800" height="579" loading="lazy"><figcaption>Antes e depois</figcaption></figure><p>Tudo o que você precisa fazer é colocar o cursor em qualquer lugar dentro de um bloco que você deseja indentar, pressionar <code>Esc</code> para entrar no modo normal e, em seguida, <code>=i{</code> . Pronto! Todo o corpo da função (incluindo blocos internos) será indentado.</p><blockquote>OBSERVAÇÃO: não espere indentação em seus arquivos Python. Isso só funciona quando o Vim consegue identificar o início e o fim usando parênteses de abertura e fechamento.</blockquote><p>Você também pode aumentar/diminuir a indentação dentro de um bloco usando: <code>&gt;;i{</code> para aumentar e <code>nd&lt;i{</code> para diminuir no modo normal.</p><h4 id="posso-estar-sonhando-mas-voz-tr-mula-quero-dizer-eu-s-quero-tentar-h-posso-estar-exagerando-muito-com-essa-pergunta-mas-pausa-de-5-segundos-n-o-importa-vamos-para-a-pr-xima-pergunta-">Posso estar sonhando, mas (<em>voz trêmula</em>), quero dizer, eu só quero tentar, hãããã, posso estar exagerando muito com essa pergunta, mas (pausa de 5 segundos)... não importa, vamos para a próxima pergunta.</h4><p>O Vim é bastante receptivo a críticas e reconhece que não é um IDE. Vamos lá, vamos ver o que você tem.</p><h4 id="bem-desculpe-mas-por-acaso-ofegante-com-algum-plug-in-ou-algo-assim-o-vim-tem-autocompletar-como-um-ide">Bem, desculpe, mas, por acaso (<em>ofegante</em>), com algum <em>plug-in</em> ou algo assim, o Vim tem autocompletar como um IDE?</h4><p>Você pode ficar surpreso, mas sim! Além disso, adivinha... </p><p><em>rufar de tambores</em>... <br><em>rufar de tambores</em>... <br><em>rufar de tambores</em>... <br><em>rufar de tambores</em>...<br></p><p><strong>Sem nenhum <em>plug-in</em>!</strong></p><p>Você me ouviu certo! A única condição para o Vim mostrar opções é "o Vim deve saber sobre o que você está falando". Isso pode ser através de um arquivo de origem incluído ou de funções ou variáveis definidas.</p><p>Tudo o que você precisa fazer é começar a digitar e, em seguida, pressionar <code>Ctrl+n</code> no modo de inserção.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/bpqE5V4PSocJYzVCra5QVFD6WpWQgdKyHcw-.png" class="kg-image" alt="bpqE5V4PSocJYzVCra5QVFD6WpWQgdKyHcw-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/bpqE5V4PSocJYzVCra5QVFD6WpWQgdKyHcw-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/bpqE5V4PSocJYzVCra5QVFD6WpWQgdKyHcw-.png 766w" sizes="(min-width: 720px) 720px" width="766" height="302" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/OBwyMT5rKu2tqTiEYbG-ZiUGdyZQ-J0hKdhJ.png" class="kg-image" alt="OBwyMT5rKu2tqTiEYbG-ZiUGdyZQ-J0hKdhJ" width="582" height="456" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/PtWzDrYGUVKQKHZrX7sNd8PkYQKV54qhXjRf.png" class="kg-image" alt="PtWzDrYGUVKQKHZrX7sNd8PkYQKV54qhXjRf" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/PtWzDrYGUVKQKHZrX7sNd8PkYQKV54qhXjRf.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/PtWzDrYGUVKQKHZrX7sNd8PkYQKV54qhXjRf.png 800w" sizes="(min-width: 720px) 720px" width="800" height="580" loading="lazy"><figcaption>Exemplos em C, Python e Java</figcaption></figure><p>Imagine só as possibilidades, especialmente se você estiver escrevendo código em C e não conseguir se lembrar da chamada exata da biblioteca OpenSSL. Tudo o que você precisa fazer é incluir o cabeçalho!</p><p><a href="https://asciinema.org/a/NXJIU6fNkCz2Lk2uKYBhcv5Fi"><strong><strong>[DEMO] </strong>Recurso de autocompletar no Vim</strong></a></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/ATclZNHrZU8b2kesTWFlGAcXVlDp2A6KCklC.jpeg" class="kg-image" alt="ATclZNHrZU8b2kesTWFlGAcXVlDp2A6KCklC" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/ATclZNHrZU8b2kesTWFlGAcXVlDp2A6KCklC.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/ATclZNHrZU8b2kesTWFlGAcXVlDp2A6KCklC.jpeg 800w" sizes="(min-width: 720px) 720px" width="800" height="451" loading="lazy"><figcaption>Preenchimento automático do Vim ajudando com funções OpenSSL</figcaption></figure><p>Deixe-me lembrar novamente: sem a necessidade de <em>plug-ins</em>, ok?</p><p>OBSERVAÇÃO: os arquivos de cabeçalho podem estar localizados em outros locais no Mac e o Vim pode não ser capaz de encontrá-los. Eu uso um Mac para fazer login em uma máquina Linux. Então, se você estiver usando um Mac, me desculpe por isso.</p><h4 id="eu-entendo-que-o-vim-apenas-um-editor-de-texto-mas-se-voc-quer-que-eu-trabalhe-sem-perder-o-foco-e-sem-sair-do-vim-o-tempo-todo-quais-op-es-eu-tenho-se-n-o-consigo-lembrar-todos-os-nomes-de-arquivo">Eu entendo que o Vim é apenas um editor de texto, mas se você quer que eu trabalhe sem perder o foco e sem sair do Vim o tempo todo, quais opções eu tenho se não consigo lembrar todos os nomes de arquivo?</h4><p>Simples, use o explorador de arquivos fornecido pelo Vim! Sim, o Vim oferece um explorador de arquivos simples (<em>sem nenhum plug-in</em>). Basta digitar: <code>Explore</code> em qualquer janela do Vim e você verá um explorador de arquivos fácil de navegar, que pode ser percorrido usando as setas para cima ⬆ e para baixo ⬇. Pressione <code>Enter/Return</code> para abrir um arquivo/diretório. Use: <code>q</code> para sair do explorador e do Vim. Se você não deseja sair do Vim e continuar trabalhando com um arquivo aberto, você tem 3 opções:</p><ol><li>Abra o explorador em uma divisão horizontal (<code>:Sexplore</code>) ou vertical (<code>:Vexplore</code>) e saia do explorador usando <code>:q</code>.</li><li>Abra o explorador em uma nova aba usando <code>:Texplore</code> e saia usando <code>:q</code></li><li>Abra o explorador de arquivos na janela atual e, em seguida, descarregue o <em>buffer </em>atual e o remova da lista de <em>buffers </em>usando <code>:bdel</code> (excluir <em>buffer</em>).</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/GImb6qQyAyyLoE4unQ1gelPBDz8A2gbizZW9.png" class="kg-image" alt="GImb6qQyAyyLoE4unQ1gelPBDz8A2gbizZW9" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/GImb6qQyAyyLoE4unQ1gelPBDz8A2gbizZW9.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/GImb6qQyAyyLoE4unQ1gelPBDz8A2gbizZW9.png 694w" width="694" height="478" loading="lazy"><figcaption><code>:Explore</code> a partir de qualquer janela do Vim mostra o explorador de arquivos</figcaption></figure><blockquote>OBSERVAÇÃO: você também pode usar o comando abreviado <code>:Ex</code> para abrir o explorador de arquivos</blockquote><h4 id="-s-vezes-eu-tenho-que-repetir-as-mesmas-etapas-em-algumas-linhas-para-editar-algo-tenho-certeza-de-que-o-vim-tem-algum-recurso-que-me-permite-fazer-isso-estou-certo">Às vezes, eu tenho que repetir as mesmas etapas em algumas linhas para editar algo. Tenho certeza de que o Vim tem algum recurso que me permite fazer isso. Estou certo?</h4><p>100% certo! Você está falando sobre macros – e o Vim suporta macros. Repetir o último comando executado é simples e pode ser usado para tarefas repetitivas simples. No entanto, se o processamento de texto consistir em várias etapas para obter um resultado, as macros são úteis.</p><p>Considere um exemplo de um arquivo de cabeçalho em C:</p><pre><code class="language-c">void encrypt_text(char *text, int bytes)
void decrypt_text(char *text, int bytes)
void process_text(char *text, int bytes)
void another_important_function(int bytes, double precision)</code></pre><p>Ops! Você se esqueceu de colocar um ponto e vírgula no final de cada linha e também percebeu que todas essas funções retornam um código de erro inteiro em vez de void.</p><p>Coloque o cursor no início da palavra <code>void</code></p><ul><li>Pressione <code>cw</code> no modo normal para excluir a palavra <code>void</code> e digitar <code>int</code>.</li><li>Pressione <code>Esc</code> , vá para o final da linha usando <code>Shift+a</code> para inserir o <code>;</code>.</li><li>Pressione <code>Esc</code> e pressione <code>^</code> para retornar ao início da linha editada.</li></ul><p>O resultado é:</p><pre><code class="language-c">int encrypt_text(char *text, int bytes);
void decrypt_text(char *text, int bytes)
void process_text(char *text, int bytes)
void another_important_function(int bytes, double precision)</code></pre><p>Você pode gravar essa sequência de etapas e reproduzi-la em todas as 4 linhas.</p><p>Tudo que você precisa fazer é, antes de iniciar a sequência, iniciar a gravação da macro em qualquer letra (vamos dizer <code>a</code>) pressionando <code>qa</code> no modo normal. Agora, suas etapas estarão sendo gravadas em <code>a</code> . Quando terminar todas as etapas, basta pressionar <code>q</code> no modo normal. Isso encerrará a gravação. Para reproduzir essas etapas, basta manter o cursor no mesmo lugar em que foi colocado durante a macro. Pressione <code>@a</code> e pronto! O Vim repetirá as mesmas etapas para você nessa linha! Para repeti-lo em várias linhas, você também pode usar <code>@@</code> após usar o comando <code>@a</code> uma vez.</p><h4 id="eu-sei-que-o-vim-est-longe-de-ser-um-ambiente-de-desenvolvimento-integrado-ide-e-posso-ter-algumas-esperan-as-pouco-realistas-mas-s-uma-pergunta-r-pida-poss-vel-editar-arquivos-remotamente-com-o-vim">Eu sei que o Vim está longe de ser um ambiente de desenvolvimento integrado (IDE) e posso ter algumas esperanças pouco realistas, mas só uma pergunta rápida: é possível editar arquivos remotamente com o Vim?</h4><p>Se você considerar os recursos disponíveis:<br>[1] Vim;<br>[2] openssh-client (vem instalado na maioria das distribuições Linux).</p><p>Você está com sorte, meu amigo! Sim, o Vim suporta a edição remota de arquivos. O Vim utiliza a conexão segura estabelecida pelo scp (cópia segura), fornecida pelo openssh-client. Há momentos em que você está trabalhando com arquivos em várias máquinas remotas e é uma perda de tempo fazer login em uma máquina apenas para editar um único arquivo! Você pode ficar tranquilo na sua máquina atual, desde que saiba as credenciais e o caminho da máquina remota.</p><pre><code class="language-bash">vim scp://usuarioremoto@IP_ou_nomedohost_remoto/caminho/relativo/do/arquivo</code></pre><p>Por exemplo: Eu preciso editar um arquivo em 10.0.18.12 armazenado em <code>/home/dev-john/project/src/main.c</code> e tenho as credenciais de login para <code>dev-john</code>, Posso acessar o <code>main.c</code> usando:</p><pre><code>$ vim scp://dev-john@10.0.18.12/project/src/main.c</code></pre><p>Posso usar o caminho relativo porque posso começar a procurar o arquivo a partir do diretório home de <code>dev-john</code>.</p><p>DICA: se você acessa uma máquina remota com frequência, pode criar um arquivo de configuração ssh para criar um atalho para a conexão. Crie um arquivo <code>~/.ssh/config</code> com:</p><pre><code class="language-bash">Host remote-dev-machine
    Hostname 10.0.18.12
    User dev-john
    IdentityFile ~/.ssh/id_rsa</code></pre><p>Agora, você pode acessar seu arquivo usando:</p><pre><code class="language-bash">$ vim scp://remote-dev-machine/project/src/main.c</code></pre><p>Se for confuso lembrar do caminho relativo e não for intuitivo, você também pode especificá-lo de modo alternativo:</p><pre><code class="language-bash">$ vim scp://maquina_dev_remota/~dev-john/project/src/main.c</code></pre><h4 id="incr-vel-j-estou-animado-com-as-capacidades-prontas-para-uso-do-vim-parece-que-voc-tem-uma-solu-o-para-muitos-problemas-comuns-de-edi-o-vamos-ver-eu-tenho-um-arquivo-com-mais-de-2-mil-linhas-e-as-fun-es-de-meu-interesse-est-o-nas-linhas-9-768-e-1898-eu-sei-que-posso-pular-para-uma-linha-usando-o-n-mero-da-linha-mas-n-o-sou-bom-em-lembrar-esses-n-meros-voc-tem-algo-para-mim">Incrível! Já estou animado com as capacidades prontas para uso do Vim. Parece que você tem uma solução para muitos problemas comuns de edição. Vamos ver. Eu tenho um arquivo com mais de 2 mil linhas e as funções de meu interesse estão nas linhas 9, 768 e 1898. Eu sei que posso pular para uma linha usando o número da linha, mas não sou bom em lembrar esses números. Você tem algo para mim?</h4><p>Claro que sim! O que você está procurando é uma solução de marcação local no Vim usando letras. Tudo que você precisa fazer é:</p><ul><li>Coloque o cursor em qualquer linha em qualquer posição.</li><li>Pressione <code>Esc</code> para garantir que esteja no modo normal.</li><li>Pressione <code>m{lowercaseletter}</code>, onde <code>{lowercaseletter}</code> é qualquer letra minúscula de <code>a-z</code>.</li><li>Você acabou de criar uma marcação local para navegar em seu arquivo.</li></ul><p>Para visualizar todas as suas marcações: pressione <code>Esc</code> e para entrar no modo de comando, digite <code>:marks</code> e pressione <code>Enter/Return</code>. Você verá uma lista de suas marcações. Para visitar qualquer marcação a qualquer momento, basta pressionar <code>Esc</code> e digitar <code>`{lowercaseletter}</code>. Pronto! Você será levado exatamente para a mesma localização onde marcou com o cursor. Exemplo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/IqGeVQdTLQSrCFzKVqa9-eVswnzGT2SkDy8H.png" class="kg-image" alt="IqGeVQdTLQSrCFzKVqa9-eVswnzGT2SkDy8H" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/IqGeVQdTLQSrCFzKVqa9-eVswnzGT2SkDy8H.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/IqGeVQdTLQSrCFzKVqa9-eVswnzGT2SkDy8H.png 678w" width="678" height="212" loading="lazy"><figcaption>Marcações no Vim</figcaption></figure><p>Eu criei uma marcação local para a linha 21, coluna 18 usando <code>a</code>. Se eu estiver editando algo na linha 1783, basta pressionar <code>Esc</code> e digitar <code>`a</code> :</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/rpK-WeLKT0ESw1RIL80EEgrfBQwy1wWwKnIj.png" class="kg-image" alt="rpK-WeLKT0ESw1RIL80EEgrfBQwy1wWwKnIj" width="572" height="270" loading="lazy"></figure><p>Para resolver seu problema, tudo que você precisa fazer é criar 3 marcações locais e pular rapidamente para elas ao verificar <code>:marks</code>.</p><p>Problema resolvido!</p><p>Que tal se eu dissesse que você também pode criar marcadores globais? Sim, é possível criar marcadores globais também! Eles são equivalentes aos atalhos de janelas ou GUI (links simbólicos/<em>hardlinks</em> no Linux), exceto pelo fato de que você não precisa criar um link real. É isso mesmo! Você pode literalmente pular de editar um arquivo em /<code>dir1</code> pra outro arquivo e linha em <code>/project/src/</code> no seu Vim sem sair!</p><p>Não se preocupe, não é algo novo e difícil de lembrar. Tudo que você precisa fazer é: usar uma letra maiúscula em vez de uma letra minúscula para criar um marcador global. Isso é tudo! Sério mesmo! Você navega até o marcador global usando o mesmo processo. Por exemplo: se você criou um marcador usando <code>mP</code> , tudo que você precisa fazer é pressionar <code>Esc</code> e digitar <code>`P</code> e pronto! Você pula para o seu marcador global (o Vim se lembra do caminho, o que faz com que você não precise digitar nada sobre o caminho).</p><p>Você pode acessar os marcadores globais da mesma maneira que os locais: <code>:marks</code></p><pre><code class="language-bash">:marks
mark line  col file/text
 P     53    4 ~/project/src/large-file.c
 A     11    0 ~/project/README.md</code></pre><blockquote>OBSERVAÇÃO: se você não estiver interessado na posição do cursor e quiser estar no início da linha marcada, use <code>'P</code> em vez de <code>`P</code> (use uma aspa simples em vez de crase para se posicionar no início da linha).</blockquote><h4 id="ouvi-dizer-que-o-vim-suporta-divis-o-de-janelas-juntamente-com-abas-eu-entendo-que-as-abas-s-o-timas-e-permitem-trabalhar-com-v-rios-arquivos-abertos-ao-mesmo-tempo-o-que-essa-divis-o-por-que-eu-gostaria-disso">Ouvi dizer que o Vim suporta divisão de janelas juntamente com abas! Eu entendo que as abas são ótimas e permitem trabalhar com vários arquivos abertos ao mesmo tempo. O que é essa divisão? Por que eu gostaria disso?</h4><p>Cenários:</p><ul><li>Você pode querer editar um arquivo enquanto olha para outro arquivo simultaneamente (talvez esteja definindo uma função em C olhando para sua declaração em um arquivo de cabeçalho).</li><li>Você pode querer editar uma parte de um arquivo enquanto olha para a parte superior/inferior do mesmo arquivo simultaneamente.</li><li>Seu trabalho pode exigir que você edite um arquivo enquanto olha para diferentes partes de diferentes arquivos simultaneamente.</li></ul><p>O Vim suporta a divisão da tela tanto horizontalmente quanto verticalmente. O melhor disso é que você pode até navegar pelo sistema de arquivos para abrir um arquivo quando dividir sua tela.</p><p>Aqui estão as opções disponíveis:</p><pre><code>:split nomedoarquivo  - divide a janela na horizontal e carrega o arquivo
:vsplit nomedoarquivo - divide a janela na vertical e abre o arquivo
ctrl-w seta_para_cima - move o cursor para cima em uma janela
ctrl-w ctrl-w    - move o cursor para outra janela (ciclo)
ctrl-w _         - maximiza a janela atual na vertical
ctrl-w |         - maximiza a janela atual na horizontal
ctrl-w =         - torna todas as janelas do mesmo tamanho
:sview file      - o mesmo que split, mas somente leitura
:close           - fecha a janela atual</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/wj-bKJhdZ0ZJpjs3ryZGa9vGat9nkn6PoZB6.png" class="kg-image" alt="wj-bKJhdZ0ZJpjs3ryZGa9vGat9nkn6PoZB6" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/wj-bKJhdZ0ZJpjs3ryZGa9vGat9nkn6PoZB6.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/wj-bKJhdZ0ZJpjs3ryZGa9vGat9nkn6PoZB6.png 800w" sizes="(min-width: 720px) 720px" width="800" height="425" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/4fwUNCFGZHMpC9NgLN34JGK1JFMOSpSwRANi.png" class="kg-image" alt="4fwUNCFGZHMpC9NgLN34JGK1JFMOSpSwRANi" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/4fwUNCFGZHMpC9NgLN34JGK1JFMOSpSwRANi.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/4fwUNCFGZHMpC9NgLN34JGK1JFMOSpSwRANi.png 800w" sizes="(min-width: 720px) 720px" width="800" height="890" loading="lazy"><figcaption>Janela normal (canto superior esquerdo), :split &lt;arquivo&gt; (canto superior direito), :vsplit &lt;arquivo&gt; (inferior)</figcaption></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/E1ewlYcq9bHjEW1sXhSpt1LaKlqNPH81jWw4.png" class="kg-image" alt="E1ewlYcq9bHjEW1sXhSpt1LaKlqNPH81jWw4" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/E1ewlYcq9bHjEW1sXhSpt1LaKlqNPH81jWw4.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/E1ewlYcq9bHjEW1sXhSpt1LaKlqNPH81jWw4.png 800w" sizes="(min-width: 720px) 720px" width="800" height="187" loading="lazy"></figure><p>Maximizando uma janela para trabalhar:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/6ojjo1cyuKPSotf19qxtRcksAKoamYpx3mgz.png" class="kg-image" alt="6ojjo1cyuKPSotf19qxtRcksAKoamYpx3mgz" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/6ojjo1cyuKPSotf19qxtRcksAKoamYpx3mgz.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/6ojjo1cyuKPSotf19qxtRcksAKoamYpx3mgz.png 800w" sizes="(min-width: 720px) 720px" width="800" height="239" loading="lazy"><figcaption>O painel precisa ser maximizado verticalmente e horizontalmente para ocupar toda a janela</figcaption></figure><p>Redimensionando:</p><pre><code>CTRL-W [N] -	Diminui a altura da janela atual em N (padrão 1)
CTRL-W [N] +	Aumenta a altura da janela atual em N (padrão 1)
CTRL-W [N] &lt;	Diminui a largura da janela atual em N (padrão 1)
CTRL-W [N} &gt;	Aumenta a largura da janela atual em N (padrão 1)</code></pre><p><strong>Existe alguma maneira de usar o explorador de arquivos enquanto divido as janelas? Não consigo me lembrar e digitar sempre os nomes dos arquivos!</strong></p><p>Claro, tudo que você precisa fazer é digitar: <code>:Sexplore</code> para o explorador de arquivos horizontal e <code>:Vexplore</code> para o explorador de arquivos vertical. Você também pode usar: <code>:Vexplore!</code> para abrir o explorador de arquivos no lado direito (em vez do padrão esquerdo).</p><p>Novamente, tudo isso funciona <em>sem a necessidade de plug-ins adicionais.</em></p><h4 id="estou-no-meio-da-edi-o-de-um-c-digo-e-preciso-executar-rapidamente-um-comando-de-shell-devo-salvar-meu-trabalho-sair-do-vim-e-executar-meus-comandos-aposto-que-h-uma-maneira-melhor-com-o-vim-">Estou no meio da edição de um código e preciso executar rapidamente um comando de shell. Devo salvar meu trabalho, sair do Vim e executar meus comandos? Aposto que há uma maneira melhor com o Vim.</h4><p>O Vim não quer que você saia dele e quer que você continue focado no seu trabalho. Por isso, há a opção de executar comandos de shell de dentro do Vim. Não se preocupe, todo o seu trabalho não salvo não será descartado, você apenas executa o seu comando e pronto! Você está de volta ao seu arquivo salvo/não salvo com segurança!</p><p>Digamos que você esteja no meio de uma sessão de codificação e precisa dar uma olhada na página do <code>man</code> das operações de arquivo porque esqueceu a assinatura! Você não precisa salvar seu trabalho, sair do Vim e depois verificar as páginas do <code>man</code>, nem precisa abrir outra aba apenas para a página do <code>man</code>. Você pode executar o comando diretamente dentro do editor Vim.</p><p><strong><strong>[DEMO]</strong> </strong><a href="https://asciinema.org/a/vZgdxBb0slZG3cB9ZXqNFpgpi"><strong>Comandos Unix do Vim</strong></a></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/AdheBhI32Ti3bOsjH-FUPuqugongB41XMJ-k.png" class="kg-image" alt="AdheBhI32Ti3bOsjH-FUPuqugongB41XMJ-k" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/AdheBhI32Ti3bOsjH-FUPuqugongB41XMJ-k.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/AdheBhI32Ti3bOsjH-FUPuqugongB41XMJ-k.png 800w" sizes="(min-width: 720px) 720px" width="800" height="576" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/PbN-40zw3dLd-ADaoSlY9j4r1CPveMmCdy5Q.png" class="kg-image" alt="PbN-40zw3dLd-ADaoSlY9j4r1CPveMmCdy5Q" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/PbN-40zw3dLd-ADaoSlY9j4r1CPveMmCdy5Q.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/PbN-40zw3dLd-ADaoSlY9j4r1CPveMmCdy5Q.png 800w" sizes="(min-width: 720px) 720px" width="800" height="590" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/QR57vMytkwfcB3eNbz2UDIRAS6hxw3T7j5nJ.png" class="kg-image" alt="QR57vMytkwfcB3eNbz2UDIRAS6hxw3T7j5nJ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/QR57vMytkwfcB3eNbz2UDIRAS6hxw3T7j5nJ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/QR57vMytkwfcB3eNbz2UDIRAS6hxw3T7j5nJ.png 772w" sizes="(min-width: 720px) 720px" width="772" height="548" loading="lazy"><figcaption>Executando comandos de shel no Vim e retornando ao editor</figcaption></figure><p>Adivinha! Prepare-se para se surpreender. O Vim também suporta o comando <code>make</code> a partir do seu arquivo! Tudo que você precisa fazer é navegar até um diretório com um <code>Makefile</code>. Abra qualquer arquivo (pode ser seu código-fonte) e faça todas as alterações e salve. Espere, não há necessidade de sair para ver o resultado da compilação. Você pode acionar a compilação do <code>make</code> diretamente do Vim:</p><p><strong><strong>[DEMO]</strong> </strong><a href="https://asciinema.org/a/148687"><strong>Acionar a compilação do make a partir do Vim</strong></a></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/X5Fc1RFaV6cmQNbfBZx-mk0SORNL6vt7ZhKj.png" class="kg-image" alt="X5Fc1RFaV6cmQNbfBZx-mk0SORNL6vt7ZhKj" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/X5Fc1RFaV6cmQNbfBZx-mk0SORNL6vt7ZhKj.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/X5Fc1RFaV6cmQNbfBZx-mk0SORNL6vt7ZhKj.png 800w" sizes="(min-width: 720px) 720px" width="800" height="204" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/RtDOq--CU522ri03TzCNsfXXsvZ5k8bnU0QY.png" class="kg-image" alt="RtDOq--CU522ri03TzCNsfXXsvZ5k8bnU0QY" width="592" height="134" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/KbeSb0lbsalK-wXV7JLnLuf1kiRLYP-qQQt7.png" class="kg-image" alt="KbeSb0lbsalK-wXV7JLnLuf1kiRLYP-qQQt7" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/KbeSb0lbsalK-wXV7JLnLuf1kiRLYP-qQQt7.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/KbeSb0lbsalK-wXV7JLnLuf1kiRLYP-qQQt7.png 650w" width="650" height="156" loading="lazy"><figcaption>Acionando make builds a partir do Vim</figcaption></figure><p>Do mesmo modo, você pode compilar outros alvos no seu Makefile!</p><p>Exemplo – Limpeza do diretório de compilação:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/et4iHMv7ucgX9wwpKF9q3tv6EItczICVobsz.png" class="kg-image" alt="et4iHMv7ucgX9wwpKF9q3tv6EItczICVobsz" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/et4iHMv7ucgX9wwpKF9q3tv6EItczICVobsz.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/et4iHMv7ucgX9wwpKF9q3tv6EItczICVobsz.png 800w" sizes="(min-width: 720px) 720px" width="800" height="201" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/ERlbwxBamwe-f6OIU3i5pypZdBCKTJvlxNt1.png" class="kg-image" alt="ERlbwxBamwe-f6OIU3i5pypZdBCKTJvlxNt1" width="568" height="98" loading="lazy"></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/6hcFG2Kp9MZ0YhswQDNdIBfduX9NICQNpvx3.png" class="kg-image" alt="6hcFG2Kp9MZ0YhswQDNdIBfduX9NICQNpvx3" width="592" height="176" loading="lazy"><figcaption>Diretório de limpeza usando o comando make do Vim</figcaption></figure><p>Espero que esses recursos legais ajudem você a usar o Vim de modo mais produtivo.</p><h3 id="refer-ncias-em-ingl-s-">Referências (em inglês):</h3><ul><li><a href="http://www.openvim.com/tutorial.html" rel="noopener">http://www.openvim.com/tutorial.html</a></li><li><a href="https://linuxconfig.org/vim-tutorial" rel="noopener">https://linuxconfig.org/vim-tutorial</a></li><li><a href="ftp://ftp.vim.org/pub/vim/doc/book/vimbook-OPL.pdf" rel="noopener">ftp://ftp.vim.org/pub/vim/doc/book/vimbook-OPL.pdf</a></li><li><a href="http://vim.wikia.com/wiki/Tutorial" rel="noopener">http://vim.wikia.com/wiki/Tutorial</a></li><li><a href="http://www.viemu.com/a-why-vi-vim.html" rel="noopener">http://www.viemu.com/a-why-vi-vim.html</a></li><li><a href="http://robertames.com/files/vim-editing.html" rel="noopener">http://robertames.com/files/vim-editing.html</a></li><li><a href="https://www.youtube.com/watch?v=wlR5gYd6um0" rel="noopener">https://www.youtube.com/watch?v=wlR5gYd6um0</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como criar uma SPA com Vue.js e C# usando .NET Core ]]>
                </title>
                <description>
                    <![CDATA[ Digamos que você é um desenvolvedor de front-end ou que tenha trabalhado mais com o front-end recentemente. Às vezes, você acaba usando algumas tecnologias de back-end, mas tende a ficar na sua zona de conforto, provavelmente no universo do JavaScript. É possível que você tenha criado uma pequena API com ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-criar-uma-spa-com-vue-js-e-c-sharp-usando-net-core/</link>
                <guid isPermaLink="false">63bae2e2ad276e05ed7570a2</guid>
                
                    <category>
                        <![CDATA[ Vue.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Wed, 29 Mar 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/dashboard-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-build-an-spa-with-vuejs-and-c-using-net-core/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build an SPA with Vue.js and C# Using .NET Core</a>
      </p><p>Digamos que você é um desenvolvedor de <em>front-end</em> ou que tenha trabalhado mais com o <em>front-end</em> recentemente.</p><p>Às vezes, você acaba usando algumas tecnologias de <em>back-end</em>, mas tende a ficar na sua zona de conforto, provavelmente no universo do JavaScript. É possível que você tenha criado uma pequena API com Python em algum momento também.</p><p>Você, no entanto, nunca tocou na <em>stack</em> de tecnologias moderna da família .NET.</p><p>Nesse sentido, este tutorial vai guiá-lo, passo a passo, na criação de uma aplicação moderna de <em>Single-Page Application</em> (SPA), que usará o Vue.js para o <em>front-end</em> e o .NET Core (C#) para o <em>back-end</em>.</p><p>Além disso, veremos como escrever alguns testes, tanto de unidade quanto de integração, a fim de cobrir a funcionalidade do <em>front-end</em> e do <em>back-end</em> (ao menos, parcialmente).</p><p>Se você quiser pular a leitura, aqui está o <a href="https://github.com/mihailgaberov/pizza-app/blob/master/">repositório do GitHub</a> com um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/README.md">README</a> detalhado.</p><h2 id="o-que-vamos-criar"><strong>O que vamos criar?</strong></h2><p>Vamos criar uma aplicação da web na qual os usuários podem fazer login/se cadastrar e nos dizer o quanto eles gostam de pizza ao pressionar um botão dizendo "I love it" ('Eu adoro pizza').</p><p>Não há restrições de quantas vezes cada usuário pode nos mostrar o quanto gosta de pizza. O único requisito é que apenas usuários logados podem votar.</p><p>Na página inicial, junto com os botões de login/cadastro, colocaremos um pequeno gráfico de barras, exibindo os X usuários com a maior apreciação (no eixo X) e o número de votos (no eixo Y)."</p><h2 id="instala-o"><strong>Instalação</strong></h2><p>Vamos começar pelo <em>front-end</em>. Faz mais sentido construir primeiro as partes visíveis da nossa aplicação. Assim, construiremos o nosso <em>front-end</em> com uma das bibliotecas de <em>front-end</em> mais famosas do mercado: o Vue.js.</p><h3 id="como-configurar-o-front-end"><strong>Como configurar o <em>front-end</em></strong></h3><p>Para instalar e configurar inicialmente o nosso <em>front-end</em> com Vue.js, vamos usar a CLI do Vue. Trata-se de uma ferramenta de linha de comando padrão para o desenvolvimento de aplicativos em Vue.js.</p><blockquote>Nota da tradução: CLI é a abreviação para <em>Command Line Interface</em>, ou interface da linha de comando, em português. </blockquote><p>Para instalá-la, use o comando abaixo. Observe que todos os comandos neste tutorial usam o NPM, que você precisa ter instalado na sua máquina para acompanhar.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">npm install -g @vue/cli</code></pre><figcaption>Instalando a CLI do Vue</figcaption></figure><p>Depois de instalar a CLI do Vue com sucesso, poderemos utilizá-la para instalar e configurar o Vue.js. Vamos fazer isso por meio deste processo:</p><p>1º Passo: crie um diretório de projeto vazio e abra-o com os seguintes abaixo.</p><figure class="kg-card kg-code-card"><pre><code>mkdir pizza-app
cd pizza-app</code></pre><figcaption>Criando um novo diretório de projeto vazio</figcaption></figure><p>Passo 2: dentro do diretório raiz do projeto, execute o comando a seguir.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">vue create frontend</code></pre><figcaption>Criando a parte de <em>front-end</em> do app</figcaption></figure><p>Em seguida, nas opções fornecidas, selecione o seguinte:</p><ul><li>Seleção manual de recursos "<em>Manually select features</em>".</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-52.png" class="kg-image" alt="image-52" width="407" height="201" loading="lazy"><figcaption>Instalação do Vue.js – seleção manual dos recursos</figcaption></figure><ul><li>Babel</li><li>Router</li><li>Pré-processadores do CSS (<em>CSS-Preprocessors</em>, como o SASS)</li></ul><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-53.png" class="kg-image" alt="image-53" width="401" height="331" loading="lazy"><figcaption>Instalação do Vue.js – seleção dos recursos</figcaption></figure><p>Em seguida, selecione a versão 2.x na próxima tela:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-54.png" class="kg-image" alt="image-54" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-54.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-54.png 963w" width="963" height="223" loading="lazy"><figcaption>Selecionando a versão 2.x</figcaption></figure><blockquote>Nota de tradução: o Vue.js, no momento da tradução, está em sua versão 3 e o suporte à versão 2 terminará ao final deste ano. Neste momento, no entanto, ainda é possível realizar as configurações de acordo com este tutorial seguindo as instruções.</blockquote><p>Em seguida, selecione &nbsp;'<em>Use history mode for router?</em>' e '<em>Sass/SCSS (with node-sass)</em>', assim:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-57.png" class="kg-image" alt="image-57" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-57.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-57.png 963w" width="963" height="277" loading="lazy"></figure><ul><li>Linter / Formatter</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-58.png" class="kg-image" alt="image-58" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-58.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-58.png 957w" width="957" height="279" loading="lazy"></figure><ul><li>Teste de unidade com Jest</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-59.png" class="kg-image" alt="image-59" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-59.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-59.png 965w" width="965" height="297" loading="lazy"></figure><ul><li>Teste de ponta a ponta (E2E) com Cypress</li></ul><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-60.png" class="kg-image" alt="image-60" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-60.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-60.png 957w" width="957" height="315" loading="lazy"></figure><p>Depois desse último passo, finalize o processo de instalação com as opções padrão.</p><p>Agora estamos prontos para executar a aplicação usando os seguintes comandos a partir da pasta raiz do projeto:</p><pre><code class="language-bash">cd frontend
npm run serve</code></pre><p>Depois que o app estiver em execução, você poderá vê-lo no seu navegador em http://localhost:8080:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/welcome-to-your-vuejs-app.png" class="kg-image" alt="welcome-to-your-vuejs-app" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/welcome-to-your-vuejs-app.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/welcome-to-your-vuejs-app.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/welcome-to-your-vuejs-app.png 1519w" sizes="(min-width: 1200px) 1200px" width="1519" height="866" loading="lazy"><figcaption>Tela de instalação padrão do Vue.js</figcaption></figure><p>Antes de prosseguir com a criação dos componentes reais que a nossa aplicação de <em>front-end</em> terá, vamos instalar a parte do <em>back-end</em> da nossa aplicação por meio da CLI do .NET Core.</p><h3 id="como-configurar-o-back-end">Como configurar o <em>back-end</em></h3><p>Como mencionado acima, usaremos outra ferramenta de linha de comando, a CLI do .NET Core, que possibilita a criação e configuração de apps .NET.</p><p>Se você ainda não tem, pode usar este<a href="https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.401-windows-x64-installer"> link</a> para baixá-la e, em seguida, instalá-la. </p><p>Depois de ter a CLI do .NET Core instalada, vá para o diretório raiz do seu projeto e execute o seguinte comando para criar o <em>back-end </em>da nossa aplicação. Criaremos uma pasta chamada <code>backend</code> e instalaremos um app .NET para a web dentro dela:</p><pre><code>dotnet new web -o backend</code></pre><h3 id="gitignore-io"><strong><strong>gitignore.io</strong></strong></h3><p>Antes de continuar com a instalação dos próximos pacotes que precisaremos, vamos organizar nosso arquivo <em>.gitignore</em>.</p><p>Este é um arquivo de configuração que informa ao Git o que ignorar ao fazer o <em>commit</em> das alterações em repositórios baseados em Git (os do GitHub).</p><p>Como queremos ter um arquivo .gitignore, ele incluirá regras para dois tipos de aplicações:</p><ul><li>uma baseada em Node.js, que é o nosso <em>front-end</em> do Vue.js; e</li><li>uma para o .NET (C#) que é o nosso <em>back-end</em>.</li></ul><p>Para isso, usaremos uma ferramenta chamada gitignore.io. Essa ferramenta vai gerar esses arquivos para nós. A vantagem de usar essa ferramenta é que ela nos permite digitar quais são nossas linguagens de programação/plataformas e gera o arquivo .gitignore para nós.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-61.png" class="kg-image" alt="image-61" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-61.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-61.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-61.png 1065w" width="1065" height="552" loading="lazy"><figcaption>Usando o gitignore.io para gerar um arquivo .gitignore</figcaption></figure><p>Além disso, no topo do arquivo gerado, ele salva links para criação ou edição posterior, como mostrado abaixo:</p><pre><code># Created by https://www.toptal.com/developers/gitignore/api/webstorm,vue,vuejs,visualstudio
# Edit at https://www.toptal.com/developers/gitignore?templates=webstorm,vue,vuejs,visualstudio</code></pre><p>Agora, estamos prontos para instalar o restante dos pacotes que precisamos.</p><p>Primeiro, vamos instalar um pacote chamado SpaServices, que nos permitirá ter a aplicação em execução usando apenas um URL e apontando para a aplicação .NET. De sua parte, ele encaminhará solicitações para a nossa aplicação de <em>front-end</em>.</p><p>Para instalá-lo, abra o seu terminal, vá para a pasta <code>backend</code> do seu projeto e digite o seguinte comando:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.SpaServices.Extensions --version 3.1.8
</code></pre><p>Depois disso, precisamos configurar a nossa aplicação de <em>back-end</em> com o pacote SpaServices para ter o resultado desejado.</p><p>Todas as solicitações serão encaminhadas para a nossa aplicação de <em>back-end</em> .NET e, se a solicitação for destinada ao <em>front-end</em>, ela será encaminhada.</p><p>Para fazer isso, abra o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/Startup.cs">Startup.cs</a> e atualize seu conteúdo para ficar assim:</p><pre><code class="language-c">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace backend
{
    public class Startup
    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        // Este método é chamado pelo tempo de execução. Use-o para adicionar serviços ao contêiner.
        // Para obter mais informações sobre como configurar sua aplicação, acesse https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            string connectionString = Configuration.GetConnectionString("DefaultConnection");
            services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt; options.UseSqlite(connectionString));
            services.AddSpaStaticFiles(configuration: options =&gt; { options.RootPath = "wwwroot"; });
            services.AddControllers();
            services.AddCors(options =&gt;
            {
                options.AddPolicy("VueCorsPolicy", builder =&gt;
                {
                    builder
                    .AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials()
                    .WithOrigins("https://localhost:5001");
                });
            });
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  .AddJwtBearer(options =&gt;
                {
                    options.Authority = Configuration["Okta:Authority"];
                    options.Audience = "api://default";
                });
            services.AddMvc(option =&gt; option.EnableEndpointRouting = false);
        }

        // Este método é chamado pelo tempo de execução. Use-o para configurar o pipeline da solicitação HTTP.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dbContext)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("VueCorsPolicy");

            dbContext.Database.EnsureCreated();
            app.UseAuthentication();
            app.UseMvc();
            app.UseRouting();
            app.UseEndpoints(endpoints =&gt; { endpoints.MapControllers(); });
            app.UseSpaStaticFiles();
            app.UseSpa(configuration: builder =&gt;
            {
                if (env.IsDevelopment())
                {
                    builder.UseProxyToSpaDevelopmentServer("http://localhost:8080");
                }
            });
        }
    }
}</code></pre><p>Essa é a versão final do arquivo Startup.cs e, por isso, você provavelmente deve ter notado algumas outras coisas nela. Voltaremos nisso um pouco mais tarde neste tutorial.</p><p>Neste ponto, você deve ser capaz de executar a sua aplicação <em>back-end</em>. Se quiser fazer isso, execute os seguintes comandos a partir da pasta raiz do seu projeto:</p><pre><code>cd backend
dotnet run</code></pre><h2 id="como-configurar-a-autentica-o">Como configurar a autenticação</h2><p>Como você deve se lembrar da descrição no início, nossa aplicação deve ter uma opção de registro/login.</p><p>Para atender a esse requisito, usaremos um serviço terceirizado chamado Okta. Instalaremos os pacotes necessários para usar o Okta SDK no <em>front-end</em> e no <em>back-end</em> do nosso app.</p><p>Antes disso, porém, você precisa criar uma conta no site deles e obter acesso ao painel de administração. A partir daí, você pode criar uma aplicação. Aqui vemos como fica na minha aplicação:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-62.png" class="kg-image" alt="image-62" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-62.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-62.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-62.png 1511w" sizes="(min-width: 1200px) 1200px" width="1511" height="610" loading="lazy"></figure><p>Agora, vamos começar com o pacote que precisamos para nosso <em>front-end</em>. Na pasta raiz, execute os seguintes comandos:</p><pre><code class="language-bash">cd frontend
npm i @okta/okta-vue</code></pre><p>Após esta etapa, estamos prontos para alterar nossa aplicação do Vue.js para que use as vantagens do Okta SDK.</p><p>Também instalaremos outro pacote, chamado BootstrapVue, que fornece um conjunto de componentes do Vue.js bonitos e prontos para uso. Isso nos ajudará a economizar tempo de desenvolvimento e também nos dará um <em>front-end</em> de boa aparência.</p><p>Para instalá-lo, execute o seguinte na sua pasta <code>frontend</code>:</p><pre><code class="language-bash">npm i vue bootstrap-vue bootstrap</code></pre><h3 id="como-configurar-o-roteador">Como configurar o roteador</h3><p>Chegou a hora de escrever um pouco de código. Precisamos editar nosso <a href="https://router.vuejs.org/">roteador</a> para aplicar o que vem dos serviços de autenticação do Okta.</p><p>Você pode ver o arquivo completo no meu repositório do GitHub, mas aqui está a parte essencial que você precisa configurar com seus próprios dados (que você obteve quando se registrou no site do desenvolvedor do Okta):</p><pre><code class="language-javascript">Vue.use(Auth, {
  issuer: 'https://dev-914982.okta.com/oauth2/default',
  client_id: '0oatq53f87ByM08MQ4x6',
  redirect_uri: 'https://localhost:5001/implicit/callback',
  scope: 'openid profile email'
})

....

router.beforeEach(Vue.prototype.$auth.authRedirectGuard())</code></pre><h3 id="tela-inicial">Tela inicial</h3><p>Depois de classificar nosso roteador, podemos finalmente fazer algumas alterações na tela inicial da nossa aplicação, que ficará visível para nossos usuários.</p><p>Abra o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/App.vue">App.vue</a> em seu IDE e altere seu conteúdo da seguinte maneira:</p><pre><code class="language-javascript">&lt;template&gt;
  &lt;div id="app"&gt;
    &lt;header&gt;
      &lt;b-navbar toggleable="md" type="light" variant="light"&gt;
        &lt;b-navbar-toggle target="nav-collapse"&gt;&lt;/b-navbar-toggle&gt;
        &lt;b-navbar-brand to="/"&gt;Love Pizza&lt;/b-navbar-brand&gt;
        &lt;b-collapse is-nav id="nav-collapse"&gt;
          &lt;b-navbar-nav&gt;
            &lt;b-nav-item href="#" @click.prevent="login" v-if="!user"&gt;Login&lt;/b-nav-item&gt;
            &lt;b-nav-item href="#" @click.prevent="logout" v-else&gt;Logout&lt;/b-nav-item&gt;
          &lt;/b-navbar-nav&gt;
        &lt;/b-collapse&gt;
      &lt;/b-navbar&gt;
    &lt;/header&gt;
    &lt;main&gt;
      &lt;div&gt;
        Love pizza button and clicks counter here
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  name: 'app',
  data() {
    return {
      user: null
    }
  },
  async created() {
    await this.refreshUser()
  },
  watch: {
    '$route': 'onRouteChange'
  },
  methods: {
    login() {
      this.$auth.loginRedirect()
    },
    async onRouteChange() {
      await this.refreshUser()
    },
    async refreshUser() {
      this.user = await this.$auth.getUser()
    },
    async logout() {
      await this.$auth.logout()
      await this.refreshUser()
      this.$router.push('/')
    }
  }
}
&lt;/script&gt;

&lt;style lang="scss"&gt;
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;

  a {
    font-weight: bold;
    color: #2c3e50;

    &amp;.router-link-exact-active {
      color: #42b983;
    }
  }
}
&lt;/style&gt;</code></pre><p>Neste momento, sua aplicação deve ter a seguinte aparência:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-173.png" class="kg-image" alt="image-173" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-173.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-173.png 811w" width="811" height="525" loading="lazy"><figcaption><em>Front-end</em> do app em Vue.js – em desenvolvimento</figcaption></figure><p><strong>Observação</strong>: não se confunda com o texto 'Love pizza button and clicks counter here' (aqui vão o botão de pizza e o contador de cliques). Ao criar as UIs, é uma boa prática deixar esses espaços reservados para componentes que serão desenvolvidos no futuro.</p><p>No nosso caso, é aqui que adicionaremos os componentes responsáveis pelo botão 'I love it' e para o contador posteriormente. Eles mostrarão o número de votos por usuário.</p><figure class="kg-card kg-code-card"><pre><code class="language-javascript">&lt;main&gt;
  &lt;div&gt;
  	Love pizza button and clicks counter here
  &lt;/div&gt;
&lt;/main&gt;</code></pre><figcaption>Espaço reservado para componentes a serem adicionados posteriormente</figcaption></figure><h3 id="autentica-o-no-back-end">Autenticação no <em>back-end</em></h3><p>Até agora, configuramos nosso <em>front-end</em> para que use o serviço de autenticação fornecido pelo Okta. Porém, para ter toda a imagem pronta para uso, precisamos fazer o mesmo no lado do <em>back-end</em>.</p><p>É de onde faremos chamadas HTTP, para nos comunicarmos com o banco de dados. Como você verá mais adiante, algumas dessas chamadas precisarão ser autenticadas para serem bem-sucedidas.</p><p>Vamos começar novamente com a instalação de alguns pacotes que facilitarão nosso trabalho. No seu terminal, vá para o diretório <code>backend</code> e execute o seguinte:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 3.1.8
dotnet add package Microsoft.Extensions.Configuration --version 3.1.7</code></pre><p>Então, precisamos de outro pacote que nos ajude a configurar nosso banco de dados. Usaremos o banco de dados SQLite, que é superfácil de usar, na configuração do .NET Core.</p><p>Ainda na pasta <code>backend</code>, execute:</p><pre><code class="language-bash">dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 2.1.1</code></pre><p>Assim que terminarmos as instalações, certifique-se de que tem o conteúdo completo do arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/Startup.cs">Startup.cs</a> (e se ainda não o fez, recomendo fazer isso agora).</p><h3 id="pizzavotesapiservice"><strong><strong>PizzaVotesApiService</strong></strong></h3><p>OK, pessoal! &nbsp;Configuramos nosso <em>front-end</em> e nosso <em>back-end</em> para oferecer suporte à autenticação. Adicionamos o SQLite como um banco de dados a ser usado para armazenar os votos dos usuários. Por fim, temos uma versão inicial da nossa tela inicial.</p><p>Agora, é hora de implementar um serviço no <em>front-end</em> que nos permitirá consumir a API do nosso <em>back-end</em>.</p><p>Ótimo trabalho até agora!</p><p>Antes de poder fazer chamadas HTTP do <em>front-end</em> para o <em>back-end</em>, precisamos instalar mais um pacote em nossa aplicação do Vue.js. Esse pacote se chama axios e nos dá a capacidade de fazer <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" rel="nofollow">XMLHttpRequests</a> a partir do navegador, que é exatamente o que precisamos.</p><p>Abra seu terminal, vá para a pasta <code>frontend</code> do seu projeto e execute:</p><pre><code>npm i axios</code></pre><p>Em seguida, em seu IDE, vá para a pasta <code>src</code> do <em>front-end </em>do seu app, crie um arquivo .js e adicione o seguinte código dentro dele:</p><pre><code>import Vue from 'vue'
import axios from 'axios'

const client = axios.create({
    baseURL: 'http://localhost:5000/api/pizzavotes',
    json: true
})

export default {
    async execute(method, resource, data) {
        const accessToken = await Vue.prototype.$auth.getAccessToken()
        return client({
            method,
            url: resource,
            data,
            headers: {
                Authorization: `Bearer ${accessToken}`
            }
        }).then(req =&gt; {
            return req.data
        })
    },
    getAll() {
        return this.execute('get', '/')
    },
    getById(id) {
        return this.execute('get', `/${id}`)
    },
    create(data) {
        return this.execute('post', '/', data)
    },
    update(id, data) {
        return this.execute('put', `/${id}`, data)
    },
}</code></pre><p>Eu dei nome ao meu arquivo de <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/PizzaVotesApiService.js">PizzaVotesApiService.js</a>. Pararemos com a integração da API por um tempo e criaremos outro componente que conterá os controles que os usuários usarão para interagir com essa API.</p><h3 id="componente-do-painel">Componente do painel</h3><p>Diga "olá" para o nosso componente <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/Dashboard.vue">Dashboard.vue</a>.</p><p>É aqui que colocaremos o botão 'I love it' ('Eu adoro pizza') e um pequeno contador de votos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-63.png" class="kg-image" alt="image-63" width="207" height="183" loading="lazy"><figcaption>Botão 'I love it' e contador de votos</figcaption></figure><p>Também adicionaremos uma imagem de pizza divertida.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-64.png" class="kg-image" alt="image-64" width="250" height="284" loading="lazy"><figcaption>Imagem da pizza</figcaption></figure><p>Também adicionaremos um belo gráfico de barras, mostrando os X principais eleitores.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-65.png" class="kg-image" alt="image-65" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-65.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-65.png 641w" width="641" height="603" loading="lazy"><figcaption>Gráfico de barras dos principais votantes</figcaption></figure><p>Você pode copiar e colar o conteúdo completo do arquivo do meu repositório para que possamos continuar integrando tudo.</p><h3 id="integra-o-da-api">Integração da API</h3><p>Vou usar um pequeno diagrama para representar o fluxo de dados. Como dizem, "uma imagem vale mais que mil palavras":</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/data-flow.png" class="kg-image" alt="data-flow" width="571" height="61" loading="lazy"><figcaption>Diagrama do fluxo de dados</figcaption></figure><p>Como você pode ver no diagrama (eu espero), quando o usuário insere seus votos, os dados vão do componente do painel para o serviço de API que criamos para comunicação com a API de <em>back-end</em>. Em seguida, ele alcança o controlador de <em>back-end</em> que está de fato fazendo as chamadas HTTP.</p><p>Depois que os dados são buscados, o serviço os repassa para nossa interface do usuário, onde os mostramos por meio de nossos componentes do Vue.js. Como você verá, existe alguma lógica adicional que verifica se o usuário está autenticado para saber quais chamadas executar.</p><p>Aqui está a implementação do <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/PizzaVotesController.cs"><em>controller</em></a> em si:</p><pre><code class="language-c">using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace backend.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class PizzaVotesController : ControllerBase
    {
        private readonly ApplicationDbContext _dbContext;

        public PizzaVotesController(ApplicationDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        // GET api/pizzavotes
        [HttpGet]
        public async Task&lt;ActionResult&lt;List&lt;PizzaVotes&gt;&gt;&gt; Get()
        {
            return await _dbContext.PizzaVotes.ToListAsync();
        }

        // GET api/pizzavotes/{email}
        [Authorize]
        [HttpGet("{id}")]
        public async Task&lt;ActionResult&lt;PizzaVotes&gt;&gt; Get(string id)
        {
            return await _dbContext.PizzaVotes.FindAsync(id);
        }

        // POST api/pizzavotes
        [Authorize]
        [HttpPost]
        public async Task Post(PizzaVotes model)
        {
            await _dbContext.AddAsync(model);
            await _dbContext.SaveChangesAsync();
        }

        // PUT api/pizzavotes/{email}
        [Authorize]
        [HttpPut("{id}")]
        public async Task&lt;ActionResult&gt; Put(string id, PizzaVotes model)
        {
            var exists = await _dbContext.PizzaVotes.AnyAsync(f =&gt; f.Id == id);
            if (!exists)
            {
                return NotFound();
            }

            _dbContext.PizzaVotes.Update(model);

            await _dbContext.SaveChangesAsync();

            return Ok();
        }
    }
}</code></pre><p>Aqui temos quatro métodos para executar as quatro operações básicas:</p><ul><li>Obter todos os registros do banco de dados;</li><li>Obter os registros de um usuário (pelo endereço de e-mail);</li><li>Criar um novo registro de usuário;</li><li>Atualizar os registros de um usuário existente.</li></ul><p>Você provavelmente notou a cláusula <code>[Authorize]</code> acima de três dos quatro métodos. Esses métodos vão exigir que o usuário seja autenticado para executar.</p><p>Deixaremos o método <code>GET api/pizzavotes</code> sem autorização para obter todos os registros de propósito. Como gostaríamos de mostrar o gráfico de barras na tela inicial para todos os usuários, precisaremos poder fazer esta chamada, independentemente de o usuário estar autenticado ou não.</p><h3 id="permitindo-o-registro">Permitindo o registro</h3><p>Algo para se observar: se você gostaria de ter um 'Cadastre-se' em sua tela de login, você precisa permitir isso no painel de administração do Okta.</p><p>Uma vez logado, selecione no menu <strong><em>Users -&gt; Registration </em></strong>(Usuários -&gt; Registro):</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-66.png" class="kg-image" alt="image-66" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-66.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-66.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-66.png 1080w" width="1080" height="534" loading="lazy"><figcaption>Permitir registro de novos usuários</figcaption></figure><h3 id="finalizando-o-back-end"><strong>Finalizando o<strong> </strong><em><strong>back</strong>-<strong>end</strong></em></strong></h3><p>Para que o <em>back-end</em> de sua aplicação funcione totalmente, dê uma olhada no meu <a href="https://github.com/mihailgaberov/pizza-app/tree/master/backend">repositório aqui </a>e adicione os arquivos ausentes.</p><p>Se você acompanhou até este ponto, você deve ter os seguintes arquivos (exceto a pasta de teste, pois vamos adicioná-la mais a frente):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-67.png" class="kg-image" alt="image-67" width="354" height="484" loading="lazy"><figcaption>Estrutura do <em>back-end</em> do app</figcaption></figure><h3 id="finalizando-o-front-end"><strong>Finalizando o <strong><em>front</em></strong><em>-</em><strong><em>end</em></strong></strong></h3><p>Para finalizar o trabalho do <em>front-end</em> da nossa aplicação, criaremos mais dois componentes.<br><br>O primeiro renderizará o gráfico de barras mencionado acima, enquanto o segundo exibirá o endereço de e-mail do usuário que está conectado no momento.</p><p>No seu IDE, vá para <code>frontend/src/components</code> e crie dois arquivos, chamados <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/Username.vue">Username.vue</a> e <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/src/components/VotesChart.vue">VotesChart.vue</a>, respectivamente.</p><p>Username.vue é um componente muito curto e simples que pega o endereço de e-mail do usuário como suporte e o renderiza. Aqui está a sua implementação:</p><pre><code>&lt;template&gt;
  &lt;div class="username"&gt;{{ username }}&lt;/div&gt;
&lt;/template&gt;

&lt;script&gt;
export default {
  props: { username: String },
}
&lt;/script&gt;

&lt;style lang="scss"&gt;
.username {
  color: rebeccapurple;
  display: flex;
  align-items: center;
  justify-content: center;
}

.username::before {
  content: "•";
}

.username::after {
  content: "•";
}
&lt;/style&gt;
</code></pre><p>Um único ponto que é preciso observar aqui é que estamos usando SASS/SCSS para definir os estilos dos componentes. Isso é possível por termos escolhido essa opção no início (quando estávamos instalando nossa aplicação do Vue.js).</p><p>Para desenhar o gráfico, usaremos um pacote chamado vue-chart.js. Instale-o executando o seguinte comando na sua pasta <code>frontend</code>:</p><pre><code>npm i vue-chartjs chart.js</code></pre><p>Nosso componente <strong>VotesChart.vue</strong> será uma espécie de <em>wrapper</em> para o componente gráfico de barras que vem do pacote vue-chartjs.</p><p><br>Nós o usamos para obter os dados do componente pai, <strong>Dashboard.vue</strong>, e processá-los. Classificamos o array de dados para exibir nossos principais votantes, classificados do maior para o menor número de votos. </p><p>Em seguida, passamos para o componente do gráfico de barras para visualizá-lo. Aqui está a implementação completa:</p><pre><code>&lt;script&gt;
import { Bar } from 'vue-chartjs'

const TOP_N_VOTERS_TO_SHOW_ON_CHART = 10

// Usado para ordenar pelo valor dos votos - do maior para o menor (desc)
function sortByStartDate(nextUser, currentUser) {
  const nextVoteValue = nextUser.value
  const currentVoteValue = currentUser.value
  return currentVoteValue - nextVoteValue
}

export default {
  extends: Bar,
  props: { data: Array },

  watch: {
    data: async function (newVal) {
      const sortedVotes = Array.from(newVal).sort(sortByStartDate).slice(0, TOP_N_VOTERS_TO_SHOW_ON_CHART)
      this.labels = sortedVotes.map(user =&gt; user.id)
      this.values = sortedVotes.map(user =&gt; user.value)

      this.renderChart({
        labels: this.labels,
        datasets: [
          {
            label: 'Pizza Lovers',
            backgroundColor: '#f87979',
            data: this.values,
          }
        ]
      }, {
        scales: {
          yAxes: [{
            ticks: {
              stepSize: 1,
              min: 0,
              max: this.values[0]
            }
          }]
        }
      })
    }
  }
}
&lt;/script&gt;
</code></pre><p>Observe que há uma constante na parte superior do arquivo que definirá quantos dos principais votantes gostaríamos de mostrar neste gráfico. Atualmente, está definida como 10, mas você pode alterá-la como quiser.</p><p><br>Quando estiver pronto com todo o <em>front-end</em> e quiser executar a aplicação, você pode fazer isso:</p><p>Vá para a pasta <code>frontend</code> e execute:</p><pre><code class="language-bash">npm run serve</code></pre><p>Vá para a pasta <code>backend</code> e execute:</p><pre><code class="language-bash">dotnet run</code></pre><p>Abra seu navegador e acesse <a href="https://localhost:5001">https://localhost:5001</a>.</p><h2 id="como-testar-nossas-aplica-es">Como testar nossas aplicações</h2><p>Até agora, criamos uma aplicação de página única moderna e totalmente funcional com um <em>back-end</em> em .NET Core e um banco de dados SQLite. Isso é muito trabalho. Parabéns! ✨</p><p>Facilmente, poderíamos parar aqui e tomar um suco ou um café.</p><p>Poré,...<br><br>Somos razoáveis o suficiente para saber que, se não testarmos nossas aplicações, não podemos garantir que funcionarão conforme o esperado.</p><p>Também sabemos que, se quisermos tornar nosso código testável, devemos escrevê-lo de maneira bem estruturada, tendo em mente <a href="https://www.dotnettricks.com/learn/designpatterns/different-types-of-software-design-principles">os princípios básicos do design de software</a> (texto em inglês).</p><p>Espero ter convencido você a continuar trabalhando neste tutorial. Afinal, a única coisa que nos resta fazer é escrever alguns testes para nossas duas aplicações. Então, vamos fazê-lo!</p><p>Trataremos do funcionamento de nossa API de <em>back-end</em> com<strong> testes de integração</strong> e, em nosso <em>front-end</em>, escreveremos testes de <strong>unidade</strong> e <strong>integração</strong>.</p><h3 id="testes-de-unidade-e-de-integra-o">Testes de unidade e de integração</h3><p>Antes de passar para o código, gostaria de dizer algumas palavras sobre esses tipos de testes e responder a algumas das perguntas mais frequentes.</p><p>Você deve estar se perguntando, o que são testes de unidade? O que são testes de integração? Por que nós precisamos deles? Quando devemos usar cada um deles?</p><p>Partindo da primeira pergunta, um<strong> teste de unidade</strong> é um trecho de código que testa a funcionalidade de um módulo encapsulado (ou seja, outro trecho). É escrito como uma função ou algum tipo de bloco de código independente.</p><p>Eles são bons de se ter, porque fornecem um feedback rápido do tempo de desenvolvimento e mantêm o código protegido contra regressões quando novos recursos são adicionados.</p><p>Os <strong>testes de integração</strong> são úteis quando precisamos testar como vários módulos/unidades estão trabalhando juntos. Por exemplo, uma API REST e uma interação com um banco de dados.</p><p>Dependendo do tamanho da aplicação em que estamos trabalhando, podemos precisar apenas de testes de integração. Às vezes, no entanto, precisamos de testes de integração e de unidade para testar de verdade o nosso código.</p><p>Idealmente, deveríamos ter ambos, pois são partes essenciais da pirâmide de testes e são os mais baratos de implementar.</p><p>Em alguns casos, contudo, como para nosso <em>back-end</em>, apenas testes de integração são necessários para cobrir a funcionalidade que vale a pena ser testada. Temos apenas os métodos de API para trabalhar com o banco de dados.</p><h3 id="como-criar-nossos-testes-de-back-end">Como criar nossos testes de <em>back-end</em></h3><p>Desta vez, começaremos criando nossa solução de teste. Para fazer isso, você precisa fazer algumas coisas.<br><br>Primeiro, instale a biblioteca xUnit executando o seguinte no diretório raiz do projeto:</p><pre><code class="language-bash">dotnet add package xUnit</code></pre><p>Em seguida, vá para a pasta de <code>backend</code> e crie e esvazie a pasta chamada <code>tests</code>. Então, dentro dessa pasta, execute: </p><pre><code class="language-bash">dotnet new xunit -o PizzaVotes.Tests</code></pre><p>Feito isso, abra backend.csproj e adicione as duas linhas a seguir ao bloco <code>&lt;PropertyGroup&gt;</code>:</p><pre><code>&lt;GenerateAssemblyInfo&gt;false&lt;/GenerateAssemblyInfo&gt;
&lt;GenerateTargetFrameworkAttribute&gt;false&lt;/GenerateTargetFrameworkAttribute&gt;</code></pre><p>Em seguida, vá para a pasta <code>tests</code> e instale os seguintes pacotes: </p><pre><code>Microsoft.AspNetCore.Mvc
Microsoft.AspNetCore.Mvc.Core
Microsoft.AspNetCore.Diagnostics
Microsoft.AspNetCore.TestHost
Microsoft.Extensions.Configuration.Json
Microsoft.AspNetCore.Mvc.Testing</code></pre><p>Você faz isso executando cada um dos seguintes comandos em seu terminal:</p><pre><code class="language-bash">dotnet add package Microsoft.AspNetCore.Mvc --version 2.2.0
dotnet add package Microsoft.AspNetCore.Mvc.Core --version 2.2.5
dotnet add package Microsoft.AspNetCore.Diagnostics --version 2.2.0
dotnet add package Microsoft.AspNetCore.TestHost --version 3.1.8
dotnet add package Microsoft.AspNetCore.Mvc.Testing --version 3.1.8</code></pre><p>Depois de ter tudo instalado, estamos prontos para começar a escrever alguns testes.<br><br>Como você pode ver aqui, excetuando os próprios testes, adicionei mais dois arquivos que precisamos ou que são bons de se ter ao executar os testes.</p><p>Um deles é apenas um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/ContentHelper.cs">arquivo auxiliar</a> com um método para lidar com objetos serializados e obter o conteúdo da string. O outro é o arquivo <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/TestFixture.cs">fixture</a>, onde temos as configurações e definições do nosso servidor de teste e o <em>client</em>.</p><p>Claro, há também um <a href="https://github.com/mihailgaberov/pizza-app/blob/master/backend/tests/PizzaVotes.Tests/PizzaVotesTests.cs">arquivo</a> com nossos testes. </p><p>Não vou colar o conteúdo desses arquivos aqui, pois este tutorial já ficou longo o suficiente.</p><p><strong>Você pode simplesmente copiá-los do meu repositório.</strong></p><p>Se você observar os testes mais de perto, poderá perceber que estamos testando apenas a primeira chamada, não autenticada, para uma resposta de sucesso. Para o restante, estamos verificando apenas a resposta HTTP 401, <code>Unauthorized</code> (não autorizada).</p><p>Isso ocorre porque apenas o primeiro método é público, ou seja, não precisa de autenticação.</p><p>Se tivéssemos os mesmos testes para todos os métodos, precisaríamos implementar um middleware apenas para autorizar nossa aplicação de teste na frente dos serviços de autenticação da Okta.</p><p>Como o objetivo deste tutorial é aprender uma variedade de coisas, podemos dizer que não vale a pena.</p><p>Agora a parte divertida: como executar os testes. Acontece que é muito simples. Basta ir ao seu diretório <code>tests</code> (onde está o arquivo tests.sln) do seu terminal e executar: &nbsp;</p><pre><code class="language-bash">dotnet test</code></pre><p>Você deve ver algo assim em seu terminal (ignore os avisos amarelos):</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-68.png" class="kg-image" alt="image-68" width="443" height="357" loading="lazy"><figcaption>Executando os testes do <em>back-end</em></figcaption></figure><h3 id="como-criar-nossos-testes-para-o-front-end">Como criar nossos testes para o <em>front-end</em></h3><p>É hora de adicionar alguns testes ao nosso <em>front-end</em>. Aqui, faremos testes de unidade e de integração.</p><p><strong>Testes de unidade</strong><br>Como mencionei acima, os testes de unidade são adequados quando temos um módulo ou componente que não possui dependências do mundo externo.</p><p>Esses componentes acabam sendo nossos componentes Username.vue e VotesChart.vue.</p><p>Eles são componentes representacionais, que recebem os dados de que precisam para funcionar adequadamente por meio de props. Isso significa que podemos escrever nossos testes da mesma maneira: passar a eles os dados de que precisam e verificar se os resultados de sua execução são os esperados.</p><p>Aqui, há algo importante para se destacar. Isso não significa que aquilo que foi fornecido pelo pacote <strong>@vue/test-utils</strong> (que vem ao instalar o Vue.js) não tenha sido o suficiente para testar ambos os componentes.</p><p>Em vez disso, para fins educacionais, decidi instalar e usar a biblioteca de testes do Vue também. É por isso que um dos componentes abaixo é testado com @vue/test-utils, mas o outro é testado com @testing-library/vue.</p><p>Não se esqueça de instalá-la antes de executar o teste:</p><pre><code>npm i --save-dev @testing-library/vue</code></pre><p>Novamente, para economizar espaço, não vou colar o código do teste do componente aqui, mas você pode vê-lo facilmente <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/unit/Username.spec.js">aqui</a> e <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/unit/VotesChart.spec.js">aqui</a>. </p><p>Então, para executar os testes de unidade do seu <em>front-end</em>, vá para a pasta <code>frontend</code> e execute: </p><pre><code>npm run test:unit</code></pre><p><strong>Teste de integração</strong><br>Esse tema é provavelmente bem interessante para alguns de vocês.</p><p>Se você se lembra do início deste tutorial, quando instalamos nossa aplicação do Vue.js, para nossa solução de testes e2e (ou de integração), selecionamos o <a href="https://www.cypress.io/">Cypress.js</a>.</p><p>Esta é uma ferramenta superfácil de usar, que permite aos desenvolvedores escrever testes e2e (end-to-end, ou de ponta a ponta) reais para suas aplicações, fornecendo feedback imediato.</p><p>Por experiência pessoal, eu diria que trabalhar com o Cypress é mais prazeroso do que com outros frameworks semelhantes. Se você tiver experiência anterior com estruturas como Nightwatch.js ou Selenium, o que você vê abaixo pode ser familiar para você.</p><p>Antes de executar nossos testes com o Cypress, precisamos fazer algumas pequenas alterações em sua configuração.</p><p>Encontre o <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/e2e/plugins/index.js">arquivo de índice</a> <code>plugins</code> e adicione a seguinte linha à declaração de retorno no final do arquivo:</p><pre><code>  baseUrl: "https://localhost:5001"</code></pre><p>Agora, atualize o conteúdo do test.js na pasta <code>specs</code> conforme mos<em>t</em>rado <a href="https://github.com/mihailgaberov/pizza-app/blob/master/frontend/tests/e2e/specs/test.js">aqui</a>.</p><p>Depois de fazer tudo, você poderá executar seus testes e2e via Cypress. Você pode fazer isso executando o seguinte comando enquanto estiver no diretório do <code>frontend</code>:</p><pre><code>npm run test:e2e</code></pre><p>⚡Não se esqueça de iniciar sua aplicação de <em>back-end</em> antes de executar os testes e2e para que funcionem corretamente.</p><p>Se você fez tudo como mostramos, depois de executar o comando acima, você deve ver algo assim em seu terminal:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-69.png" class="kg-image" alt="image-69" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-69.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-69.png 640w" width="640" height="223" loading="lazy"><figcaption>Executando testes e2e</figcaption></figure><p>Uma nova janela do navegador será aberta pelo próprio Cypress.js, onde você pode usar o URI fornecido para ver e executar seus testes.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-70.png" class="kg-image" alt="image-70" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-70.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-70.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-70.png 1174w" width="1174" height="806" loading="lazy"><figcaption>UI do Cypress.js</figcaption></figure><p>Quando todos os testes forem aprovados, você deverá ver uma tela como esta:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-71.png" class="kg-image" alt="image-71" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/03/image-71.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/03/image-71.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/03/image-71.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/03/image-71.png 1912w" sizes="(min-width: 1200px) 1200px" width="1912" height="1122" loading="lazy"><figcaption>Os testes e2e passaram com sucesso</figcaption></figure><h2 id="conclus-o"><strong><strong>Conclu</strong>são</strong></h2><p>Neste tutorial, vimos como usar duas das tecnologias mais importantes do mercado para criar um <em>front-end</em> e um <em>back-end</em>.</p><p>Também aprendemos como combiná-las adequadamente para criar uma aplicação de página única pequena, mas totalmente funcional, com suporte a banco de dados.</p><p>Por fim, também escrevemos testes de unidade e de integração para ambas as pontas do projeto.</p><p>Acredito que esse tipo de exercício seja benéfico tanto para leitores experientes quanto para iniciantes, pois aborda muitas coisas diferentes passo a passo. No final, se tiver concluído todo o processo, você tem uma aplicação funcional de exemplo.</p><p>Este tutorial acabou sendo muito mais longo do que eu inicialmente pensei que seria. Se, contudo, você já fez tudo, eu admiro você! Espero que tenha sido um prazer para você ler o artigo, assim como foi para mim escrevê-lo.</p><p>Obrigado pela leitura!</p><h2 id="recursos"><strong><strong>Re</strong>cursos</strong></h2><p>Você pode encontrar abaixo os links que foram úteis para mim, de algum modo, enquanto escrevia o artigo (recursos em inglês).</p><p><a href="https://consultwithgriff.com/spas-with-vuejs-aspnetcore/">https://consultwithgriff.com/spas-with-vuejs-aspnetcore/</a><br><a href="https://github.com/okta/okta-auth-dotnet">https://github.com/okta/okta-auth-dotnet</a><br><a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test">https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-with-dotnet-test</a><br><a href="https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpresponsemessage?view=netcore-3.1">https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpresponsemessage?view=netcore-3.1</a><br><a href="https://vue-test-utils.vuejs.org/guides/#testing-key-mouse-and-other-dom-events">https://vue-test-utils.vuejs.org/guides/#testing-key-mouse-and-other-dom-events</a><br><a href="https://docs.cypress.io/guides/references/configuration.html#Options">https://docs.cypress.io/guides/references/configuration.html#Options</a><br><a href="https://docs.cypress.io/guides/tooling/visual-testing.html#Functional-vs-visual-testing">https://docs.cypress.io/guides/tooling/visual-testing.html#Functional-vs-visual-testing</a><br><a href="https://www.codingame.com/playgrounds/35462/creating-web-api-in-asp-net-core-2-0/part-3---integration-tests">https://www.codingame.com/playgrounds/35462/creating-web-api-in-asp-net-core-2-0/part-3---integration-tests</a><br><a href="https://testing-library.com/docs/vue-testing-library/intro">https://testing-library.com/docs/vue-testing-library/intro</a><br><a href="https://www.valentinog.com/blog/canvas/">https://www.valentinog.com/blog/canvas/</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Usando as planilhas do Google como um endpoint de JSON ]]>
                </title>
                <description>
                    <![CDATA[ ATUALIZAÇÃO: 13/5/2020 – Os passos da nova caixa de diálogo de compartilhamento [https://gsuiteupdates.googleblog.com/2020/04/new-file-sharing-dialog-google-drive.html]  estão disponíveis abaixo. > Obrigado, Erica H.! Você está construindo algum protótipo de aplicação web dinâmica e precisa da colaboração de pessoas que não possuem experiência como desenvolvedoras? Já participei de um hackathon antes. Mesmo tendo ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/usando-as-planilhas-do-google-como-um-endpoint-de-json/</link>
                <guid isPermaLink="false">63834851d7295905e9348e24</guid>
                
                    <category>
                        <![CDATA[ JSON ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Sun, 01 Jan 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/0_kycb_xJ-enmTWhvL.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/cjn-google-sheets-as-json-endpoint/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to use Google Sheets as a JSON Endpoint</a>
      </p><p>ATUALIZAÇÃO: 13/5/2020 – Os passos da <a href="https://gsuiteupdates.googleblog.com/2020/04/new-file-sharing-dialog-google-drive.html">nova caixa de diálogo de compartilhamento</a> estão disponíveis abaixo.</p><blockquote>Obrigado, Erica H.!</blockquote><p>Você está construindo algum protótipo de aplicação web dinâmica e precisa da colaboração de pessoas que não possuem experiência como desenvolvedoras?</p><p>Já participei de um hackathon antes. Mesmo tendo a experiência e o conhecimento em desenvolvimento de aplicações, não tinha habilidade ou tempo suficiente para implementar um aplicação web completa na sprint de 3 dias. Era pouco tempo para ajudar e, assim, foi deixada de lado a possibilidade de assistir a tutoriais e estudar HTML e CSS.</p><p>O resultado? Aprendi muito, mas gostaria de ter contribuído mais.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-125.png" class="kg-image" alt="image-125" width="310" height="232" loading="lazy"></figure><p>Em um dos hackathons dos quais participei recentemente, encontrei um problema semelhante. Dessa vez, eu não era o novato. Havia no meu time pessoas que não eram engenheiras de software e que queriam ajudar na construção de nosso protótipo de aplicação web. Felizmente, nos deparamos com as planilhas do Google como uma maneira de essas pessoas simularem nosso banco de dados e fazerem com que os desenvolvedores de back-end se conectassem ao endpoint de JSON das planilhas do Google e pudessem, assim, analisá-lo.</p><p>Com este guia, você será capaz de:</p><ol><li>Criar uma planilha nas planilhas do Google.</li><li>Publicar a planilha na web.</li><li>Gerar um endpoint de JSON.</li><li>Tornar a planilha pública para colaboração.</li><li>Passar o endpoint de JSON para o time de desenvolvedores de back-end.</li></ol><p>Após este tutorial, você poderá entrar em equipes dizendo: "Posso ajudar com o back-end!".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-126.png" class="kg-image" alt="image-126" width="315" height="395" loading="lazy"></figure><h3 id="se-o-1-criando-uma-planilha-do-google">Seção 1: Criando uma planilha do Google</h3><p><strong>Passo<strong><strong><strong> 1:</strong></strong></strong></strong></p><p>Vá até as <a href="https://docs.google.com/spreadsheets/u/0/" rel="nofollow noopener">planilhas do Google</a></p><p><strong>Passo<strong><strong><strong> 2:</strong></strong></strong></strong></p><p>Crie uma planilha</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_2md2vMHKWXzXbWOwddzXPw.png" class="kg-image" alt="1_2md2vMHKWXzXbWOwddzXPw" width="404" height="448" loading="lazy"></figure><h3 id="se-o-2-publicando-suas-planilhas-do-google-na-web">Seção 2: Publicando suas planilhas do Google na web</h3><p><em>Nota: a atualização da nova caixa de diálogo de compartilhamento a partir de 13/05/2020, localizada após o passo 2.</em></p><p><strong>Passo<strong><strong><strong> 1:</strong></strong></strong></strong></p><p>Clique em "<strong><em>Arquivo</em></strong>"<strong><strong><strong><strong><em><em> </em></em></strong></strong></strong></strong><em><em>&gt; </em></em>"<strong><strong><strong><strong><em><em>Publi</em></em></strong></strong></strong><em>car na</em><strong><strong><strong><em><em> web…</em></em></strong></strong></strong></strong>" (ou, em inglês, como na imagem, <strong>File</strong> &gt; <strong>Publish to the web...</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_XFtPyWBYh3JX6PdQUJ5j-w.png" class="kg-image" alt="1_XFtPyWBYh3JX6PdQUJ5j-w" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_XFtPyWBYh3JX6PdQUJ5j-w.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_XFtPyWBYh3JX6PdQUJ5j-w.png 634w" width="634" height="1428" loading="lazy"></figure><p><strong>Passo<strong><strong><strong> 2:</strong></strong></strong></strong></p><p>Clique em "<strong><strong><strong><strong><em><em>Publi</em></em></strong></strong></strong><em>car</em></strong>" (ou, em inglês, como na imagem, <strong>Publish</strong>), depois em "<strong><strong><strong><strong><em><em>OK</em></em></strong></strong></strong></strong>"<strong><em>.</em></strong></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_QtAY0n29zHviNXdsPJZaQQ.png" class="kg-image" alt="1_QtAY0n29zHviNXdsPJZaQQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_QtAY0n29zHviNXdsPJZaQQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_QtAY0n29zHviNXdsPJZaQQ.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_QtAY0n29zHviNXdsPJZaQQ.png 1268w" sizes="(min-width: 720px) 720px" width="1268" height="1592" loading="lazy"></figure><p><strong>Passo<strong><strong><strong> 3:</strong></strong></strong></strong></p><p>Não há necessidade de fazer nada aqui.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_WenBwpAkxyDc4fhGPeC6Dw.png" class="kg-image" alt="1_WenBwpAkxyDc4fhGPeC6Dw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_WenBwpAkxyDc4fhGPeC6Dw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_WenBwpAkxyDc4fhGPeC6Dw.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_WenBwpAkxyDc4fhGPeC6Dw.png 1258w" sizes="(min-width: 720px) 720px" width="1258" height="1202" loading="lazy"></figure><h3 id="atualiza-o-13-05-2020-nova-caixa-de-di-logo-de-compartilhamento">ATUALIZAÇÃO: 13/05/2020 - Nova caixa de diálogo de compartilhamento</h3><p><strong>Passo<strong> 1:</strong></strong><br>Clique em <strong>"Compartilhar"</strong> (ou, em inglês, como na imagem, <strong>Share</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-108.png" class="kg-image" alt="image-108" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/image-108.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-108.png 650w" width="650" height="264" loading="lazy"></figure><p><strong>Passo<strong> 2:</strong></strong></p><p>Clique em "<strong>Alterar para qualquer pessoa com o link</strong>" (ou, em inglês, como na imagem, <strong>Change to anyone with the link</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-107-1.png" class="kg-image" alt="image-107-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/image-107-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-107-1.png 811w" sizes="(min-width: 720px) 720px" width="811" height="485" loading="lazy"></figure><p><strong>Passo<strong> 3:</strong></strong></p><p>Clique em "<strong>Concluído</strong>" (ou, em inglês, como na imagem, <strong>Done</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-109-1.png" class="kg-image" alt="image-109-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/image-109-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/image-109-1.png 808w" sizes="(min-width: 720px) 720px" width="808" height="464" loading="lazy"></figure><h3 id="se-o-4-usando-suas-planilhas-das-planilhas-do-google-como-endpoint-de-json">Seção 4: usando suas planilhas das planilhas do Google como endpoint de JSON</h3><p><strong>Passo<strong><strong><strong> 1:</strong></strong></strong></strong></p><p>Copie o template de URL e cole na barra de endereços:</p><p><a href="https://spreadsheets.google.com/feeds/cells/1g4FBktkm7al3ZkDI8LuFXuztTqK4nY-eUYMLep6BRuw/1/public/full?alt=json" rel="nofollow noopener noopener nofollow noopener">https://spreadsheets.google.com/feeds/cells/CÓDIGODASUAPLANILHAGOOGLESHEETS/NÚMERODAPÁGINADAPLANILHA/public/full?alt=json</a></p><p><strong>Passo<strong><strong><strong> 2:</strong></strong></strong></strong></p><p>Vá até a planilha do Google aberta e verifique a barra de endereços.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_xRIMehCRmQxSQpAWi2bhlQ.png" class="kg-image" alt="1_xRIMehCRmQxSQpAWi2bhlQ" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_xRIMehCRmQxSQpAWi2bhlQ.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_xRIMehCRmQxSQpAWi2bhlQ.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_xRIMehCRmQxSQpAWi2bhlQ.png 1562w" sizes="(min-width: 720px) 720px" width="1562" height="66" loading="lazy"><figcaption>URL da planilha do Google</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_AM6_ME5wgoQdtfMHFB_ipg.png" class="kg-image" alt="1_AM6_ME5wgoQdtfMHFB_ipg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_AM6_ME5wgoQdtfMHFB_ipg.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_AM6_ME5wgoQdtfMHFB_ipg.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_AM6_ME5wgoQdtfMHFB_ipg.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="68" loading="lazy"><figcaption>Código da planilha do Google</figcaption></figure><p><strong>Passo<strong><strong><strong> 3:</strong></strong></strong></strong></p><p>Vá até o template de URL e substitua</p><ul><li><em><strong>CÓDIGODASUAPLANILHAGOOGLESHEETS</strong> </em>por <strong><strong><strong><strong><em><em>1ifbWzueslEP5-_ysP6gg7o_NaHQmqF8LlXBfStCwFMs</em></em></strong></strong></strong></strong></li><li><em><strong>NÚMERODAPÁGINADAPLANILHA</strong> </em>por <strong><strong><strong><strong><em><em>1</em></em></strong></strong></strong></strong></li></ul><p><strong>Passo<strong><strong><strong> 4:</strong></strong></strong></strong></p><p>Recupere o URL do JSON</p><p><a href="https://spreadsheets.google.com/feeds/cells/1ifbWzueslEP5-_ysP6gg7o_NaHQmqF8LlXBfStCwFMs/1/public/full?alt=json" rel="nofollow noopener">https://spreadsheets.google.com/feeds/cells/1ifbWzueslEP5-_ysP6gg7o_NaHQmqF8LlXBfStCwFMs/1/public/full?alt=json</a></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_SU97RXIK-rFaMWEfaP1kng.png" class="kg-image" alt="1_SU97RXIK-rFaMWEfaP1kng" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_SU97RXIK-rFaMWEfaP1kng.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_SU97RXIK-rFaMWEfaP1kng.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_SU97RXIK-rFaMWEfaP1kng.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="1253" loading="lazy"><figcaption>Resultado do URL do JSON</figcaption></figure><h3 id="se-o-5-tornando-p-blica-sua-planilha-do-google-para-colabora-o-e-entrada-de-dados-">Seção 5: Tornando pública sua planilha do Google (para colaboração e entrada de dados)</h3><h4 id="passo-1-"><strong>Passo 1:</strong></h4><p>No canto superior direito, clique em "<strong>Compartilhar</strong>" (ou, em inglês, como na imagem, <strong>Share</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_O2SCuizLuiLPFFBQVRL9vw.png" class="kg-image" alt="1_O2SCuizLuiLPFFBQVRL9vw" width="468" height="118" loading="lazy"></figure><p><strong>Passo<strong><strong><strong> 2:</strong></strong></strong></strong></p><p>Adicione um nome e clique em "<strong><strong><strong><strong><em><em>Sa</em></em></strong></strong></strong><em>lvar</em></strong>" (ou, em inglês, como na imagem, <strong>Save</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_D6leg5gLfYpoTOXlrpFUcw.png" class="kg-image" alt="1_D6leg5gLfYpoTOXlrpFUcw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_D6leg5gLfYpoTOXlrpFUcw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_D6leg5gLfYpoTOXlrpFUcw.png 882w" sizes="(min-width: 720px) 720px" width="882" height="584" loading="lazy"></figure><p><strong>Passo<strong><strong><strong> 3:</strong></strong></strong></strong></p><p>Clique em "<strong><strong><strong><strong><em><em>Avan</em></em></strong></strong></strong><em>çado</em></strong>" (ou, em inglês, como na imagem, <strong>Advanced</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_k7DGUBwGJnVIdZeuaQbGlA.png" class="kg-image" alt="1_k7DGUBwGJnVIdZeuaQbGlA" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_k7DGUBwGJnVIdZeuaQbGlA.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_k7DGUBwGJnVIdZeuaQbGlA.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_k7DGUBwGJnVIdZeuaQbGlA.png 1204w" sizes="(min-width: 720px) 720px" width="1204" height="654" loading="lazy"></figure><p><strong>Passo <strong><strong><strong>4:</strong></strong></strong></strong></p><p>Clique em "<strong><em>Alterar</em><strong><strong><strong><em><em>…</em></em></strong></strong></strong></strong>" &nbsp;(ou, em inglês, como na imagem, <strong>Change</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_qkKSGYrYiNp861WQjaoUKg.png" class="kg-image" alt="1_qkKSGYrYiNp861WQjaoUKg" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_qkKSGYrYiNp861WQjaoUKg.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_qkKSGYrYiNp861WQjaoUKg.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_qkKSGYrYiNp861WQjaoUKg.png 1190w" sizes="(min-width: 720px) 720px" width="1190" height="562" loading="lazy"></figure><p><strong>Passo<strong><strong><strong> 5:</strong></strong></strong></strong></p><p>Clique em "<strong><em>Ativado </em><strong><strong><strong><em><em>— P</em></em></strong></strong></strong><em>úblico</em><strong><strong><strong><em><em> </em></em></strong></strong></strong><em>na</em><strong><strong><strong><em><em> web</em></em></strong></strong></strong></strong>" (ou, em inglês, como na imagem, <strong>ON - Public on the web</strong>). Depois, clique em salvar "<strong><strong><strong><strong><em><em>Sa</em></em></strong></strong></strong><em>lvar</em></strong>" (ou, em inglês, como na imagem, <strong>Save</strong>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_paO-_3OAzlhzW-oZQI9udw.png" class="kg-image" alt="1_paO-_3OAzlhzW-oZQI9udw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_paO-_3OAzlhzW-oZQI9udw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_paO-_3OAzlhzW-oZQI9udw.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_paO-_3OAzlhzW-oZQI9udw.png 1206w" sizes="(min-width: 720px) 720px" width="1206" height="958" loading="lazy"></figure><h3 id="pegadinhas-comuns-">Pegadinhas comuns:</h3><p>Se você receber a resposta abaixo, verifique o URL e certifique-se de estar usando o código correto das planilhas do Google na barra de endereço.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_xrfoHNKtE4uld3IylAI1Lw.png" class="kg-image" alt="1_xrfoHNKtE4uld3IylAI1Lw" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_xrfoHNKtE4uld3IylAI1Lw.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/11/1_xrfoHNKtE4uld3IylAI1Lw.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_xrfoHNKtE4uld3IylAI1Lw.png 1392w" sizes="(min-width: 720px) 720px" width="1392" height="808" loading="lazy"></figure><p>Se você receber a resposta abaixo, volte para a<em> Seção 2: Publicando suas planilhas do Google na web.</em></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ZL71DxnV5Rw6asXjpjjC1Q-1.png" class="kg-image" alt="1_ZL71DxnV5Rw6asXjpjjC1Q-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/11/1_ZL71DxnV5Rw6asXjpjjC1Q-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/11/1_ZL71DxnV5Rw6asXjpjjC1Q-1.png 760w" sizes="(min-width: 720px) 720px" width="760" height="234" loading="lazy"></figure><p><a href="https://www.linkedin.com/in/clarkngo/">LinkedIn do autor do texto</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como usar o Redux em sua aplicação do React com TypeScript ]]>
                </title>
                <description>
                    <![CDATA[ O Redux é um contêiner de estado previsível para aplicações escritas em JavaScript. Ele também é popularmente conhecido como uma biblioteca para o gerenciamento de estado em aplicações do React. Utilizar o Redux junto com TypeScript oferece ao desenvolvedor uma melhor experiência, pois o TypeScript é um superconjunto do JavaScript ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/</link>
                <guid isPermaLink="false">63304f8c5c046e06ec87ab43</guid>
                
                    <category>
                        <![CDATA[ Redux ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Tue, 11 Oct 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-redux-in-your-react-typescript-app/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use Redux in Your React TypeScript App</a>
      </p><p>O Redux é um contêiner de estado previsível para aplicações escritas em JavaScript. Ele também é popularmente conhecido como uma biblioteca para o gerenciamento de estado em aplicações do React.</p><p>Utilizar o Redux junto com TypeScript oferece ao desenvolvedor uma melhor experiência, pois o TypeScript é um superconjunto do JavaScript que verifica o código para torná-lo robusto e compreensível.</p><p>Neste guia, mostrarei como usar o Redux em seu projeto com TypeScript criando uma aplicação do React que permite adicionar, excluir e exibir artigos.</p><p><em>Vamos lá!</em></p><ul><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#pr-requisitos">Pré-requisitos</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#configurando-o-projeto">Configurando o projeto</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-os-tipos">Criando os tipos</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-os-tipos-de-a-o">Criando os tipos de ação</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-os-criadores-de-a-o">Criando os criadores de ação</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-um-redutor">Criando um redutor</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-um-reposit-rio">Criando um repositório</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/como-usar-o-redux-em-sua-aplicacao-do-react-com-typescript/#criando-os-componentes">Criando os componentes</a></li></ul><h2 id="pr-requisitos">Pré-requisitos</h2><p>Este tutorial pressupõe que você tenha pelo menos um conhecimento básico de React, Redux e TypeScript.</p><p>Portanto, se não estiver familiarizado com essas tecnologias, tente primeiro ler este <a href="https://www.ibrahima-ndaw.com/blog/a-practical-guide-to-typescript/">guia prático do TypeScript</a> ou este <a href="https://www.ibrahima-ndaw.com/blog/7-steps-to-understand-react-redux/">tutorial do React Redux</a> (textos em inglês). Caso contrário, vamos começar.</p><h2 id="configurando-o-projeto">Configurando o projeto</h2><p>Para usar o Redux e o TypeScript, precisamos criar uma aplicação em React.</p><p>Para isso, vamos abrir a CLI (interface de linha de comando) e executar este comando:</p><pre><code class="language-shell">  npx create-react-app my-app --template typescript
</code></pre><p>A seguir, vamos estruturar o projeto do seguinte modo:</p><pre><code>├── src
|  ├── components
|  |  ├── AddArticle.tsx
|  |  └── Article.tsx
|  ├── store
|  |  ├── actionCreators.ts
|  |  ├── actionTypes.ts
|  |  └── reducer.ts
|  ├── type.d.ts
|  ├── App.test.tsx
|  ├── App.tsx
|  ├── index.css
|  ├── index.tsx
|  ├── react-app-env.d.ts
|  └── setupTests.ts
├── tsconfig.json
├── package.json
└── yarn.lock
</code></pre><p>A estrutura de arquivos do projeto é bastante simples. No entanto, há duas coisas que você deve prestar atenção:</p><ul><li>A pasta <code>store</code> do repositório, que contém arquivos relacionados ao React Redux. </li><li>O arquivo <code>type.d.ts</code>, que contém os tipos do TypeScript, que podem ser usados agora em outros arquivos sem importar.</li></ul><p>Dito isso, agora, podemos instalar o Redux e criar nosso primeiro repositório.</p><p>Com isso, vamos abrir o projeto e executar o seguinte comando:</p><pre><code class="language-shell">  yarn add redux react-redux redux-thunk
</code></pre><p>Se, no lugar do Yarn, você estiver usando o <code>npm</code>, execute:</p><pre><code class="language-shell">  npm install redux react-redux redux-thunk
</code></pre><p>Também precisamos instalar os tipos como dependências de desenvolvimento para ajudar o TypeScript a entender as bibliotecas.</p><p>Então, vamos executar este comando novamente na CLI.</p><pre><code class="language-shell">  yarn add -D @types/redux @types/react-redux @types/redux-thunk
</code></pre><p>No <code>npm</code>:</p><pre><code class="language-shell">  npm install -D @types/redux @types/react-redux @types/redux-thunk
</code></pre><p>Ótimo! A partir de agora podemos criar os tipos do TypeScript para o projeto na próxima seção.</p><h2 id="criando-os-tipos"><strong>Criando os tipos</strong></h2><p>Os tipos do TypeScript permitem definir tipos para suas variáveis, parâmetros de função e assim por diante.</p><ul><li>type.d.ts</li></ul><pre><code class="language-ts">interface IArticle {
  id: number
  title: string
  body: string
}

type ArticleState = {
  articles: IArticle[]
}

type ArticleAction = {
  type: string
  article: IArticle
}

type DispatchType = (args: ArticleAction) =&gt; ArticleAction
</code></pre><p>Aqui, começamos declarando a interface <code>IArticle</code>, que reflete a forma de um determinado artigo.</p><p>Em seguida, temos <code>ArticleState</code>, <code>ArticleAction</code> e <code>DispatchType</code>, que servirão como tipos para, respectivamente, o objeto de estado, os criadores de ação e a função de <em>dispatch</em> fornecida pelo Redux. </p><p>Dito isso, agora temos os tipos necessários para começar a usar o React Redux. A seguir, vamos criar os tipos de ação.</p><h2 id="criando-os-tipos-de-a-o"><strong>Criando os tipos de ação</strong></h2><ul><li>store/actionTypes.ts</li></ul><pre><code class="language-ts">export const ADD_ARTICLE = "ADD_ARTICLE"
export const REMOVE_ARTICLE = "REMOVE_ARTICLE"
</code></pre><p>Precisamos de dois tipos de ação para o repositório em Redux, um para adicionar artigos e outro para excluí-los.</p><h2 id="criando-os-criadores-de-a-o"><strong>Criando os criadores de ação</strong></h2><ul><li>store/actionCreators.ts</li></ul><pre><code class="language-ts">import * as actionTypes from "./actionTypes"

export function addArticle(article: IArticle) {
  const action: ArticleAction = {
    type: actionTypes.ADD_ARTICLE,
    article,
  }

  return simulateHttpRequest(action)
}

export function removeArticle(article: IArticle) {
  const action: ArticleAction = {
    type: actionTypes.REMOVE_ARTICLE,
    article,
  }
  return simulateHttpRequest(action)
}

export function simulateHttpRequest(action: ArticleAction) {
  return (dispatch: DispatchType) =&gt; {
    setTimeout(() =&gt; {
      dispatch(action)
    }, 500)
  }
}
</code></pre><p>Neste tutorial, simularei a solicitação HTTP atrasando-a por meio segundo. Se quiser, porém, sinta-se à vontade para usar um servidor real.</p><p>Aqui, a função <code>addArticle</code> fará o <em>dispatching</em> de uma ação para adicionar um novo artigo, enquanto o método <code>removeArticle</code> fará o oposto. Portanto, exclua o objeto passado como argumento.</p><h2 id="criando-um-redutor"><strong>Criando um redutor</strong></h2><p>Um redutor (em inglês, <em>reducer</em>) é uma função pura que recebe o estado do repositório e uma ação como parâmetro e depois retorna o estado atualizado.</p><ul><li>store/reducer.ts</li></ul><pre><code class="language-ts">import * as actionTypes from "./actionTypes"

const initialState: ArticleState = {
  articles: [
    {
      id: 1,
      title: "post 1",
      body:
        "Quisque cursus, metus vitae pharetra Nam libero tempore, cum soluta nobis est eligendi",
    },
    {
      id: 2,
      title: "post 2",
      body:
        "Harum quidem rerum facilis est et expedita distinctio quas molestias excepturi sint",
    },
  ],
}
</code></pre><p>Como você pode ver aqui, declaramos um estado inicial para que alguns artigos sejam exibidos quando a página for carregada. O objeto de estado precisa corresponder ao tipo <code>ArticleState</code> – caso contrário, o TypeScript gerará um erro.</p><ul><li>store/reducer.ts</li></ul><pre><code class="language-ts">const reducer = (
  state: ArticleState = initialState,
  action: ArticleAction
): ArticleState =&gt; {
  switch (action.type) {
    case actionTypes.ADD_ARTICLE:
      const newArticle: IArticle = {
        id: Math.random(), // not really unique
        title: action.article.title,
        body: action.article.body,
      }
      return {
        ...state,
        articles: state.articles.concat(newArticle),
      }
    case actionTypes.REMOVE_ARTICLE:
      const updatedArticles: IArticle[] = state.articles.filter(
        article =&gt; article.id !== action.article.id
      )
      return {
        ...state,
        articles: updatedArticles,
      }
  }
  return state
}

export default reducer
</code></pre><p>Em seguida, temos a função <code>reducer</code>, que espera o estado anterior e uma ação para poder atualizar o repositório. Aqui, temos duas ações: uma para adicionar e outra para excluir.</p><p>Com isso definido, agora podemos manipular o estado com o redutor. Próximo passo: criar um repositório para o projeto.</p><h2 id="criando-um-reposit-rio"><strong>Criando um repositório </strong></h2><p>O repositório em Redux é, na prática, onde vive o estado da sua aplicação.</p><ul><li>index.tsx</li></ul><pre><code class="language-tsx">import * as React from "react"
import { render } from "react-dom"
import { createStore, applyMiddleware, Store } from "redux"
import { Provider } from "react-redux"
import thunk from "redux-thunk"

import App from "./App"
import reducer from "./store/reducer"

const store: Store&lt;ArticleState, ArticleAction&gt; &amp; {
  dispatch: DispatchType
} = createStore(reducer, applyMiddleware(thunk))

const rootElement = document.getElementById("root")
render(
  &lt;Provider store={store}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;,
  rootElement
)
</code></pre><p>Como você pode ver, importamos a função do redutor e a passamos como argumento para o método <code>createStore</code> para criar um repositório do Redux. O middleware <code>redux-thunk</code> precisa ser passado como um segundo parâmetro, bem como o método para poder manipular o código assíncrono.</p><p>Em seguida, conectamos o React ao Redux fornecendo o objeto <code>store</code> como <em>props </em>ao componente <code>Provider</code>.</p><p>Agora, podemos usar o Redux neste projeto e acessar o repositório. Então, vamos criar os componentes para obter e manipular os dados.</p><h2 id="criando-os-componentes"><strong>Criando os componentes</strong></h2><ul><li>components/AddArticle.tsx</li></ul><pre><code class="language-tsx">import * as React from "react"

type Props = {
  saveArticle: (article: IArticle | any) =&gt; void
}

export const AddArticle: React.FC&lt;Props&gt; = ({ saveArticle }) =&gt; {
  const [article, setArticle] = React.useState&lt;IArticle | {}&gt;()

  const handleArticleData = (e: React.FormEvent&lt;HTMLInputElement&gt;) =&gt; {
    setArticle({
      ...article,
      [e.currentTarget.id]: e.currentTarget.value,
    })
  }

  const addNewArticle = (e: React.FormEvent) =&gt; {
    e.preventDefault()
    saveArticle(article)
  }

  return (
    &lt;form onSubmit={addNewArticle} className="Add-article"&gt;
      &lt;input
        type="text"
        id="title"
        placeholder="Title"
        onChange={handleArticleData}
      /&gt;
      &lt;input
        type="text"
        id="body"
        placeholder="Description"
        onChange={handleArticleData}
      /&gt;
      &lt;button disabled={article === undefined ? true : false}&gt;
        Add article
      &lt;/button&gt;
    &lt;/form&gt;
  )
}
</code></pre><p>Para adicionar um novo artigo, usaremos este componente de formulário. Ele recebe como parâmetro a função <code>saveArticle</code>, que permite adicionar um novo artigo ao repositório.</p><p>O objeto do artigo deve seguir o tipo <code>IArticle</code> para satisfazer os critérios TypeScript.</p><ul><li>components/Article.tsx</li></ul><pre><code class="language-tsx">import * as React from "react"
import { Dispatch } from "redux"
import { useDispatch } from "react-redux"

type Props = {
  article: IArticle
  removeArticle: (article: IArticle) =&gt; void
}

export const Article: React.FC&lt;Props&gt; = ({ article, removeArticle }) =&gt; {
  const dispatch: Dispatch&lt;any&gt; = useDispatch()

  const deleteArticle = React.useCallback(
    (article: IArticle) =&gt; dispatch(removeArticle(article)),
    [dispatch, removeArticle]
  )

  return (
    &lt;div className="Article"&gt;
      &lt;div&gt;
        &lt;h1&gt;{article.title}&lt;/h1&gt;
        &lt;p&gt;{article.body}&lt;/p&gt;
      &lt;/div&gt;
      &lt;button onClick={() =&gt; deleteArticle(article)}&gt;Delete&lt;/button&gt;
    &lt;/div&gt;
  )
}
</code></pre><p>O componente <code>Article</code> mostra um objeto de artigo.</p><p>A função <code>removeArticle</code> deve fazer o <em>dispatching</em> para acessar o repositório e, em seguida, excluir um determinado artigo. Essa é a razão pela qual usamos o <em>hook</em> <code>useDispatch</code> aqui, que permite que o Redux complete a ação de remoção.</p><p>Por conseguinte, o uso de <code>useCallback</code> ajuda a evitar renderizações desnecessárias ao memorizar valores como dependências.</p><p>Finalmente, temos os componentes que precisamos para adicionar e mostrar os artigos. Agora, vamos adicionar a última peça ao quebra-cabeça, usando tudo isso no arquivo <code>App.tsx</code>.</p><ul><li>App.tsx</li></ul><pre><code class="language-tsx">import * as React from "react"
import { useSelector, shallowEqual, useDispatch } from "react-redux"
import "./styles.css"

import { Article } from "./components/Article"
import { AddArticle } from "./components/AddArticle"
import { addArticle, removeArticle } from "./store/actionCreators"
import { Dispatch } from "redux"

const App: React.FC = () =&gt; {
  const articles: readonly IArticle[] = useSelector(
    (state: ArticleState) =&gt; state.articles,
    shallowEqual
  )

  const dispatch: Dispatch&lt;any&gt; = useDispatch()

  const saveArticle = React.useCallback(
    (article: IArticle) =&gt; dispatch(addArticle(article)),
    [dispatch]
  )

  return (
    &lt;main&gt;
      &lt;h1&gt;My Articles&lt;/h1&gt;
      &lt;AddArticle saveArticle={saveArticle} /&gt;
      {articles.map((article: IArticle) =&gt; (
        &lt;Article
          key={article.id}
          article={article}
          removeArticle={removeArticle}
        /&gt;
      ))}
    &lt;/main&gt;
  )
}

export default App
</code></pre><p>O <em>hook</em> <code>useSelector</code> permite o acesso ao estado do repositório. Aqui, passamos o <code>shallowEqual</code> como um segundo argumento para o método, de modo a dizer ao Redux para usar a igualdade rasa (<em>shallow equality</em>, em inglês) ao verificar as alterações.</p><p>Em seguida, contamos com <code>useDispatch</code> para fazer o <em>dispatching </em>de uma ação com o propósito de adicionar artigos no repositório. Por fim, percorremos o array de artigos e passamos cada um deles para o componente <code>Article</code> para que seja mostrado.</p><p>Com isso, podemos navegar até a raiz do projeto e executar este comando:</p><pre><code class="language-shell">  yarn start
</code></pre><p>No <code>npm</code>:</p><pre><code class="language-shell">  npm start
</code></pre><p>Se você abrir <code>http://localhost:3000/</code> no navegador, deverá ver isto:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/mxuc7kv9gtkiuuxdf4hx.png" class="kg-image" alt="mxuc7kv9gtkiuuxdf4hx" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/10/mxuc7kv9gtkiuuxdf4hx.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/10/mxuc7kv9gtkiuuxdf4hx.png 752w" sizes="(min-width: 720px) 720px" width="752" height="725" loading="lazy"></figure><p>Ótimo! Nossa aplicação está funcionando. Com isso, terminamos de mostrar o uso do Redux em uma aplicação do React com TypeScript.</p><p>Você pode encontrar o projeto completo <a href="https://codesandbox.io/s/react-redux-typescript-oc4hi">nesta CodeSandbox</a>.</p><p>Você pode encontrar outros conteúdos excelentes como este no <a href="https://www.ibrahima-ndaw.com/">blog do autor</a> ou segui-lo no <a href="https://twitter.com/ibrahima92_">Twitter</a> para ser notificado sobre novos textos produzidos por ele.</p><p>Obrigado pela leitura.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 10 novos recursos do ES2020 para o JavaScript que você precisa conhecer ]]>
                </title>
                <description>
                    <![CDATA[ Boas notícias – os novos recursos do ES2020 já estão disponíveis! Isso significa que agora temos uma visão completa das mudanças que ocorreram com a chegada do ES2020, a nova e aprimorada especificação do JavaScript. Então, vamos ver quais mudanças foram essas! Nº 1: BigInt BigInt, um dos recursos mais ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/10-novos-recursos-do-es2020-para-o-javascript-que-voce-precisa-conhecer/</link>
                <guid isPermaLink="false">62dc746cfea2f10707d67119</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Gabriel Galdino ]]>
                </dc:creator>
                <pubDate>Mon, 05 Sep 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/es2020logo.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/javascript-new-features-es2020/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">10 New JavaScript Features in ES2020 That You Should Know</a>
      </p><p>Boas notícias – os novos recursos do ES2020 já estão disponíveis! Isso significa que agora temos uma visão completa das mudanças que ocorreram com a chegada do ES2020, a nova e aprimorada especificação do JavaScript. Então, vamos ver quais mudanças foram essas!</p><h1 id="n-1-bigint"><strong>Nº 1: BigInt</strong></h1><p>BigInt, um dos recursos mais esperados no JavaScript, finalmente chegou. Ele permite que os desenvolvedores tenham a representação de um inteiro, escrito em JS, muito maior para processamento de dados à medida que você os manipula.</p><p>No momento, o número máximo que você pode armazenar como um inteiro em JavaScript é <code>pow(2, 53) - 1</code> . Com o BigInt, porém, você consegue muito mais.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.21.47-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.21.47-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.21.47-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.21.47-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.21.47-PM.png 1218w" sizes="(min-width: 720px) 720px" width="1218" height="1270" loading="lazy"></figure><p>Entretanto, você precisa ter um &nbsp;<code>n</code> anexado no final do número, como pode ver acima. Este <code>n</code> significa que o número é um BigInt e deve ser tratado de modo diferente pela JavaScript Engine (pela engine v8 ou qualquer engine que esteja usando).</p><p>Essa melhoria não é compatível com versões anteriores, pois o sistema numérico tradicional é o IEEE754 (que não suporta números desse tamanho).</p><h1 id="n-2-importa-o-din-mica"><strong>Nº 2: Importação dinâmica</strong></h1><p>As importações dinâmicas (em inglês, <em>dynamic imports</em>) em JavaScript oferecem a opção de importar arquivos em JS de modo dinâmico, como módulos em sua aplicação nativa. Ou seja, a mesma coisa que você consegue fazer com o Webpack e o Babel no momento.</p><p>Esse recurso ajudará você a enviar código de solicitação sob demanda, mais conhecido como <em>code splitting</em> (divisão de código), sem a sobrecarga do Webpack ou de outros empacotadores de módulos. Se preferir, você também pode carregar código de modo condicional em um bloco <em>if-else</em>.</p><p>O interessante é que você está realmente importando o módulo e, portanto, evitando de poluir o namespace global.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.26.27-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.26.27-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.26.27-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.26.27-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2022/08/Screenshot-2020-04-03-at-8.26.27-PM.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.26.27-PM.png 1612w" sizes="(min-width: 720px) 720px" width="1612" height="234" loading="lazy"></figure><h1 id="n-3-coalesc-ncia-nula"><strong>Nº 3: Coalescência nula</strong></h1><p>A coalescência nula (em inglês, <em>nullish coalescing</em>) adiciona a capacidade de verificar verdadeiramente valores <code>nullish</code> em vez de valores <code>falsey</code>. Nesse ponto, você pode se perguntar: qual é a diferença entre valores <code>nullish</code> e <code>falsey</code>?</p><p>Em JavaScript, muitos valores são <code>falsey</code>, como strings vazias, o número 0, <code>undefined</code>, <code>null</code>, <code>false</code>, <code>NaN</code> e assim por diante.</p><p>No entanto, muitas vezes, você pode querer verificar se uma variável é nula – isto é, se é <code>undefined</code> ou <code>null</code>, como quando não há problema em uma variável ter uma string vazia ou até mesmo um valor falso.</p><p>Nesse caso, você usará o novo operador de "coalescência nula", <code>??</code></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.47.03-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.47.03-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.47.03-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.47.03-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.47.03-PM.png 1156w" sizes="(min-width: 720px) 720px" width="1156" height="1330" loading="lazy"></figure><p>Você pode ver claramente como o operador OR sempre retorna um valor verdadeiro, enquanto o operador nulo retorna um valor não nulo.</p><h1 id="n-4-encadeamento-opcional"><strong>Nº 4: Encadeamento opcional</strong></h1><p>A sintaxe do encadeamento opcional (do inglês, <em>optional chaining</em>) permite que você acesse propriedades de objetos profundamente aninhados sem se preocupar se a propriedade existe ou não. Se existir, ótimo! Caso contrário, será retornado um <code>undefined</code>.</p><p>Isso não funciona apenas em propriedades de objetos, mas também em chamadas de funções e arrays. Muito conveniente! Aqui está um exemplo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.51.58-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.51.58-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.51.58-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.51.58-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.51.58-PM.png 1332w" sizes="(min-width: 720px) 720px" width="1332" height="606" loading="lazy"></figure><h1 id="n-5-promise-allsettled"><strong>Nº 5: Promise.allSettled</strong></h1><p>O método <code>Promise.allSettled</code> aceita um array de Promises e só o resolve quando todas as <em>Promises</em> são resolvidas ou rejeitadas.</p><p>Isso não estava disponível de modo nativo antes, embora algumas implementações próximas, como <code>race</code> e <code>all</code>, já estivessem disponíveis. </p><p>Agora, é possível "apenas executar todas as Promises - sem se importar com os resultados" nativamente para o JavaScript.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.54.58-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.54.58-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.54.58-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.54.58-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2022/08/Screenshot-2020-04-03-at-8.54.58-PM.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.54.58-PM.png 1614w" sizes="(min-width: 720px) 720px" width="1614" height="1456" loading="lazy"></figure><h1 id="n-6-string-matchall"><strong>Nº 6: String#matchAll</strong></h1><p><code>matchAll</code> é um novo método adicionado ao protótipo <code>String</code>, que está relacionado a Expressões Regulares. Ele retorna um iterador, que, por sua vez, retorna todos os grupos correspondentes, um após o outro. Vejamos um exemplo simples:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.59.14-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-8.59.14-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-8.59.14-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-8.59.14-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-8.59.14-PM.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="638" loading="lazy"></figure><h1 id="n-7-globalthis"><strong>Nº 7: globalThis</strong></h1><p>Se você escrevesse algum código JS multiplataforma que pudesse ser executado no Node, no ambiente do navegador e também dentro de web-workers, você teria dificuldade em obter o objeto global.</p><p>Isso ocorre porque o ambiente global é <code>window</code> para os navegadores, <code>global</code> para Node e <code>self</code> para os web-workers. Se houver mais tempos de execução, o objeto global também será diferente para eles.</p><p>Então, você precisaria ter sua própria implementação de detecção de tempo de execução e então usar o global correto – ao menos, até agora.</p><p>O ES2020 nos traz <code>globalThis</code>, que sempre se refere ao objeto global, não importando onde você esteja executando seu código:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-9.02.27-PM.png" class="kg-image" alt="Screenshot-2020-04-03-at-9.02.27-PM" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/08/Screenshot-2020-04-03-at-9.02.27-PM.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/08/Screenshot-2020-04-03-at-9.02.27-PM.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/08/Screenshot-2020-04-03-at-9.02.27-PM.png 1296w" sizes="(min-width: 720px) 720px" width="1296" height="240" loading="lazy"></figure><h1 id="n-8-m-dulo-namespace-exports"><strong>Nº 8: Módulo Namespace Exports</strong></h1><p>Nos módulos do JavaScript, já era possível utilizar a seguinte sintaxe:</p><pre><code class="language-js">import * as utils from './utils.mjs'</code></pre><p>No entanto, nenhuma sintaxe de <code>export</code> simétrica existia, até agora:</p><pre><code class="language-js">export * as utils from './utils.mjs'</code></pre><p>A linha acima equivale a:</p><pre><code class="language-js">import * as utils from './utils.mjs'
export { utils }</code></pre><h1 id="n-9-ordem-de-entrada-bem-definida"><strong>Nº 9: </strong>Ordem de entrada bem definida</h1><p>A especificação ECMA não definiu em qual ordem <code>for (x in y)</code> &nbsp;deve ser executado. Embora os navegadores tenham implementado uma ordem consistente por conta própria até então, isso foi oficialmente padronizado no ES2020.</p><h1 id="n-10-import-meta"><strong>Nº 10: import.meta</strong></h1><p>O objeto <code>import.meta</code> foi criado pela implementação do ECMAScript com um protótipo <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null"><code>null</code></a>.</p><p>Considere um módulo, <code>module.js</code>:</p><pre><code class="language-html">&lt;script type="module" src="module.js"&gt;&lt;/script&gt;
</code></pre><p>Você pode acessar as metainformações sobre o módulo usando o objeto <code>import.meta</code>:</p><pre><code class="language-js">console.log(import.meta); // { url: "file:///home/user/module.js" }</code></pre><p>Ele retorna um objeto com uma propriedade <code>url</code> indicando o URL de base do módulo. Este será o URL a partir do qual o script foi obtido (para scripts externos) ou o URL de base do documento que o contém (para scripts incorporados).</p><h1 id="conclus-o"><strong>Conclusão</strong></h1><p>Adoro a consistência e a velocidade na qual a comunidade do JavaScript evoluiu e está evoluindo. É realmente incrível e maravilhoso ver como o JavaScript veio de uma linguagem que era bastante criticada, há 10 anos, para uma das linguagens mais fortes, flexíveis e versáteis atualmente.</p><p>Você deseja aprender JavaScript e outras linguagens de programação de uma maneira completamente nova? Acesse a <a href="https://codedamn.com/">nova plataforma para desenvolvedores</a> na qual o autor está trabalhando atualmente e teste-a.</p><p>Qual é o seu recurso favorito do ES2020? Informe o autor por meio de mensagem ou conecte-se com ele pelo <a href="https://twitter.com/mehulmpt">Twitter</a> ou pelo <a href="https://instagram.com/mehulmpt">Instagram</a>!</p><p>Este artigo é baseado em um vídeo do autor sobre o mesmo tópico. Seria muito importante para ele que você apoiasse esse material, curtindo-o e compartilhando-o.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/Fag_8QjBwtY?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="What's new in ES2020? New JavaScript Features" name="fitvid0"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
