<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ricardo Mello</title>
    <description>The latest articles on DEV Community by Ricardo Mello (@ricmello).</description>
    <link>https://dev.to/ricmello</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F307303%2F52baee3f-b6b4-4e36-a93b-e1fb75f7903b.jpeg</url>
      <title>DEV Community: Ricardo Mello</title>
      <link>https://dev.to/ricmello</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ricmello"/>
    <language>en</language>
    <item>
      <title>O código não se tornou commodity após a AI. Ele sempre foi</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Tue, 24 Feb 2026 01:00:17 +0000</pubDate>
      <link>https://dev.to/ricmello/o-codigo-nao-se-tornou-commodity-apos-a-ai-ele-sempre-foi-3605</link>
      <guid>https://dev.to/ricmello/o-codigo-nao-se-tornou-commodity-apos-a-ai-ele-sempre-foi-3605</guid>
      <description>&lt;p&gt;Recentemente eu li algumas notícias apocalípticas sobre a profissão de desenvolvimento após o advento da AI, como &lt;a href="https://medium.com/chris-messina/code-as-commodity-b9b7492dc4eb" rel="noopener noreferrer"&gt;esse post&lt;/a&gt; do Chris Messina dizendo que código se tornou uma commodity, ou o CEO da Microsoft AI dizendo &lt;a href="https://fortune.com/2026/02/13/when-will-ai-kill-white-collar-office-jobs-18-months-microsoft-mustafa-suleyman" rel="noopener noreferrer"&gt;nesse artigo da Fortune&lt;/a&gt; que dá 18 meses pra automatizar todas as profissões de colarinho branco, incluindo a nossa.&lt;/p&gt;

&lt;p&gt;Não adianta, basta surgir uma tecnologia disruptiva que os profetas do apocalipse e a galera do hype surgem em pé de guerra. Na prática, toda ferramenta que reduz fricção na criação de software gera um certo pânico no mercado, mas depois vira uma infraestrutura invisível.&lt;/p&gt;

&lt;p&gt;O mercado de tecnologia é feito de ciclos, e quem tá nessa há mais tempo sabe bem do que eu estou falando. Delphi, Visual Basic, Dreamweaver, WordPress, low-code, no-code... Todos eles prometeram a mesma coisa: &lt;strong&gt;permitir que um único desenvolvedor faça o trabalho de um time inteiro&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;E aqui estamos, 20 anos depois, ouvindo a mesma história de novo.&lt;/p&gt;

&lt;h2&gt;
  
  
  A commodity código
&lt;/h2&gt;

&lt;p&gt;Um dos exemplos mais conhecidos sobre comoditização é o sal, que era considerado um artigo precioso, causou guerras e ergueu impérios, mas hoje é baratinho no mercado e qualquer um pode comprar.&lt;/p&gt;

&lt;p&gt;O sal se tornou barato, mas cozinhar não se tornou uma commodity. A skill de saber o que fazer com os ingredientes é o que realmente importa.&lt;/p&gt;

&lt;p&gt;O código sempre foi algo básico. Qualquer aluno de primeiro período de faculdade ou de curso técnico consegue criar instruções básicas, rodar um algoritmo e criar um software pequeno. Eu programava desde os treze anos de idade, enquanto meu irmão mais novo o faz desde os oito. &lt;/p&gt;

&lt;p&gt;Engenheiros, por exemplo, já usam o tal "disposable software" há muito tempo, criando algoritmos pra resolver cálculos quando o matlab não consegue. Pessoas criavam sistemas inteiros na década de 90 usando MS Access, Delphi, VB e similares.&lt;/p&gt;

&lt;p&gt;O que mudou de lá pra cá foi que software se tornou algo muito complexo, e na maioria das vezes um complexo totalmente desnecessário.&lt;/p&gt;

&lt;p&gt;O que a IA realmente reduziu foi o custo da produção de código sintático, como boilerplates. O custo de decisão arquitetural continua o mesmo, senão maior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Os vendedores de complexidade
&lt;/h2&gt;

&lt;p&gt;Eu nunca escrevi aplicações em Ruby, mas tive que ver &lt;a href="https://www.youtube.com/watch?v=gcwzWzC7gUA" rel="noopener noreferrer"&gt;esse keynote&lt;/a&gt; do DHH na RubyConf onde ele mencionou um termo que eu achei sensacional: "merchants of complexity".&lt;/p&gt;

&lt;p&gt;Desenvolver código se tornou algo muito complicado e a culpa também é nossa. Muitas empresas acham que precisam separar frontend e backend porque todo mundo tá fazendo e elas não querem ficar pra trás. Isso faz algumas empresas precisarem de um arquiteto, 2 devs backend, 1 dev frontend, DevOps, dois ciclos de QA, PM, entre outros, pra subir uma tela de login básica em 3 meses pra um volume ridículo de usuários.&lt;/p&gt;

&lt;p&gt;Se os LLMs vão mudar isso? Com certeza vão, mas não é o fim do mundo.&lt;/p&gt;

&lt;p&gt;As mesmas empresas que criaram essa complexidade desnecessária agora estão vendendo a solução. Enquanto o Suleyman disse que vai automatizar tudo em um ano e meio, o mesmo artigo da Fortune traz um estudo da METR que diz que a AI está causando o efeito contrário e deixando os devs 20% mais lentos. Na prática são executivos vendendo um produto. A Borland fez isso com o Delphi, enquanto a Microsoft fez a mesma coisa com o VB.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que não é commodity
&lt;/h2&gt;

&lt;p&gt;Se código sempre foi commodity, o que não é commodity de fato?&lt;/p&gt;

&lt;p&gt;Saber &lt;strong&gt;o que fazer&lt;/strong&gt;, &lt;strong&gt;por que fazer&lt;/strong&gt;, e como fazer isso &lt;strong&gt;sobreviver em produção no longo prazo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A AI pode criar o melhor código pra uma situação, quando na verdade a decisão deveria ter sido remover aquele código, ou em outro cenário ela pode criar uma implementação redundante que vai causar gargalos de desempenho em produção.&lt;/p&gt;

&lt;p&gt;Mesmo um dev senior usando AI precisa de julgamento técnico pra tomar as decisões certas. Ela não conhece todas as suas regras de negócio, seus SLAs, ou por que aquele "refactoring bobo" vai quebrar três outros serviços. Nunca foi sobre code vs no-code, mas ser um dev ou um mero digitador.&lt;/p&gt;

&lt;h2&gt;
  
  
  Um novo ciclo
&lt;/h2&gt;

&lt;p&gt;Devs generalistas vão ascender e ter novamente a possibilidade de criar software em escala para problemas reais, enquanto devs backend que não fazem a mínima ideia de como funciona a aplicação pra qual eles criam APIs, ou devs frontend que não sabem o básico de como o backend funciona vão perder espaço. Um dev fullstack usando Claude Code ou Cursor consegue prototipar em dias (ou horas) o que antes precisava de um squad inteiro durante semanas.&lt;/p&gt;

&lt;p&gt;Eu enxergo essas mudanças como o início de um novo ciclo, onde saber fazer código não é o suficiente. Mas pra mim e pra vários desenvolvedores do mercado, nunca foi. A nossa profissão sempre foi mais intelectual do que braçal e isso meus amigos, não é commodity.&lt;/p&gt;

&lt;p&gt;Eu uso LLMs diariamente e realmente enxergo a AI como uma ferramenta poderosa para potencializar o desenvolvimento de aplicações por parte de desenvolvedores que levam ao mercado a sério. Porém, eu enxergo esta mesma AI como uma bomba nas mãos de quem não entende os conceitos básicos de desenvolvimento de software. Simplesmente porque quando a gente atinge o limite de até onde ela consegue ir, é o primeiro grupo que vai saber o que fazer, enquanto o segundo vai precisar abrir um ticket de suporte no lovable.&lt;/p&gt;

&lt;p&gt;Então basicamente o que está acontecendo não é uma desvalorização acentuada do código ou da profissão de desenvolvedor, mas um novo ciclo que está começando seguindo os mesmos princípios que já vivemos antes. Essa ferramenta é mais poderosa do que todas as outras, mas todas as outras também foram as mais poderosas de suas épocas.&lt;/p&gt;

&lt;p&gt;Se você sobreviveu ao Delphi, ao jQuery, ao Angular 1 vs 2 (ou ao React), ao hype do blockchain, você vai sobreviver a esse também.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>AI Agents, Comandos de Voz e uma nova forma de criar software</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Thu, 19 Jun 2025 03:33:09 +0000</pubDate>
      <link>https://dev.to/ricmello/ai-agents-comandos-de-voz-e-uma-nova-forma-de-criar-software-4i38</link>
      <guid>https://dev.to/ricmello/ai-agents-comandos-de-voz-e-uma-nova-forma-de-criar-software-4i38</guid>
      <description>&lt;p&gt;A forma que a gente trabalha há muito tempo não me parece a ideal. Eu posso até não ter achado a forma ideal ainda, mas eu continuo nessa procura. Eu realmente acho que depois de a tecnologia evoluir tanto, a gente não precisa mais trabalhar como datilógrafos do século passado.&lt;/p&gt;

&lt;p&gt;Se você parar pra observar o quanto o nosso modelo de trabalho evoluiu nos últimos anos comparado às tecnologias que a gente desenvolve, você vai notar um gap muito grande. A gente desenvolveu aplicações distribuídas, blockchain, inteligência artificial, visão computacional, e muitas outras coisas absurdamente incríveis, ao mesmo tempo que nós continuamos fazendo isso sentados (alguns de pé) escrevendo em uma tela branca – pode me zoar, eu não uso dark mode.&lt;/p&gt;

&lt;p&gt;Os softwares de reconhecimento de voz eram horríveis sim, mas o Ditado do Mac não é mais aquela coisa primitiva que rodava em um Symbian. E se você não conhece o Symbian, me avisa pra eu parar de usar exemplos velhos.&lt;/p&gt;

&lt;p&gt;Eu imagino que essas ferramentas só vão melhorar ao longo do tempo, e sinceramente eu não quero ficar parado no tempo fazendo coisas como eu fazia lá em 2010. Te convido a fazer o mesmo.&lt;/p&gt;

&lt;p&gt;Tenho testado algumas formas diferentes de trabalhar nesses últimos anos. Isso inclui inteligência artificial, comandos de voz, e até o amado/odiado vibe coding. Quero compartilhar dois pontos que estão mudando a minha forma de trabalhar, e talvez mude a sua também.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. AI Agents
&lt;/h2&gt;

&lt;p&gt;A menos que você esteja vivendo em uma caverna, você já deve ter ouvido falar de AI Agents. Resumindo de uma forma bem rasa, um AI agent é um ChatGPT turbinado que executa tarefas de forma autônoma direto na sua IDE. Ele cria features, altera arquivos e roda comandos com um único prompt, o que te permite realizar mudanças significativas em segundos.&lt;/p&gt;

&lt;p&gt;AI Agents são o presente, e eu recomendo fortemente que façam parte do seu workflow. Dependendo da linguagem você pode querer usar uma IDE com o AI Agent e outra que você se sentir mais confortável pra programar, mas vale muito a pena. O ganho de produtividade é absurdo, e do momento que você cria o seu próprio framework com o &lt;a href="https://docs.cursor.com/context/rules" rel="noopener noreferrer"&gt;Cursor Rules&lt;/a&gt; ou similar, o Agent começa a gerar um código bem parecido com o que você escreveria.&lt;/p&gt;

&lt;p&gt;Pensando em time, você também consegue adicionar essas regras ao repositório, e outras pessoas do time usando AI Agents terão resultados parecidos. Você também pode pedir uma revisão de código pro seu Agent baseado nas regras antes de submeter pra revisão do time.&lt;/p&gt;

&lt;p&gt;A lista de prós é extensa, e vale o teste. Minha lista de AI Agents favoritos tem: &lt;a href="https://www.cursor.com" rel="noopener noreferrer"&gt;Cursor&lt;/a&gt;, &lt;a href="https://github.com/features/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt; e &lt;a href="https://windsurf.com" rel="noopener noreferrer"&gt;WindSurf&lt;/a&gt;. O &lt;a href="https://docs.anthropic.com/en/docs/claude-code/overview" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; é muito bom, mas ele roda no terminal e não na IDE. &lt;/p&gt;

&lt;p&gt;P.S.: Se alguém usa a &lt;a href="https://www.jetbrains.com/ai/" rel="noopener noreferrer"&gt;AI da JetBrains&lt;/a&gt;, defende ela aqui porque eu não curti muito.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Ditado e comandos de voz
&lt;/h2&gt;

&lt;p&gt;Algo relativamente antigo, genérico e que funciona em várias aplicações diferentes é o Ditado. A proposta é bem simples: você consegue escrever falando. Isso serve pra mandar mensagens, pedir pra inteligência artificial criar alguma coisa, ou pedir pra Siri tocar uma música. Isso vai te fazer pensar duas vezes antes de mandar aquele áudio que poderia ser uma mensagem.&lt;/p&gt;

&lt;p&gt;Eu não sou um heavy user da Siri, tenho conhecimento muito básico de assistentes, e mantenho o "Hey Siri" desativado porque eu ainda sou meio bolado com um celular ou computador me ouvindo o tempo todo, mas tenho mudado minha cabeça quanto isso porque eu acho algo inevitável.&lt;/p&gt;

&lt;p&gt;"Ah mas o ChatGPT tem modo voz". Concordo totalmente, mas o modo de voz do ChatGPT não vai abrir o seu WhatsApp e mandar uma mensagem (ainda), ou escrever algo dentro da sua IDE. Se você aliar o ditado do mac ou do Windows a uma IDE com AI Agent, você vai simplesmente abrir uma classe de entity, e dizer em voz alta "create a repository for this entity". Voilà. O AI Agent vai começar criar.&lt;/p&gt;

&lt;p&gt;Eu não sei dizer a qualidade dos prompts em português, mas no teste que eu fiz funcionou perfeitamente. Até porque os modelos usados são o Claude, GPT, Gemini, e outros grandes que a gente já usa no dia a dia.&lt;/p&gt;

&lt;p&gt;Aqui vão os links sobre como habilitar o modo de ditado: &lt;a href="https://support.apple.com/pt-br/guide/mac-help/mh40584/mac" rel="noopener noreferrer"&gt;macOS&lt;/a&gt; e &lt;a href="https://support.microsoft.com/pt-br/windows/usar-a-digita%C3%A7%C3%A3o-por-voz-para-falar-em-vez-de-digitar-no-seu-computador-fec94565-c4bd-329d-e59a-af033fa5689f" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Falar com uma AI, ver ela programando e só revisar o resultado me faz sentir o Homem de Ferro falando com o Jarvis. Eu acho algo incrível e que só tem a melhorar no futuro.&lt;/p&gt;

&lt;p&gt;A maioria dessas ferramentas possuem um período de testes gratuito, então vale muito a pena fazer um teste. Te garanto que você vai curtir um bocado. Dica: O Claude é meu modelo favorito mesmo no GitHub Copilot, mas embora eu tenha usado o Copilot desde os betas, hoje eu tô no time do Cursor.&lt;/p&gt;

&lt;p&gt;Ainda me vejo escrevendo prompts muito mais pelo costume do que pela facilidade. Mudar a forma de trabalhar depois de mais de uma década é complicado. E se você tem LER, que são aquelas lesões por esforço repetitivo, isso vai te ajudar um bocado a digitar menos e aliviar elas também – mas não esqueça da fisioterapia.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Web Components com Preact</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Fri, 26 Apr 2024 01:14:44 +0000</pubDate>
      <link>https://dev.to/ricmello/web-components-com-preact-2hhj</link>
      <guid>https://dev.to/ricmello/web-components-com-preact-2hhj</guid>
      <description>&lt;p&gt;O Preact se intitula como "Fast 3kB alternative to React with the same modern API". E na minha opinião, ele tá se subestimando. Não é minha intenção entrar em uma comparação de React vs Preact, mas a performance dele a possibilidade de criar web components são duas grandes vantagens. É esse segundo ponto que vamos abordar hoje.&lt;/p&gt;

&lt;p&gt;Eu escolhi o Preact ao invés de outras libs como Lit ou Stencil porque além de ele ser muito leve e possuir uma ótima performance, os componentes são iguais aos do React, o que significa uma curva de aprendizado muito pequena caso o seu time já conheça React. Você consegue criar uma lib agnóstica sem abrir mão do TSX/JSX, hooks, e tudo aquilo que faz o React ser o que ele é, o que na minha opinião faz o Preact ser o melhor dos dois mundos no desenvolvimento de bibliotecas.&lt;/p&gt;

&lt;p&gt;Por último, mas não menos importante, o Preact já oferece suporte nativo aos Signals, que te permite criar um gerenciamento de estado atômico e, mais uma vez, muito performático.&lt;/p&gt;




&lt;h2&gt;
  
  
  O projeto
&lt;/h2&gt;

&lt;p&gt;O nosso objetivo vai ser bem simples, que é transformar um componente de counter em um web component. Sabe aquele counter que aparece quando você gera uma aplicação com o vite? Ele mesmo. Vamos usar uma técnica simples pra transformar esse cara em um web component que pode ser utilizado em qualquer lugar, inclusive em um HTML comum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mão na massa
&lt;/h2&gt;

&lt;p&gt;Pra esse exemplo eu criei um projeto Preact no &lt;a href="https://stackblitz.com"&gt;Stackblitz&lt;/a&gt; e vou alterá-lo para exportar e renderizar os web components. Se preferir, você também pode criar um projeto local usando o &lt;a href="https://preactjs.com/guide/v10/getting-started"&gt;getting started&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eu deletei o app.tsx e o app.css. Também removi o &lt;code&gt;render()&lt;/code&gt; do &lt;code&gt;main.tsx&lt;/code&gt;. Como nós vamos exportar o web component pra ser usado diretamente no HTML, não faz sentido renderizar o preact como aplicação.&lt;/p&gt;

&lt;p&gt;Pra começar, crie um componente &lt;code&gt;counter.tsx&lt;/code&gt; com o seguinte conteúdo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact/hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O pulo do gato
&lt;/h3&gt;

&lt;p&gt;Qualquer componente preact pode ser registrado como web component usando o mini wrapper &lt;a href="https://github.com/preactjs/preact-custom-element"&gt;preact-custom-element&lt;/a&gt;. Esse cara transforma o componente em Web Component seguindo a V1 da especificação Custom Elements.&lt;/p&gt;

&lt;p&gt;Pra instalar o wrapper, rode o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;preact-custom-element
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E se você está usando typescript, instale os types também:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i @types/preact-custom-element --save-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, é só usar o wrapper no componente e o código do seu counter deve ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact/hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact-custom-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{...};&lt;/span&gt;

&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ric-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Por último, exporte o componente no &lt;code&gt;main.tsx&lt;/code&gt;. Como removemos a maior parte desse arquivo, ele deve ficar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A partir daí você já consegue utilizar o seu web component no index.html:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/vite.svg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Vite + Preact + TS + Web Components&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ric-counter&amp;gt;&amp;lt;/ric-counter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.tsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Com isso, o web component será renderizado normalmente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkbio03m6aiky69opxn7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqkbio03m6aiky69opxn7.png" alt="Botão counter sendo renderizado como web component" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você deve ter notado que eu declarei a tag &lt;code&gt;&amp;lt;ric-counter&amp;gt;&amp;lt;/ric-counter&amp;gt;&lt;/code&gt; antes do import do &lt;code&gt;main.tsx&lt;/code&gt;. Isso é pra mostrar que ele consegue detectar tags que já foram declaradas antes de ele ser inicializado, o que significa que você não precisa se preocupar em carregar o js antes das tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Atributos
&lt;/h2&gt;

&lt;p&gt;Os atributos são essenciais pra permitir que a aplicação possa controlar o comportamento dos componentes, ao mesmo tempo que nós como desenvolvedores de componentes definimos o que pode ser controlado.&lt;/p&gt;

&lt;p&gt;Os web components recebem os atributos como string por padrão, então é importante ter em mente que os seus dados podem precisar ser convertidos antes da utilização. Eu considero uma boa prática fazer isso já nas primeiras linhas do componente, e trabalhar internamente com a variável no tipo que eu quiser pra sempre converter tudo em um lugar único:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact/hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact-custom-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CounterProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;label&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CounterProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Count is&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawSteps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Converto o atributo steps (rawSteps) pra number e uso como steps internamente&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawSteps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ric-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;steps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;//          ^            ^           ^                       ^&lt;/span&gt;
&lt;span class="c1"&gt;//          |         tag HTML       |                   shadow-dom&lt;/span&gt;
&lt;span class="c1"&gt;//     Componente           Atributos observados&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sempre que um atributo observado for alterado, o componente vai ser atualizado. Os atributos que não estiverem nessa lista só serão detectados caso sejam passados na inicialização.&lt;/p&gt;

&lt;p&gt;Já o shadow, é um booleano que indica se o seu componente deve usar ou não o &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM"&gt;Shadow DOM&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;O HTML com os atributos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/vite.svg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Vite + Preact + TS + Web Components&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ric-counter&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Custom count:"&lt;/span&gt; &lt;span class="na"&gt;steps=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ric-counter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.tsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora é só testar e ver um novo label e incrementando de dois em dois:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm1yusvt8z7sxtorsi3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm1yusvt8z7sxtorsi3c.png" alt="Botão counter customizado" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks
&lt;/h3&gt;

&lt;p&gt;Os callbacks são um tipo importante de atributo, afinal as pessoas que vão utilizar o nosso componente precisam saber se um botão foi clicado e/ou se o estado do componente mudou.&lt;/p&gt;

&lt;p&gt;Como os atributos de um web component são passados como strings, é preciso passar as funções de callback de uma forma diferente: via JavaScript.&lt;/p&gt;

&lt;p&gt;E pra tornar isso possível vamos adicionar uma nova propriedade ao nosso componente chamada &lt;code&gt;onChange&lt;/code&gt; e executar esse callback dentro a função de increment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact/hooks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;register&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact-custom-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;preact&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CounterProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;label&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FunctionalComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CounterProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;label&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Count is&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawSteps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawSteps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;increment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useCallback&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;increment&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ric-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;steps&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E agora no HTML, basta usar o &lt;code&gt;querySelector&lt;/code&gt; e atribuir a propriedade com a nossa função de callback:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ric-counter&lt;/span&gt; &lt;span class="na"&gt;label=&lt;/span&gt;&lt;span class="s"&gt;"Custom count:"&lt;/span&gt; &lt;span class="na"&gt;steps=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ric-counter&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.tsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ric-counter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;counter changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora é só testar e ver um console.log sendo executado cada vez que clicar no botão. Você também pode ver o resultado final no meu &lt;a href="https://stackblitz.com/edit/vitejs-vite-nuvqqa"&gt;Stackblitz&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Poder utilizar um web component direto no HTML abre portas pra muitos casos reais de uso. Você pode exportar os seus componentes pra serem incluídos em sites wordpress, ou até mesmo criar wrappers pra outros frameworks e reutilizar o seu código em diferentes interfaces.&lt;/p&gt;

&lt;p&gt;Como eu disse antes &lt;a href="https://dev.to/ricmello/web-components-e-a-minha-opiniao-sobre-o-futuro-das-libs-front-end-181l"&gt;nesse post&lt;/a&gt;, eu não acho que valha a pena desenvolver aplicações inteiras usando web components podendo usar direto o preact ou outro framework, mas se o seu contexto é libs, widgets, ou qualquer tipo de componente que é incorporado em outro website (por exemplo um chat), essa abordagem vai fazer muito sentido.&lt;/p&gt;




&lt;p&gt;Se você curte o assunto e gostaria de ver mais posts desses por aqui, me avisa porque é algo que eu tenho gostado bastante de estudar, e acho que realmente vale a pena o investimento.&lt;/p&gt;

&lt;p&gt;E se você não gostou de alguma coisa, ou tem alguma sugestão que possa fazer esse e os próximos artigos menores, lança aqui nos comentários também. Todo comentário é bem vindo e as críticas vão me ajudar a aprimorar os próximos posts 🙂&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Web Components e a minha opinião sobre o futuro das libs front-end</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Thu, 04 Apr 2024 12:50:36 +0000</pubDate>
      <link>https://dev.to/ricmello/web-components-e-a-minha-opiniao-sobre-o-futuro-das-libs-front-end-181l</link>
      <guid>https://dev.to/ricmello/web-components-e-a-minha-opiniao-sobre-o-futuro-das-libs-front-end-181l</guid>
      <description>&lt;p&gt;Eu tô ficando velho. E como todo velho, eu ganho licença poética pra prever eventos futuros baseados em eventos passados. Tem dia que eu sei que vai chover, tem dia que eu sei que vai ser bom, e tem dia que eu consigo escrever.&lt;/p&gt;

&lt;p&gt;Eu tenho trabalhado bastante com web components nos últimos anos, e tô realmente impressionado com o quanto eu consegui escalar o desenvolvimento das minhas libs depois que eu passei a utilizá-los, então esse post é pra compartilhar minha experiência e explicar por que eu acredito que o futuro das libs é por esse caminho.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tá, mas o que são web components?
&lt;/h2&gt;

&lt;p&gt;Eu copiei essa definição do &lt;a href="https://developer.mozilla.org/pt-BR/docs/Web/API/Web_components" rel="noopener noreferrer"&gt;site da Mozilla&lt;/a&gt; (MDN): Web Components é uma suíte de diferentes tecnologias que permite a criação de elementos customizados reutilizáveis — com a funcionalidade separada do resto do seu código — e que podem ser utilizados em suas aplicações web.&lt;/p&gt;

&lt;p&gt;E a minha explicação de dev simplão é: Web Components são componentes similares aos do react, angular, etc, mas que rodam em qualquer lugar e são nativos do browser. Você cria um componente &lt;code&gt;&amp;lt;ric-header&amp;gt;&amp;lt;/ric-reader&amp;gt;&lt;/code&gt; e pode usar em qualquer lugar que vai funcionar, assim como o nosso bom e velho javascript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Em qualquer lugar?
&lt;/h2&gt;

&lt;p&gt;Sim. Na &lt;del&gt;p$#%@&lt;/del&gt; coisa toda. Você pode usar o mesmo componente em um site wordpress, em um site HTML igual aos que eu fazia em 2010, ou em uma SPA react/angular/seuframeworkaqui.&lt;/p&gt;

&lt;p&gt;Os Web Components são nativos do browser, e por isso você não precisa de nenhuma mágica para renderizar. Desde que um browser moderno seja utilizado, você realmente pode utilizar o web component em uma página HTML básica ou integrar ao seu site em React.&lt;/p&gt;

&lt;p&gt;E sobre browsers modernos, &lt;a href="https://caniuse.com/custom-elementsv1" rel="noopener noreferrer"&gt;aqui está a especificação do caniuse&lt;/a&gt;. Todos os browsers atuais são compatíveis, com exceção do nosso já conhecido Opera Mini e &lt;a href="https://bugs.webkit.org/show_bug.cgi?id=182671" rel="noopener noreferrer"&gt;desse "bug"&lt;/a&gt; no Safari.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvatsu0r9a76qct8hjnzu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvatsu0r9a76qct8hjnzu.png" alt="Tabela de suporte dos navegadores aos web components: all green"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug no Safari?
&lt;/h3&gt;

&lt;p&gt;Na verdade é a falta de suporte ao atributo &lt;code&gt;is=""&lt;/code&gt;, e que está categorizada como WONTFIX no bugzilla. Nessa especificação, nós poderíamos customizar as tags nativas do HTML com esse atributo. Porém, não vai impactar em muita coisa porque podemos alcançar o mesmo resultado de outra forma.&lt;/p&gt;

&lt;p&gt;Em resumo, você poderia registrar usar um componente de parágrafo customizado assim:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;word-count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WordCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;E utilizar o componente com esse código:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;is=&lt;/span&gt;&lt;span class="s"&gt;"word-count"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Porém, o mesmo comportamento pode ser alcançado registrando um novo componente assim:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;customElements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;word-count&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;WordCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;E usando o componente:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;word-count&amp;gt;&amp;lt;/word-count&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Eu sei que a gente perde um pouco da flexibilidade por precisar de uma tag nova, mas não tem muito o que fazer a não ser reclamar na issue pra ver se a galera do safari implementa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Casos de uso
&lt;/h2&gt;

&lt;p&gt;E se você está se perguntando pra que criar uma tag customizada nativa do browser se o seu React/Angular já faz isso dentro do framework, vamos entender onde esses componentes podem te ajudar um bocado:&lt;/p&gt;

&lt;h3&gt;
  
  
  Bibliotecas agnósticas
&lt;/h3&gt;

&lt;p&gt;Se você também trabalha desenvolvendo libs que precisam rodar em diferentes tecnologias, vale a pena olhar com carinho pra uma abordagem baseada em web components.&lt;/p&gt;

&lt;p&gt;Muitas libs do mercado já estão indo por esse caminho como o &lt;a href="https://ionicframework.com/docs/components" rel="noopener noreferrer"&gt;Ionic&lt;/a&gt;, o &lt;a href="https://swiperjs.com" rel="noopener noreferrer"&gt;Swiper&lt;/a&gt;, o &lt;a href="https://material-web.dev" rel="noopener noreferrer"&gt;Material&lt;/a&gt;, entre outros. A ideia aqui é criar a sua lib usando web components e criar wrappers pros frameworks que você quiser manter, enquanto suporta todos os outros. No caso do Swiper eles estão abandonando os wrappers também e indo pra uma abordagem full web component.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design Systems
&lt;/h3&gt;

&lt;p&gt;Uma das coisas mais difíceis no desenvolvimento de design systems é conseguir manter uma base agnóstica que sobreviva ao longo do tempo sem sofrer com clones e adaptações.&lt;/p&gt;

&lt;p&gt;Os devs da sua empresa usam Angular e a sua empresa compra uma outra empresa onde os devs usam React. Unificar as identidades visuais provavelmente vai girar em torno de clonar o Design System pra React, ou em casos mais doidos reescrever tudo pra Angular.&lt;/p&gt;

&lt;p&gt;Já com web components seria basicamente criar wrappers pro react e ir substituindo os componentes mantendo a regra de negócio (quase) intacta.&lt;/p&gt;

&lt;h3&gt;
  
  
  Micro Frontends
&lt;/h3&gt;

&lt;p&gt;Eu continuo sendo do time contra Micro Frontends (fique à vontade pra me chamar pra bater um papo e me mostrar um case maneiro), mas respeito quem usa. Exemplo similar ao de Design Systems, MFEs geralmente envolvem a utilização de mais de um framework ao mesmo tempo.&lt;/p&gt;

&lt;p&gt;E aqui, de novo, unificar os estilos entre diferentes times com diferentes frameworks é muuuito complicado. Às vezes eu navego em 3 telas do mesmo app e vejo 3 layouts diferentes, e é por conta dessa dificuldade de manter um padrão entre diferentes times com diferentes stacks de tecnologia em empresas gigantes.&lt;/p&gt;

&lt;p&gt;Os Web Components se aplicariam muito bem nesse mesmo cenário tendo uma lib de componentes única entre os times.&lt;/p&gt;

&lt;h2&gt;
  
  
  E como eu faço pra usar esse treco?
&lt;/h2&gt;

&lt;p&gt;Bom, tem várias ferramentas por aí que vão te dar o mesmo resultado. Vale testar a que for melhor pro seu cenário, mas eu vou te dar algumas ideias:&lt;/p&gt;

&lt;p&gt;Se o seu forte é Angular, o &lt;a href="https://angular.dev/guide/elements" rel="noopener noreferrer"&gt;Angular Elements&lt;/a&gt; é a ferramenta oficial pra isso. Porém, eu te recomendo testar o &lt;a href="https://lit.dev" rel="noopener noreferrer"&gt;Lit&lt;/a&gt; que tem uma sintaxe parecida mas é focado em Web Components. Outra opção é o &lt;a href="https://stenciljs.com/docs/getting-started" rel="noopener noreferrer"&gt;Stencyl&lt;/a&gt;, que é feito pela galera do Ionic.&lt;/p&gt;

&lt;p&gt;Agora, se o seu forte é React, o suporte nativo só vai vir na v19 (&lt;a href="https://github.com/facebook/react/issues/11347" rel="noopener noreferrer"&gt;acompanhe essa thread aqui&lt;/a&gt;), mas existem alguns wrappers pela comunidade que prometem o mesmo resultado. Outra opção, que eu recomendo fortemente, é o &lt;a href="https://preactjs.com/guide/v10/web-components/" rel="noopener noreferrer"&gt;preact&lt;/a&gt; que é super leve, possui a mesma sintaxe e já tem suporte nativo.&lt;/p&gt;

&lt;p&gt;E se você não está familiarizado com nenhum desses dois, vale fazer uns testes e ver qual você se adapta melhor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opinião sobre o futuro do desenvolvimento front-end
&lt;/h2&gt;

&lt;p&gt;Eu acredito fortemente que as bibliotecas que usamos serão mais focadas em web components e menos em frameworks. O Swiper e o Ionic são bons exemplo disso e têm evoluído bastante.&lt;/p&gt;

&lt;p&gt;Isso permitiria à galera do Angular, por exemplo, usar vários componentes que hoje são exclusivos do React e vice-versa. Outro ganho é que as pessoas que hoje mantém libs para os dois frameworks poderiam concentrar os esforços em uma lib universal, usando o tempo livre pra tomar uma cerveja ou criar novas libs.&lt;/p&gt;

&lt;p&gt;Eu não acho que valha a pena desenvolver uma aplicação comum com web components, porque os frameworks realmente aceleram o desenvolvimento e colocar mais uma camada no meio pode não ser muito inteligente. &lt;/p&gt;

&lt;p&gt;Porém, se você trabalha com libs, times cross, e/ou precisa ter uma base sólida de componentes, esse é o caminho. Eu tenho usado o preact onde vários sites de clientes usam os mesmos componentes e o resultado tem sido muito bom.&lt;/p&gt;




&lt;p&gt;Se você curte o assunto e gostaria de ver mais posts desses por aqui, me avisa porque é algo que eu tenho gostado bastante de estudar, e acho que realmente vale a pena o investimento.&lt;/p&gt;

&lt;p&gt;E se você não gostou de alguma coisa, ou tem alguma sugestão que possa fazer esse e os próximos artigos menores, lança aqui nos comentários também. Todo comentário é bem vindo e as críticas vão me ajudar a aprimorar os próximos posts 🙂&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Adicionando domínio customizado a uma Lambda com o API Gateway</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Wed, 27 Mar 2024 23:43:27 +0000</pubDate>
      <link>https://dev.to/aws-builders/adicionando-dominio-customizado-a-uma-lambda-com-o-api-gateway-1p5g</link>
      <guid>https://dev.to/aws-builders/adicionando-dominio-customizado-a-uma-lambda-com-o-api-gateway-1p5g</guid>
      <description>&lt;p&gt;Já tem tempos que eu não escrevo então me desculpa porque perdi um pouco o jeito, mas hoje eu vou compartilhar algo super simples que eu nunca tinha feito: adicionar um domínio customizado pra uma AWS Lambda.&lt;/p&gt;

&lt;p&gt;Se você nunca criou uma lambda, te recomendo &lt;a href="https://dev.to/ricmello/como-criar-um-backend-pro-seu-frontend-com-aws-lambdas-5fk9"&gt;esse post aqui&lt;/a&gt; que eu acabei de criar.&lt;/p&gt;

&lt;p&gt;Agora, nós vamos adicionar um domínio customizado pra ela.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mas por que usar um domínio customizado?
&lt;/h2&gt;

&lt;p&gt;E por que não usar? Parece que um gato sobe no teclado sempre que a gente gera um link de uma lambda. Links como  &lt;a href="https://dz4y7rvv2az4iopdqzvgneefhy0jdfii.lambda-url.us-east-1.on.aws" rel="noopener noreferrer"&gt;https://dz4y7rvv2az4iopdqzvgneefhy0jdfii.lambda-url.us-east-1.on.aws&lt;/a&gt; ou &lt;a href="https://lh4j4sdpmljdcrcr34gqc6ddni0qvugg.lambda-url.us-east-1.on.aws" rel="noopener noreferrer"&gt;https://lh4j4sdpmljdcrcr34gqc6ddni0qvugg.lambda-url.us-east-1.on.aws&lt;/a&gt; são gerados e ficam beeem feios quando usados no frontend.&lt;/p&gt;

&lt;p&gt;Plus, se você precisar apontar o seu link pra qualquer outro lugar (outra lambda, uma API, outra cloud...) será muito mais tranquilo e você não vai ter que atualizar a url da lambda em milhares de lugares onde ela pode estar sendo utilizada.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Gateway
&lt;/h2&gt;

&lt;p&gt;Pra atingir o nosso objetivo, vamos usar o API Gateway. Esse cara consegue organizar todas as nossas lambdas e criar mapeamentos pra elas definindo paths específicos. Isso te permite usar a lambda &lt;code&gt;nomesuperultragigante.lambda-url.us-east-1.on.aws&lt;/code&gt; como um endpoint comum &lt;code&gt;api.meuwebsite.com/v1/lambda&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando a API no API Gateway
&lt;/h2&gt;

&lt;p&gt;Pra começar, vamos criar a API que vai mapear a lambda em um endpoint no api gateway. Para isso, ainda na tela do API Gateway, vá em &lt;strong&gt;APIs &amp;gt; Create API &amp;gt; REST API&lt;/strong&gt;. Eu vou usar o nome &lt;code&gt;faker-api&lt;/code&gt; pra esse tutorial:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2pfbn70f5z39ci3as37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh2pfbn70f5z39ci3as37.png" alt="Screenshot da tela de criação de API" width="800" height="684"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com a API criada, você deve ver essa tela:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl2r79ju0uoiclpel9vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftl2r79ju0uoiclpel9vn.png" alt="Screenshot da tela de edição/configuração da API" width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources
&lt;/h3&gt;

&lt;p&gt;No API Gateway você pode realmente brincar de criação de API. Em create resources você pode ir definindo os paths por exemplo &lt;code&gt;/v1&lt;/code&gt;, depois &lt;code&gt;/v1/domain&lt;/code&gt; até chegar em &lt;code&gt;/v1/domain/endpoint&lt;/code&gt;. É uma ferramenta muito poderosa que te permite mapear todas as rotas e integrar com lambdas, apis, ou qualquer outro serviço.&lt;/p&gt;

&lt;p&gt;No nosso caso, eu vou tentar manter mais simples e criar um único resource chamado &lt;code&gt;persons&lt;/code&gt;. Para isso, vá em &lt;strong&gt;Create Resource&lt;/strong&gt;, dê o nome &lt;code&gt;persons&lt;/code&gt; pra ele, selecione a opção de CORS e clique em &lt;strong&gt;Create Resource&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0cywlyok86hh88brzgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0cywlyok86hh88brzgs.png" alt="Screenshot da criação de Resource" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Com o endpoint persons selecionado, vá em &lt;strong&gt;Create method&lt;/strong&gt; e preencha as seguintes infos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Method type: GET&lt;/li&gt;
&lt;li&gt;Integration type: Lambda function&lt;/li&gt;
&lt;li&gt;Em lambda function: Selecione a nossa lambda de teste&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa1z5zmypa86vpoiqmwk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa1z5zmypa86vpoiqmwk.png" alt="Screenshot da criação de api pra lambda" width="800" height="901"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois de clicar em Create method, o resultado deve ser esse aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswmoyv2uwixhwe064x0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswmoyv2uwixhwe064x0v.png" alt="Screenshot da página com o método de persons criado" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;Deploy API&lt;/strong&gt; e crie um stage chamado &lt;code&gt;development&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ivz65kkze1ulzzxjxlm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ivz65kkze1ulzzxjxlm.png" alt="Screenshot da tela de criação de stage" width="800" height="778"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Você deve ser redirecionado pra essa tela com o stage criado, e mais uma URL gigante:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh5wgjf4f6e4z2o23g2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkh5wgjf4f6e4z2o23g2n.png" alt="Screenshot da página de stage development" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando o domínio
&lt;/h2&gt;

&lt;p&gt;Pra criar o nosso domínio, vamos no painel do &lt;strong&gt;API Gateway -&amp;gt;  Custom domain names -&amp;gt; Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpu5vqgu2hnu3ensm4dz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgpu5vqgu2hnu3ensm4dz.png" alt="Create custom domain" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Antes de começar, na configuração do endpoint, você vai precisar adicionar um certificado pro domínio que você deseja criar. Clique em &lt;strong&gt;Create a new ACM certificate&lt;/strong&gt; e uma nova aba se abrirá.&lt;/p&gt;

&lt;p&gt;Na tela do Certificate Manager, clique em &lt;strong&gt;Request a certificate -&amp;gt; Request a public certificate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Na tela que vai se abrir, insira o domínio que você vai usar pra solicitar o certificado. No meu caso é o &lt;code&gt;faker-api.ricmello.com&lt;/code&gt;, mas você pode adicionar mais de um domínio ou um wildcard como &lt;code&gt;*.ricmello.com&lt;/code&gt; pra não precisar criar um certificado pra cada subdomínio.&lt;/p&gt;

&lt;p&gt;O método de validação recomendado pela própria AWS é o de DNS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa1e7npu46tzk3obd4xx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa1e7npu46tzk3obd4xx.png" alt="Screenshot da tela de requisição de certificado" width="800" height="635"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;request&lt;/strong&gt; e depois &lt;strong&gt;view certificate&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Caso você já use o Route53, basta clicar em &lt;strong&gt;Create records in Route 53&lt;/strong&gt; e os registros serão criados automaticamente pra validação do domínio. Ou caso você use outro serviço é só criar um novo registro do tipo CNAME e colar os valores que vão aparecer pra você como no print abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31ev7azh4gvd47qvzcsi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31ev7azh4gvd47qvzcsi.png" alt="Screenshot da página com o CNAME a ser criado" width="800" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois de configurar o DNS, o seu certificado vai estar disponível, mas isso pode demorar um pouco. Você pode usar a ferramenta &lt;a href="https://www.whatsmydns.net" rel="noopener noreferrer"&gt;whatsmydns&lt;/a&gt; pra ver se a sua configuração tá certa e aguardar até o certificado ser emitido como esse aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6oc04mseahf1u8rkb2pe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6oc04mseahf1u8rkb2pe.png" alt="Screenshot da tela de certificado com o status emitido" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora podemos voltar na criação do domínio no API Gateway e selecionar o certificado criado. No nome do domínio eu preenchi o mesmo &lt;code&gt;faker-api.ricmello.com&lt;/code&gt; que eu usei pro certificado:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f24pjpvpcki0xenwofx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8f24pjpvpcki0xenwofx.png" alt="Screenshot da tela de criação do API Gateway com o certificado selecionado" width="800" height="807"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;Create domain name&lt;/strong&gt; para salvar e volte pra tela de configuração de domínio. Você deve criar um CNAME apontando o seu domínio pro API Gateway domain name, que no meu exemplo é o &lt;code&gt;d-4ip5ycuy62.execute-api.us-east-1.amazonaws.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzypfr1238oim0pw05wkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzypfr1238oim0pw05wkf.png" alt="Screenshot da configuração do nome de domínio customizado" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Associando o domínio
&lt;/h2&gt;

&lt;p&gt;Na tela de Custom domain names, vá em &lt;strong&gt;API mappings &amp;gt; Configure API mappings &amp;gt; Add new mapping&lt;/strong&gt;, e configure um mapeamento selecionando a sua API e o stage criado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F732fxmm8avafm4ajxl0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F732fxmm8avafm4ajxl0n.png" alt="Screenshot da tela de configuração de API com a lambda e o stage development selecionados" width="800" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feito! O seu domínio vai apontar pro api gateway e você vai conseguir utilizar a lambda pelo mapeamento como na imagem abaixo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhcglap2lze07jkii2bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbhcglap2lze07jkii2bq.png" alt="Imagem da resposta da lambda utilizando o domínio criado" width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;E aí, curtiu? Tem alguma dúvida? Se tiver qualquer coisa que eu possa fazer pra tornar esse artigo melhor, pode reclamar, elogiar ou sugerir outro artigo. Manda ver nos comentários porque feedbacks são sempre super bem vindos.&lt;/p&gt;

</description>
      <category>lambda</category>
      <category>apigateway</category>
      <category>aws</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Como criar um backend pro seu frontend com AWS Lambdas</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Mon, 25 Mar 2024 03:20:11 +0000</pubDate>
      <link>https://dev.to/aws-builders/como-criar-um-backend-pro-seu-frontend-com-aws-lambdas-5fk9</link>
      <guid>https://dev.to/aws-builders/como-criar-um-backend-pro-seu-frontend-com-aws-lambdas-5fk9</guid>
      <description>&lt;p&gt;Embora eu não seja o cara do backend, eu sempre tive muito contato com o desenvolvimento de APIs mesmo enquanto front, mas Lambdas foram algo que eu sempre ignorei.&lt;/p&gt;

&lt;p&gt;Primeiro eu achava complicado, depois desnecessário porque eu achava mais fácil subir uma aplicação, até o dia que eu resolvi dar uma chance pro negócio e cara, vale a pena.&lt;/p&gt;

&lt;p&gt;No youtube tem vídeo antigo falando sobre isso, mas se você é velho que nem eu e gosta de ler, vamo lá!&lt;/p&gt;

&lt;p&gt;Ah, e pra esse exemplo eu vou criar uma lambda que busca os dados da Faker Api. É um exemplo básico, mas mais pra frente eu vou explicar alguns casos de uso reais onde ele pode ser útil.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando a lambda
&lt;/h2&gt;

&lt;p&gt;A real é que você não precisa ser o bichão do backend pra trabalhar com lambdas. Criar uma é bem simples e pode ser criada direto do painel da AWS. Pra começar, acesse o &lt;a href="https://console.aws.amazon.com/lambda/home"&gt;painel das lambdas&lt;/a&gt; e clique em &lt;strong&gt;Create Function&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ao criar, você pode usar um blueprint que já contém alguns exemplos como conectar ao DynamoDB ou ao S3, mas pro nosso caso nós vamos de &lt;strong&gt;Author from Scratch&lt;/strong&gt; mesmo.&lt;/p&gt;

&lt;p&gt;Dê um nome pra function, que eu vou chamar de &lt;code&gt;faker-api&lt;/code&gt;, e altere o campo architecture pra arm64 que tem um custo menor do que a x86. Você pode conferir o meu setup aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h1wj7mollw4ha2ymlhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h1wj7mollw4ha2ymlhe.png" alt="screenshot da tela de create function" width="800" height="515"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementando a Faker Api
&lt;/h2&gt;

&lt;p&gt;Function criada, agora vamos implementar o nosso código pra buscar os dados da faker api. Você deve substituir o código padrão do index.mjs por esse aqui:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://fakerapi.it/api/v1/persons?_quantity=1&amp;amp;_gender=male&amp;amp;_birthday_start=2005-01-01`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;rawData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;rawData&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawData&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getData&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando o código acima:&lt;/p&gt;

&lt;p&gt;Nós temos a arrow function &lt;code&gt;handler&lt;/code&gt;, que é responsável por executar a lambda. Dentro dela, eu tô chamando a função &lt;code&gt;getData&lt;/code&gt; que por sua vez faz uma requisição pra Faker Api utilizando a api &lt;code&gt;https&lt;/code&gt; do Node. Em seguida, faz o parser da response e retorna os dados.&lt;/p&gt;

&lt;p&gt;A essa altura a sua lambda deve estar assim:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1gzo7gqc5fxo6hmhmu5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1gzo7gqc5fxo6hmhmu5.png" alt="Código-fonte da lambda faker-api" width="800" height="528"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clique em &lt;strong&gt;deploy&lt;/strong&gt; para publicar 🙂&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando uma URL pública
&lt;/h2&gt;

&lt;p&gt;Por último, vá na aba &lt;strong&gt;Configuration&lt;/strong&gt;, clique em &lt;strong&gt;Function url&lt;/strong&gt; e &lt;strong&gt;Create function url&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmibqep39bjtxff65e0od.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmibqep39bjtxff65e0od.png" alt="Screenshot da página Create function url" width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vamos deixar o &lt;strong&gt;Auth Type&lt;/strong&gt; como &lt;code&gt;NONE&lt;/code&gt; e em Additional Settings, marque a caixa &lt;strong&gt;Configure cross-origin resource sharing (CORS)&lt;/strong&gt;. Depois, é só clicar em &lt;strong&gt;Save&lt;/strong&gt;. Você vai ver uma URL criada similar a essa aqui:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6msbbp3ftor93x1k37jl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6msbbp3ftor93x1k37jl.png" alt="Screenshot da lambda com URL criada" width="800" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basta abrir o link no seu navegador que você vai conseguir ver os resultados. E com isso você tem um endpoint seu publicado pra utilizar no frontend. É só consumir com a função &lt;code&gt;fetch&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://dz4y7rvv2az4iopdqzvgneefhy0jdfif.lambda-url.us-east-1.on.aws&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;success: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Tá, agora vamos aos esclarecimentos
&lt;/h2&gt;

&lt;p&gt;Você deve estar se perguntando: pra que diabos eu preciso de uma lambda pra chamar outra API pública se eu posso chamar ela diretamente? E a realidade é que você não precisa. Porém, existem alguns casos onde esse tipo básico de lambda vai te ajudar bastante:&lt;/p&gt;

&lt;h3&gt;
  
  
  Proxy de API
&lt;/h3&gt;

&lt;p&gt;Nem sempre você vai querer que o frontend se conecte no seu endpoint ou possa manipular os resultados da pesquisa. No nosso exemplo, a lambda está filtrando os resultados da Faker Api pra sempre mostrar uma pessoa do gênero masculino nascida a partir de 01/01/2005, e o frontend (ou um usuário mal intencionado) não consegue mudar os filtros aplicados.&lt;/p&gt;

&lt;p&gt;Em um caso de uso real, eu subi um servidor do Strapi e usei a lambda pra expor algumas collections sem expor a API inteira. Nesse caso, a minha lambda tinha a apiKey pra consultar o Strapi e só retornava o que era estritamente necessário pro frontend funcionar. Praticamente um BFF.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mock
&lt;/h3&gt;

&lt;p&gt;Se você precisar subir um serviço pra simular uma API que ainda não está construída, você pode usar essa mesma lambda retornando dados estáticos respeitando o contrato da API que ainda será feita. Em minutos você vai ter um endpoint pra trabalhar que vai estar acessível de qualquer lugar.&lt;/p&gt;




&lt;p&gt;É isso! E aí, curtiu? Tem alguma dúvida? Se tiver qualquer coisa que eu possa fazer pra tornar esse artigo melhor, seja reclamar, elogiar ou sugerir outro artigo, manda ver nos comentários. Feedbacks são sempre super bem vindos.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>webdev</category>
      <category>aws</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Porque você não deveria usar funções de debounce o tempo todo</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Tue, 24 Oct 2023 15:23:09 +0000</pubDate>
      <link>https://dev.to/ricmello/porque-voce-nao-deveria-usar-funcoes-de-debounce-o-tempo-todo-1bam</link>
      <guid>https://dev.to/ricmello/porque-voce-nao-deveria-usar-funcoes-de-debounce-o-tempo-todo-1bam</guid>
      <description>&lt;p&gt;E porque essa técnica muito legal é gambiarra.&lt;/p&gt;




&lt;p&gt;Hoje eu vi outro post ensinando a criar uma função de debounce pra diminuir a quantidade de requisições desnecessárias.&lt;/p&gt;

&lt;p&gt;Se você não viu, tem &lt;a href="https://www.freecodecamp.org/portuguese/news/debounce-como-atrasar-a-execucao-de-uma-funcao-em-javascript-exemplo-com-js-es6/"&gt;esse ótimo post do FreeCodeCamp&lt;/a&gt; ensinando.&lt;/p&gt;

&lt;p&gt;O debounce é &lt;del&gt;uma gambiarra&lt;/del&gt; um recurso super útil e que pode te ajudar bastante a controlar a quantidade de requisições feitas ao servidor, principalmente quando os recursos são limitados. Geralmente usado em campos de autocomplete, você espera até o usuário parar de digitar por determinado tempo (300 ou 500ms) pra fazer a requisição, assim você não faz uma requisição pra cada letra e diminui a quantidade de requests "desnecessários".&lt;/p&gt;

&lt;h2&gt;
  
  
  Isso faz sentido?
&lt;/h2&gt;

&lt;p&gt;Hoje podemos escalar aplicações como nunca em horários de pico, e poupar grana enquanto elas não estão sendo utilizadas. A obsessão por performance do lado do backend é frequente. Será que a API não consegue resolver isso sozinha?&lt;/p&gt;

&lt;p&gt;A resposta é: &lt;strong&gt;sim, deveria&lt;/strong&gt;. Estratégias de cache, bancos em memória, indexação, e um mundo de ferramentas criadas para fornecer uma resposta super rápida sem onerar o banco principal. APIs respondendo em 50ms enquanto a gente vai lá e mete um debounce de 300ms 🤡&lt;/p&gt;

&lt;h2&gt;
  
  
  A experiência do usuário
&lt;/h2&gt;

&lt;p&gt;Todo mundo, principalmente quem é heavy user, já passou por apps ou sistemas onde você precisa esperar um tiquinho depois de digitar pra ver os resultados. É pouco tempo, mas é irritante quando você compara com ferramentas como a busca da Amazon, Google Maps, ou outras do tipo. &lt;/p&gt;

&lt;p&gt;Se você já colocou o delay e a API demora um pouco a mais pra responder, soma os tempos e você vai ver o usuário triste.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Aí, travou essa *****"&lt;br&gt;
– Usuário triste&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Depois, abre o seu inspector e faz uma pesquisa no Google Maps pra você ver quantas requisições ele faz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ah, mas DDoS...
&lt;/h2&gt;

&lt;p&gt;Se você confia no seu frontend pra te poupar de um DDoS, meu amigo... você tá em uma situação complicada. Acho que só outro post mesmo pra caber, mas me avisa aqui que eu faço.&lt;/p&gt;

&lt;h2&gt;
  
  
  Então eu não devo usar debounce?
&lt;/h2&gt;

&lt;p&gt;Calma... depois de virar dev sênior, você aprende que é pago pra dizer "depende" pra tudo. E mais uma vez aqui: DEPENDE.&lt;/p&gt;

&lt;p&gt;Se você trabalha em um frontend que consome uma API nova, e o backend não consegue dar conta de muitas requests, remove o debounce e pede pra ele consertar esse treco aí. Manda o print do inspector do site da Amazon e avisa quantas pessoas usam diariamente.&lt;/p&gt;

&lt;p&gt;Agora, se você trabalha em um sistema legado onde a API não dá conta da quantidade de requests, ou se o chefe não deixar o backend consertar o bug, ou se vc quiser salvar dinheiro pq a API do Google Places tá comendo seu orçamento, aí sim vc usa o debounce, mas não acostuma com ele. Debounce é gambiarra, não deixa te convencerem do contrário.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>performance</category>
    </item>
    <item>
      <title>O guia definitivo para hospedar uma SPA Angular/React com S3, Route 53 e CloudFront</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Wed, 22 Mar 2023 02:28:33 +0000</pubDate>
      <link>https://dev.to/aws-builders/o-guia-definitivo-para-hospedar-uma-spa-angularreact-com-s3-route-53-e-cloudfront-232h</link>
      <guid>https://dev.to/aws-builders/o-guia-definitivo-para-hospedar-uma-spa-angularreact-com-s3-route-53-e-cloudfront-232h</guid>
      <description>&lt;p&gt;O combo S3 + CloudFront é uma ótima opção para hospedagem de aplicações Angular e React. Como dito antes &lt;a href="https://dev.to/aws-builders/deploy-de-angularreact-para-o-s3-via-github-actions-43mn"&gt;nesse post&lt;/a&gt;, uma SPA é simplesmente um monte de arquivos HTML, CSS e JS que rodam no browser, então qualquer servidor de arquivos cumpre a responsa de hospedar esse tipo de aplicação.&lt;/p&gt;

&lt;p&gt;O S3 (Simple Storage Service) é um serviço de armazenamento de objetos que pode ser usado para armazenar e recuperar qualquer quantidade de dados de qualquer lugar na web.&lt;/p&gt;

&lt;p&gt;O CloudFront, por sua vez, é uma rede de entrega de conteúdo (CDN) que entrega dados, vídeos, aplicativos e APIs com segurança, baixa latência e alta velocidade de transferência. Ao usar o CloudFront com o S3, você pode melhorar o desempenho e a confiabilidade do seu site ou aplicativo distribuindo seu conteúdo globalmente para reduzir a latência, melhorar o tempo de carregamento das páginas e a quantidade de acessos ao bucket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pré-requisitos
&lt;/h2&gt;

&lt;p&gt;Antes de começar, precisamos seguir o passo a passo para a  &lt;a href="https://dev.to/aws-builders/como-criar-e-publicar-uma-aplicacao-angular-no-amazon-s3-49d8"&gt;criação do bucket no S3&lt;/a&gt;, e  caso você queira ter deploys automatizados, &lt;a href="https://dev.to/aws-builders/deploy-de-angularreact-para-o-s3-via-github-actions-43mn"&gt;configurar o Github Actions&lt;/a&gt; pra atualizar o bucket automaticamente, Por último, vamos configurar o CloudFront e o Route 53.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Importante:&lt;/strong&gt; embora uma infinidade de artigos e tutoriais (incluindo o meu anterior) ensine, não é uma boa prática deixar o bucket público em produção. Logo, o CloudFront se torna super necessário, principalmente em ambientes corporativos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reconfigurando o bucket
&lt;/h2&gt;

&lt;p&gt;Depois de seguir o passo a passo do tutorial anterior, vamos tornar o bucket privado novamente. Vá na aba permissions do seu bucket, remova a policy do tutorial anterior e marque a opção &lt;strong&gt;Block all public access&lt;/strong&gt;. O resultado deve ser esse:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbmo78nme2iv895mf5oc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbmo78nme2iv895mf5oc.png" alt="Bucket privado e com policy removida"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando a distribuição
&lt;/h2&gt;

&lt;p&gt;Vá para o &lt;a href="https://console.aws.amazon.com/cloudfront/v3/home" rel="noopener noreferrer"&gt;painel do CloudFront&lt;/a&gt; na AWS e clique em &lt;strong&gt;Create Distribution&lt;/strong&gt;. Na criação de distribuição, iremos preencher alguns campos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Origin domain:&lt;/strong&gt; selecione o bucket com a sua aplicação&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Origin access:&lt;/strong&gt; selecione a opção &lt;strong&gt;Origin access control settings (recommended)&lt;/strong&gt;, que irá deixar o bucket acessível somente para o CloudFront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ainda em Origin Access:&lt;/strong&gt; clique em &lt;strong&gt;Create Control Setting&lt;/strong&gt;, e em seguida em &lt;strong&gt;create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Default root object&lt;/strong&gt;: preencha &lt;code&gt;index.html&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Create Distribution&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Após a criação você verá um aviso dizendo que a policy do bucket precisa ser atualizada. O processo é bem simples: clique em &lt;strong&gt;Copy Policy&lt;/strong&gt; no próprio aviso, que irá deixar a policy na sua área de transferência, depois em &lt;strong&gt;Go to S3 bucket&lt;/strong&gt;, e cole o conteúdo em Bucket Policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi0qitu0z0qt7zn8f01fn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi0qitu0z0qt7zn8f01fn.png" alt="Aviso de que a Bucket Policy precisa ser alterada"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Voltando à sua distribuição do CloudFront, você verá o link onde ela foi publicada. A essa altura o seu app já estará rodando nesse link mesmo com bucket privado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6hy1lkycc06xp1o6m2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6hy1lkycc06xp1o6m2l.png" alt="Minha distribuição do CloudFront"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuração do domínio
&lt;/h2&gt;

&lt;p&gt;Também é possível configurar um domínio personalizado no Route 53. Caso você ainda não tenha uma zona configurada, você tem duas opções:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pt_br/Route53/latest/DeveloperGuide/dns-configuring-new-domain.html" rel="noopener noreferrer"&gt;Configurar o roteamento de DNS para um novo domínio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/pt_br/Route53/latest/DeveloperGuide/MigratingDNS.html" rel="noopener noreferrer"&gt;Configurar o Route 53 como serviço DNS para um domínio existente&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Com a hosted zone criada, basta navegar até ela e clicar em &lt;strong&gt;Create Record&lt;/strong&gt; para criar um novo registro, e setar como &lt;strong&gt;Alias to CloudFront Distribution&lt;/strong&gt; e apontar para a URL da sua distribuição como no print abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyl3bvj6ql0fs43opc7mf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyl3bvj6ql0fs43opc7mf.png" alt="Exemplo de criação de domínio personalizado no Route 53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois, precisamos voltar no painel do CloudFront &amp;gt; sua distribution &amp;gt; settings e:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adicione o seu domínio como &lt;strong&gt;alternate domain name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Crie um certificado

&lt;ul&gt;
&lt;li&gt;Clique em &lt;strong&gt;Request certificate&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Selecione &lt;strong&gt;Request a public certificate&lt;/strong&gt; na janela que vai abrir&lt;/li&gt;
&lt;li&gt;Insira o seu domínio em &lt;strong&gt;Fully qualified domain name&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Clique em Request&lt;/li&gt;
&lt;li&gt;Na lista de certificados, clique no certificado recém-criado&lt;/li&gt;
&lt;li&gt;Em Domains, vá em &lt;strong&gt;Create records in Route 53&lt;/strong&gt; e confirme a operação&lt;/li&gt;
&lt;li&gt;Aguarde o certificado ficar com o status &lt;strong&gt;Issued&lt;/strong&gt; (pode levar alguns minutos)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Selecione o certificado que você acabou de criar&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqefbxff0yx9mgp61b66.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foqefbxff0yx9mgp61b66.png" alt="Configuração do CloudFront com o domínio novo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  O pulo do gato
&lt;/h2&gt;

&lt;p&gt;Tanto o Angular quanto o React possuem o conceito de rota, o que significa que elas são tratadas no frontend. Se o usuário der um F5 ou tentar abrir uma rota diferente do seu app, o CloudFront vai tentar buscar essa rota no S3 e retornar um erro porque ele não vai encontrar nenhum objeto na roda solicitada.&lt;/p&gt;

&lt;p&gt;A solução é redirecionar as requests para o &lt;code&gt;index.html&lt;/code&gt;. Para isso, vá em &lt;strong&gt;Error Pages&lt;/strong&gt; &amp;gt; &lt;strong&gt;Create Custom Error Response&lt;/strong&gt; e crie a configuração abaixo:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figvubpnfvg229enxc5o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figvubpnfvg229enxc5o0.png" alt="Custom Error Response configurada como http error = 403, customize error = yes, response page path = /index.html, http response code = 200: OK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Essa config redireciona todos os erros 403 para o &lt;code&gt;index.html&lt;/code&gt; e retorna Http 200 (OK) para o browser. Assim, independente da rota que o usuário acessar, o CloudFront vai retornar o frontend e o próprio frontend é quem vai gerenciar se aquela rota existe ou não, além de realizar os redirecionamentos caso necessário, que é o comportamento correto.&lt;/p&gt;

&lt;h2&gt;
  
  
  GG
&lt;/h2&gt;

&lt;p&gt;Agora temos a aplicação publicada, com o bucket seguro e em uma rede de alta disponibilidade que vai acelerar o carregamento independente da localização do usuário.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5jrefl6uzy2hqahq4co.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5jrefl6uzy2hqahq4co.png" alt="Print da página publicada"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É isso! E aí, curtiu? Tem alguma dúvida? Se tiver qualquer coisa que eu possa fazer pra tornar esse artigo melhor, se quiser reclamar, elogiar ou sugerir outro artigo, manda ver nos comentários. Feedbacks são sempre super bem vindos.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>react</category>
      <category>aws</category>
      <category>cloudfront</category>
    </item>
    <item>
      <title>Deploy de app Angular/React para o S3 via GitHub Actions</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Fri, 17 Mar 2023 12:00:00 +0000</pubDate>
      <link>https://dev.to/aws-builders/deploy-de-angularreact-para-o-s3-via-github-actions-43mn</link>
      <guid>https://dev.to/aws-builders/deploy-de-angularreact-para-o-s3-via-github-actions-43mn</guid>
      <description>&lt;p&gt;Há um tempo atrás eu escrevi &lt;a href="https://dev.to/aws-builders/como-criar-e-publicar-uma-aplicacao-angular-no-amazon-s3-49d8"&gt;esse post&lt;/a&gt; sobre como criar e publicar uma aplicação Angular no S3. Como ambos os frameworks usam a pasta dist, basta seguir os mesmos passos no React.&lt;/p&gt;

&lt;p&gt;Agora, nós vamos usar o GitHub Actions pra automatizar o nosso deploy e atualizar o ambiente automaticamente a cada commit na branch principal.&lt;/p&gt;

&lt;p&gt;E se você chegou até aqui mas ainda não entendeu muito bem porque publicar uma SPA no S3 ao invés de um nginx ou apache da vida, a resposta é simples: &lt;strong&gt;é tudo HTML, CSS e JS&lt;/strong&gt;. Uma SPA tem um monte de JS incorporado, regras de interface, libs, etc. mas no fim disso tudo o código é executado no browser, então a gente só precisa de um servidor de arquivos pra fazer a mágica acontecer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Repo
&lt;/h2&gt;

&lt;p&gt;Dessa vez vamos usar um &lt;a href="https://github.com/ricmello/react-s3-app"&gt;app react&lt;/a&gt; como exemplo, e se você é do team Angular pode usar &lt;a href="https://github.com/ricmello/angular-s3-app"&gt;esse repo&lt;/a&gt; como base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criando a Action
&lt;/h2&gt;

&lt;p&gt;No seu repositório, vá para a aba actions pra criar o seu primeiro workflow. Digite Node.js na caixa de pesquisa, procure por essa action aqui e clique em &lt;strong&gt;Configure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02fwp1randl4tzq72tvr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02fwp1randl4tzq72tvr.png" alt="Node.js Github Action" width="800" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Importante: GitHub Actions é o nome da ferramenta. Dentro dela, nós configuramos os workflows. Um workflow é um conjunto de instruções pra fazer o que você quiser com o seu projeto: rodar testes, buildar a aplicação, fazer o deploy ou tudo isso junto, se você consegue fazer no terminal é possível fazer via Github Actions. Ainda tem uma série de comandos predefinidos pra te ajudar no &lt;a href="https://github.com/marketplace?type=actions"&gt;marketplace&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Após clicar em Configure, o GitHub vai gerar um workflow padrão para uma aplicação node:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node&lt;/span&gt;
&lt;span class="c1"&gt;# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs&lt;/span&gt;

&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Node.js CI&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js ${{ matrix.node-version }}&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;18.x&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build --if-present&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Explicando o arquivo acima, ele é executado tanto em pushes quanto PRs para a branch main. Roda no ubuntu e executará nas versões 14, 16 e 18 do node. Como a gente não precisa suportar várias versões, eu vou fixar na versão 18.x. Essa é a parte de configuração do workflow.&lt;/p&gt;

&lt;p&gt;Nas steps, que são as etapas, o &lt;code&gt;actions/checkout&lt;/code&gt; baixa o repositório, enquanto o &lt;code&gt;setup-node&lt;/code&gt; instala o nodejs. Com o node instalado, rodamos o &lt;code&gt;npm ci&lt;/code&gt; pra &lt;a href="https://dev.to/ricmello/npm-install-vs-npm-ci-qual-utilizar-ce9"&gt;instalar as dependências&lt;/a&gt;, depois o build e os testes. Como a nossa aplicação não tem testes, eu vou remover essa última linha.&lt;/p&gt;

&lt;p&gt;A essa altura, o seu arquivo deve estar assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy React app to S3&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-and-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js 18.x&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;18.x&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora que já temos o script de build, é hora de publicar no S3. Eu criei um bucket com o nome de &lt;code&gt;my-react-s3-app&lt;/code&gt; usando as configurações do &lt;a href="https://dev.to/aws-builders/como-criar-e-publicar-uma-aplicacao-angular-no-amazon-s3-49d8"&gt;tutorial anterior&lt;/a&gt;. Com o bucket pronto, fica faltando configurar as credenciais da AWS e subir os arquivos.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Com isso, o meu arquivo final ficou assim:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy React app to S3&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;main"&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v3&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use Node.js 18.x&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;18.x&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup AWS credentials&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v1&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
        &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_REGION }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to S3&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws s3 sync dist/ s3://my-react-s3-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A step &lt;strong&gt;Setup AWS credentials&lt;/strong&gt; configura o workflow pra usar as credenciais de uma conta que eu criei com permissão no S3. Tanto as credenciais quanto a region do meu app estão em secrets, assim eu não deixo nenhuma informação sensível no repositório. &lt;/p&gt;

&lt;p&gt;Você pode ver como gerar as credenciais &lt;a href="https://docs.aws.amazon.com/pt_br/powershell/latest/userguide/pstools-appendix-sign-up.html"&gt;nesse link&lt;/a&gt; e você pode encontrar mais informações sobre as secrets &lt;a href="https://docs.github.com/en/actions/security-guides/encrypted-secrets"&gt;aqui&lt;/a&gt;. Para criar as secrets basta ir no seu &lt;strong&gt;repositório no github &amp;gt; Settings &amp;gt; Secrets and Variables &amp;gt; Actions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;E por último, mas não menos importante, a task &lt;strong&gt;Deploy to S3&lt;/strong&gt; sobe os arquivos pro nosso bucket. Após fazer o push para o repositório, a aplicação fica disponível automaticamente em &lt;a href="https://github.com/ricmello/react-s3-app/actions/runs/4443180406"&gt;alguns segundos&lt;/a&gt;. Você pode acessar o meu app &lt;a href="https://my-react-s3-app.s3.us-west-2.amazonaws.com/index.html"&gt;nesse link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kli4yqkrkr1w8a15h5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0kli4yqkrkr1w8a15h5f.png" alt="App publicado no S3" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;É isso! E aí, curtiu? Tem alguma dúvida? Se tiver qualquer coisa que eu possa fazer pra tornar esse artigo melhor, se quiser reclamar, elogiar ou sugerir outro artigo, manda ver nos comentários. Feedbacks são sempre super bem vindos.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>react</category>
      <category>s3</category>
      <category>devops</category>
    </item>
    <item>
      <title>npm install vs npm ci: qual utilizar?</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Tue, 28 Feb 2023 23:45:55 +0000</pubDate>
      <link>https://dev.to/ricmello/npm-install-vs-npm-ci-qual-utilizar-ce9</link>
      <guid>https://dev.to/ricmello/npm-install-vs-npm-ci-qual-utilizar-ce9</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lxrs6f3sr201usinetn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7lxrs6f3sr201usinetn.png" alt="Logo do npm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O comando padrão pra instalar as dependências é o &lt;code&gt;npm install&lt;/code&gt;. Se você usa o npm há certo tempo, provavelmente já utiliza esse comando sempre que precisa instalar as dependências de um projeto.&lt;/p&gt;

&lt;p&gt;O que nem todo mundo sabe é que desde o npm v6, existe um comando similar ao &lt;code&gt;npm install&lt;/code&gt; chamado &lt;code&gt;npm ci&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nesse artigo, vamos entender as principais diferenças entre eles e quando utilizar cada um.&lt;/p&gt;

&lt;h2&gt;
  
  
  npm install
&lt;/h2&gt;

&lt;p&gt;O &lt;code&gt;npm install&lt;/code&gt; instala os pacotes do package.json e suas dependências. Caso alguma dependência possua o &lt;code&gt;^&lt;/code&gt; ou ou &lt;code&gt;~&lt;/code&gt;, ele procura novas versões e atualiza o package-lock.json com a árvore gerada.&lt;/p&gt;

&lt;h2&gt;
  
  
  npm ci
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;npm ci&lt;/code&gt;, ou "clean install" é utilizado para instalar as dependências do zero. Diferente do &lt;code&gt;npm install&lt;/code&gt;, esse comando instala as dependências a partir do &lt;code&gt;package-lock.json&lt;/code&gt; ou do &lt;code&gt;npm-shrinkwrap.json&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Isso garante que você irá sempre instalar a mesma versão de cada pacote, não importa quantas vezes o comando for executado e nem se houver atualizações disponíveis. Ideal para ambientes de build automatizado ou integração contínua (CI).&lt;/p&gt;

&lt;p&gt;Como ele pula certas etapas como atualizar o package-lock.json e resolver as dependências, esse comando também é muito mais rápido do que o &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Qual usar?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No seu ambiente de desenvolvimento, ou sempre que você quiser atualizar as dependências elegíveis, vale continuar usando o &lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Já no caso de instalar as dependências no seu servidor de integração contínua, ou até mesmo instalar local mas sem atualizar nada, vá de &lt;code&gt;npm ci&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Ambos os comandos são similares mas têm aplicações bem distintas. Eu uso o &lt;code&gt;npm install&lt;/code&gt; no dia a dia, mas recomendo fortemente a utilização do &lt;code&gt;npm ci&lt;/code&gt; no servidor de integração contínua. Além de ter builds mais confiáveis sem a possível atualização de versões, ele ainda vai ficar mais rápido.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Commitar ou não commitar o package-lock.json?</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Sat, 25 Feb 2023 15:44:12 +0000</pubDate>
      <link>https://dev.to/ricmello/commitar-ou-nao-commitar-o-package-lockjson-c72</link>
      <guid>https://dev.to/ricmello/commitar-ou-nao-commitar-o-package-lockjson-c72</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdw8w79qbg0ga8kc8qt3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdw8w79qbg0ga8kc8qt3.jpg" alt="Commitar ou não commitar?" width="500" height="756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Versão resumida:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Sim, você deve commitar&lt;/li&gt;
&lt;li&gt;Sempre faça o commit do arquivo quando ele for alterado&lt;/li&gt;
&lt;li&gt;Nunca delete o package-lock.json e nem coloque ele no .gitignore&lt;/li&gt;
&lt;li&gt;O mesmo vale para o yarn.lock&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Contexto
&lt;/h2&gt;

&lt;p&gt;Ainda hoje eu vejo muita gente discutindo sobre porque não commitar o package-lock. Rola um misticismo danado em cima desse arquivo tão útil e hoje vamos entender se vale a pena ou usar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Os problemas
&lt;/h2&gt;

&lt;p&gt;Tem sido cada vez mais raro, mas ainda acontece: aquela dependência que você adicionou no package.json e colocou a versão com um circunflexo (Ex.: &lt;code&gt;"typescript": "^4.0.0"&lt;/code&gt;) atualizou pra versão 4.9 e sua aplicação começou a quebrar. &lt;/p&gt;

&lt;p&gt;Isso acontece porque você permitiu o update da major pra essa dependência, permitindo a atualização de novas features. O problema é que um código que o desenvolvedor considera como feature, pode se tornar uma breaking change pra você.&lt;/p&gt;

&lt;p&gt;Daí você pode ser malandro e tirar o circunflexo pra travar a versão, mas você sabia que a dependência da sua dependência também pode ter o tal circunflexo?&lt;/p&gt;

&lt;p&gt;Outro caso acontece quando você desenvolve a sua feature, commita o seu código, e na hora do CI o build vai lá e quebra, mas local ele roda normalmente.&lt;/p&gt;

&lt;p&gt;Ou pior, a versão de produção começa a apresentar um bug estranho que só acontece em produção, e depois de horas investigando você descobre que é a versão da lib que tá diferente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjovxkl1fxlehtegea7b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjovxkl1fxlehtegea7b.jpg" alt="Na minha máquina funciona" width="600" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A solução: package-lock.json
&lt;/h2&gt;

&lt;p&gt;Todos esses problemas poderiam ter sido evitados com o package-lock.json. O lock, como seu próprio nome diz, é uma espécie de trava que descreve toda a árvore de dependências geradas pelo &lt;code&gt;npm install&lt;/code&gt; e garante que todas as pessoas do projeto, incluindo o seu CI, vão instalar as mesmas dependências e suas respectivas versões.&lt;/p&gt;

&lt;p&gt;Como cada commit tem seu snapshot do package-lock, você consegue voltar pra uma versão anterior da aplicação e reinstalar toda a árvore de dependências que funcionava quando o snapshot foi criado.&lt;/p&gt;

&lt;p&gt;O package-lock.json também indica quando uma dependência foi atualizada, te dando uma ótima visibilidade da árvore de dependências do seu projeto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pra galera do yarn: yarn.lock
&lt;/h2&gt;

&lt;p&gt;E se você usa o yarn, isso também vale pra você. O yarn.lock tem a mesma funcionalidade do package-lock.json e também deve ser versionado.&lt;/p&gt;

</description>
      <category>rag</category>
      <category>llm</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>React para devs Angular</title>
      <dc:creator>Ricardo Mello</dc:creator>
      <pubDate>Mon, 09 Jan 2023 01:45:59 +0000</pubDate>
      <link>https://dev.to/ricmello/react-para-devs-angular-2fhm</link>
      <guid>https://dev.to/ricmello/react-para-devs-angular-2fhm</guid>
      <description>&lt;p&gt;Já dizia o narrador em Joseph Climber, a vida de dev é uma caixinha de surpresas. Um dia você é dev Angular, no outro você acha uma oportunidade em uma empresa que você sempre quis trabalhar e quando vê a stack: React 🤦&lt;/p&gt;

&lt;p&gt;Em outro você é contratado pra uma consultoria para trabalhar com Angular, o seu projeto é cancelado na primeira semana e os caras perguntam "rola react?" 🤦 de novo.&lt;/p&gt;

&lt;p&gt;Pois é, os dois cenários aconteceram comigo em menos de um ano. Se adaptar à mudanças é uma skill importante, e isso não significa que você é um profissional ornitorrinco não. Só começa a ficar preocupante se você tiver um conhecimento superficial da stack mas o mais importante, independentemente do framework, são os fundamentos. E é sobre isso que eu pretendo escrever hoje: Como aprender React sendo um dev Angular.&lt;/p&gt;

&lt;p&gt;Cada tópico possui links para a documentação oficial para que você possa se aprofundar nos conceitos, mas é super importante saber que a curva de aprendizado é bem menor do que parece.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que é o React
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://reactjs.org" rel="noopener noreferrer"&gt;React&lt;/a&gt; é uma &lt;strong&gt;biblioteca&lt;/strong&gt; JavaScript para a construção de interfaces. E aqui começa a primeira diferença: o &lt;a href="https://angular.io" rel="noopener noreferrer"&gt;Angular&lt;/a&gt; é um &lt;strong&gt;framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Por ser uma biblioteca, o React fornece uma série de funções para a construção de interfaces, mas deixa a cargo do desenvolvedor como usá-las em sua aplicação.&lt;/p&gt;

&lt;p&gt;Parte do sucesso do React vem dessa flexibilidade de ser relativamente não opinativo. Isso resultou em um ecossistema gigante de ferramentas em torno da lib, porém, ao mesmo tempo, você pode precisar de um pouco mais de esforço pra desenvolver uma aplicação do zero, porque precisamos passar um pouco mais de tempo configurando a estrutura do projeto e definindo/escolhendo os padrões.&lt;/p&gt;

&lt;p&gt;Isso pode ser bem esquisito pra quem vem do Angular já que o framework te dá uma série de guidelines a serem seguidos, mas é algo que se acostuma. Você também vai perceber que dá pra utilizar alguns padrões do Angular em um app React como rxjs, nx, etc. e a comunidade tem uma série de padrões próprios do React também.&lt;/p&gt;

&lt;p&gt;Eu sempre lembro de quando eu estava procurando referências sobre como criar a estrutura do projeto e caí num post do Dan Abramov dizendo que essa é a estrutura ideal: &lt;a href="http://react-file-structure.surge.sh" rel="noopener noreferrer"&gt;http://react-file-structure.surge.sh&lt;/a&gt;. Isso mostra o quão livre nós estamos para criar nossos próprios padrões. Só não se esqueça: com grandes poderes vêm grandes responsabilidades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Criação de um projeto
&lt;/h2&gt;

&lt;p&gt;Diferente do Angular onde o &lt;code&gt;ng new&lt;/code&gt; é quase um mantra, nós temos uma série de possibilidades diferentes ao criar um projeto react. Uma delas, inclusive, se resume em &lt;a href="https://reactjs.org/docs/add-react-to-a-website.html" rel="noopener noreferrer"&gt;adicionar duas tags &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; em um arquivo HTML qualquer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A forma recomendada pela documentação mais próxima da nossa realidade é o &lt;a href="https://reactjs.org/docs/create-a-new-react-app.html#create-react-app" rel="noopener noreferrer"&gt;create-react-app&lt;/a&gt;, que gera um projeto configurado com scripts para executar a aplicação, rodar o build, etc. Pra isso, basta rodar o seguinte comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx create-react-app my-app &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O comando acima gera o projeto React configurado, e o flag &lt;code&gt;--template typescript&lt;/code&gt; adiciona a nossa linguagem do coração. Sem ele, o create-react-app gera um projeto javascript.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vite
&lt;/h3&gt;

&lt;p&gt;Uma opção ainda melhor do que o create-react-app e que a comunidade já considera um novo padrão é o &lt;a href="https://vitejs.dev" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A proposta dos dois é parecida, mas enquanto o create-react-app usa o webpack, o vite usa o esbuild que é significativamente mais rápido, e essa diferença de velocidade vai crescendo junto com a aplicação.&lt;/p&gt;

&lt;p&gt;Pra criar um projeto com o Vite, é só rodar o comando abaixo e seguir as instruções:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm create vite@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Componentes
&lt;/h2&gt;

&lt;p&gt;Provavelmente o conceito mais importante do desenvolvimento front-end, a boa notícia é que a estrutura básica de um componente não muda de um framework pro outro.&lt;/p&gt;

&lt;p&gt;O ciclo de vida e os nomes das propriedades são diferentes, então você provavelmente vai ficar com a documentação debaixo do braço por algum tempo, mas não vai demorar muito pra acostumar. Dá uma olhada nessa comparação de um componente básico:&lt;/p&gt;

&lt;h3&gt;
  
  
  Componente React
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.module.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Hello&lt;/span&gt; &lt;span class="nx"&gt;World&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Componente Angular
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;div class="app"&amp;gt;Hello World&amp;lt;/div&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./app.component.scss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enquanto a sintaxe é bem diferente, você pode perceber elementos muito similares. Ambos importam um arquivo scss, ambos possuem seus templates e ambos exportam seus componentes. Sendo assim, é possível usar o conhecimento que você já tem sempre que for criar um componente novo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ciclo de Vida
&lt;/h3&gt;

&lt;p&gt;As funções do &lt;a href="https://pt-br.reactjs.org/docs/state-and-lifecycle.html" rel="noopener noreferrer"&gt;ciclo de vida&lt;/a&gt; eram amplamente utilizadas pelos componentes de classe, mas como os componentes de função ganharam o gosto da galera, os &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;Hooks&lt;/a&gt; tomaram a cena e você pode pular direto pra estudar a utilização deles, principalmente o &lt;a href="https://reactjs.org/docs/hooks-effect.html" rel="noopener noreferrer"&gt;Effect Hook&lt;/a&gt;, que é o cara que substitui os métodos do ciclo de vida em componentes de função.&lt;/p&gt;

&lt;h2&gt;
  
  
  Services
&lt;/h2&gt;

&lt;p&gt;Já sobre services, diretivas, pipes... eles não existem.&lt;br&gt;
&lt;a href="https://i.giphy.com/media/5x89XRx3sBZFC/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/5x89XRx3sBZFC/giphy.gif" alt="Bola de feno no deserto" width="500" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse caso nós voltamos ao bom e velho JavaScript e criamos funções que serão utilizadas.&lt;/p&gt;

&lt;p&gt;Existem os &lt;a href="https://reactjs.org/docs/hooks-intro.html" rel="noopener noreferrer"&gt;React Hooks&lt;/a&gt;, que você pode usar pra centralizar grande parte da sua lógica que iria para os services, mas eles são bem diferentes. Enquanto os services são injetáveis e possuem um conceito completamente diferente dos componentes, os hooks são uma forma de adicionar funcionalidades aos componentes, e são executados pelos próprios componentes.&lt;/p&gt;
&lt;h2&gt;
  
  
  JSX
&lt;/h2&gt;

&lt;p&gt;Embora seja possível usar React sem JSX via &lt;a href="https://pt-br.reactjs.org/docs/react-api.html#createelement" rel="noopener noreferrer"&gt;React.createElement()&lt;/a&gt;, na minha opinião não faz o mínimo sentido porque o código fica muito mais verboso.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pt-br.reactjs.org/docs/introducing-jsx.html" rel="noopener noreferrer"&gt;O JSX&lt;/a&gt; (JavaScript XML) é uma extensão do JavaScript que te permite usar uma sintaxe similar à do HTML dentro do código JavaScript. Quando o código JSX for convertido pra JavaScript, ele é transformado em chamadas da função &lt;code&gt;React.createElement()&lt;/code&gt;. Isso significa que esse código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello, world!&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Será convertido pra esse código durante o build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O JSX é o formato recomendado e torna muito mais fácil a escrita dos templates. Há algumas pequenas diferenças em relação ao HTML como a classe CSS, em que você usa a propriedade &lt;code&gt;className&lt;/code&gt; ao invés de &lt;code&gt;class&lt;/code&gt; que é uma palavra reservada do JS, mas o fato de poder utilizar funções JS enquanto monta o template ajuda muito. Na minha opinião um &lt;code&gt;list.map(item =&amp;gt;{})&lt;/code&gt; é bem mais fácil de se fazer e entender do que um &lt;code&gt;*ngFor="let item of list&lt;/code&gt;".&lt;/p&gt;

&lt;h2&gt;
  
  
  Props e State
&lt;/h2&gt;

&lt;p&gt;As &lt;a href="https://reactjs.org/docs/components-and-props.html" rel="noopener noreferrer"&gt;props&lt;/a&gt; são equivalentes aos &lt;code&gt;@Input&lt;/code&gt; do Angular, onde nós passamos as propriedades do componente. Cada prop estará disponível como um atributo do objeto &lt;code&gt;props&lt;/code&gt; da função do componente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Passando a prop title para o componente hello world&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hey!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// Utilizando a prop na função&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O React não possui um equivalente ao &lt;code&gt;@Output&lt;/code&gt;, mas nós podemos passar uma função de callback que será utilizada:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Passando o callback de click para o componente de call to action&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CtaButton&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Click me&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Utilizando o callback no evento de clique do botão&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CtaButton&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;button&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/button&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;Além das props, cada componente possui o seu estado interno. Uma vez que esse estado é alterado, o componente renderiza novamente e o estado é mantido. Nós precisamos do hook &lt;a href="https://reactjs.org/docs/hooks-state.html" rel="noopener noreferrer"&gt;useState()&lt;/a&gt; para acessar o estado de um componente de função.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Declarando uma nova variável de estado, que chamaremos de "count" e definimos como 0&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;You clicked &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; times&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="cm"&gt;/* Ao clicar no botão, chamamos a função setCount com o novo valor */&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Click me
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Embora eu tenha lutado com todas as minhas forças nos últimos anos, o React me levou pro time e eu tenho gostado bastante de trabalhar com ele.&lt;/p&gt;

&lt;p&gt;O React é mais simples que o Angular, isso é fato e a prova é que o Angular vem se tornando mais simples a cada release pra competir. Ter o conhecimento de Angular vai te fazer estar um passo à frente no quesito estrutura de projeto e padrões então o exercício maior é se aprofundar nos conceitos da lib enquanto põe alguns conceitos do Angular na geladeira.&lt;/p&gt;

&lt;p&gt;Somando isso a uma comunidade hypada cheia de ferramentas pra agilizar o desenvolvimento, nós temos uma facilidade muito grande de desenvolver projetos rapidamente sem comprometer a qualidade.&lt;/p&gt;

&lt;p&gt;Eu espero de verdade que você goste do framework e desse artigo, e se você chegou até aqui, tenta deixar um comentário com o que você gostaria de ver nos próximos posts e o que você achou do texto. Com isso, você me ajuda a definir os próximos temas :)&lt;/p&gt;

</description>
      <category>bitcoin</category>
      <category>cryptocurrency</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
