<?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: Erick Gabriel dos Santos Alves</title>
    <description>The latest articles on DEV Community by Erick Gabriel dos Santos Alves (@erickg123).</description>
    <link>https://dev.to/erickg123</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3820654%2F4d71aafa-6bba-4d2e-abd2-95ada9f5d5f5.jpeg</url>
      <title>DEV Community: Erick Gabriel dos Santos Alves</title>
      <link>https://dev.to/erickg123</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/erickg123"/>
    <language>en</language>
    <item>
      <title>Turbinando o Pipeline: Caches, Matrix Builds e Branch Protection (Parte 4)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Mon, 03 Aug 2026 17:15:33 +0000</pubDate>
      <link>https://dev.to/erickg123/turbinando-o-pipeline-caches-matrix-builds-e-branch-protection-parte-4-21p3</link>
      <guid>https://dev.to/erickg123/turbinando-o-pipeline-caches-matrix-builds-e-branch-protection-parte-4-21p3</guid>
      <description>&lt;p&gt;Chegamos ao grande final da nossa jornada! Recapitulando o que construímos até aqui:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Criamos um pipeline que testa e compila nosso Frontend (Angular) e Backend (.NET) em paralelo.&lt;/li&gt;
&lt;li&gt;Tiramos a automação da nuvem paga e colocamos em um &lt;em&gt;Self-Hosted Runner&lt;/em&gt; gratuito.&lt;/li&gt;
&lt;li&gt;Automatizamos a criação de &lt;em&gt;Tags&lt;/em&gt; e do &lt;em&gt;Changelog&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Neste ponto, você já tem um processo melhor do que muitas empresas grandes por aí. Mas, se você observar os logs de execução, vai notar um gargalo frustrante: &lt;strong&gt;a instalação das dependências&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;A cada &lt;em&gt;push&lt;/em&gt;, seu robô perde minutos preciosos baixando a mesma pasta &lt;code&gt;node_modules&lt;/code&gt; (o famoso buraco negro do universo) e os mesmos pacotes NuGet do zero. Hoje, vamos resolver isso e, de quebra, blindar a sua branch &lt;code&gt;main&lt;/code&gt; contra códigos quebrados.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. A Mágica do Cache
&lt;/h2&gt;

&lt;p&gt;Em CI/CD, "Cache" significa guardar um backup das suas dependências da execução anterior. Se o seu arquivo &lt;code&gt;package-lock.json&lt;/code&gt; ou &lt;code&gt;.csproj&lt;/code&gt; não mudou, o GitHub Actions simplesmente restaura a pasta do cache em questão de segundos, pulando totalmente a etapa de download.&lt;/p&gt;

&lt;h3&gt;
  
  
  Otimizando o Frontend (Angular / Node)
&lt;/h3&gt;

&lt;p&gt;Se você está usando a versão mais recente da action &lt;code&gt;setup-node&lt;/code&gt;, o cache já vem embutido! Só precisamos ativá-lo e dizer onde está o nosso arquivo de &lt;em&gt;lock&lt;/em&gt;, já que nosso projeto está dentro da pasta &lt;code&gt;/frontend&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Vá no seu &lt;code&gt;.yml&lt;/code&gt; da Parte 1 e atualize a etapa do Node.js:&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="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 Node.js&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@v4&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;20'&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="c1"&gt;# Ativa o cache mágico!&lt;/span&gt;
          &lt;span class="na"&gt;cache-dependency-path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./frontend/package-lock.json'&lt;/span&gt; &lt;span class="c1"&gt;# Aponta para a subpasta&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Pronto.&lt;/em&gt; Só de adicionar essas duas linhas, o tempo do seu &lt;code&gt;npm ci&lt;/code&gt; vai cair drasticamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Otimizando o Backend (.NET / NuGet)
&lt;/h3&gt;

&lt;p&gt;Para o C#, precisamos usar a action oficial de cache (&lt;code&gt;actions/cache&lt;/code&gt;). Ela exige três coisas: o que salvar (caminho), como nomear o backup (key) e de onde tentar recuperar se não achar o exato (restore-keys).&lt;/p&gt;

&lt;p&gt;Adicione este bloco logo ANTES da etapa de &lt;code&gt;dotnet restore&lt;/code&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="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;Cache NuGet Packages&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/cache@v4&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;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/.nuget/packages&lt;/span&gt;
          &lt;span class="c1"&gt;# Cria uma chave única baseada no SO e nos arquivos de projeto&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/packages.lock.json') }}&lt;/span&gt;
          &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;${{ runner.os }}-nuget-&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Na próxima vez que o pipeline rodar, a primeira execução ainda fará o download, mas salvará o cache no final. Nas execuções seguintes, você verá a magia da restauração rápida.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Testando Multiversos com Matrix Builds
&lt;/h2&gt;

&lt;p&gt;E se você estiver construindo uma biblioteca ou ferramenta que precisa funcionar em múltiplas versões do Node (ex: 18 e 20) ou em vários Sistemas Operacionais simultaneamente?&lt;/p&gt;

&lt;p&gt;Você não precisa copiar e colar o seu código YAML. Basta usar a estratégia de &lt;strong&gt;Matrix&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-frontend&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;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&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="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;18.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;20.x&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;22.x&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# O GitHub vai rodar este Job 3 vezes simultaneamente!&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@v4&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@v4&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;${{ matrix.node-version }}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Com a &lt;code&gt;matrix&lt;/code&gt;, o GitHub Actions cria caminhos paralelos automaticamente. Se uma versão falhar e as outras passarem, você sabe exatamente onde está o problema de compatibilidade.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. O Leão de Chácara: Branch Protection Rules
&lt;/h2&gt;

&lt;p&gt;De que adianta ter um pipeline que roda testes incríveis se um desenvolvedor apressado pode simplesmente clicar em &lt;em&gt;"Merge Pull Request"&lt;/em&gt; ignorando que tudo ficou vermelho?&lt;/p&gt;

&lt;p&gt;A automação só é útil se for &lt;strong&gt;obrigatória&lt;/strong&gt;. Para isso, usamos as Regras de Proteção de Branch.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vá na aba &lt;strong&gt;Settings&lt;/strong&gt; do seu repositório no GitHub.&lt;/li&gt;
&lt;li&gt;Na barra lateral, clique em &lt;strong&gt;Branches&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Add branch ruleset&lt;/strong&gt; (ou edite a regra da sua branch &lt;code&gt;main&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Marque a opção &lt;strong&gt;Require a pull request before merging&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;O MAIS IMPORTANTE: Marque a opção &lt;strong&gt;Require status checks to pass before merging&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Na barra de pesquisa que aparecer, digite os nomes exatos dos seus &lt;em&gt;Jobs&lt;/em&gt; (ex: &lt;code&gt;Build Angular App&lt;/code&gt; e &lt;code&gt;Build &amp;amp; Test .NET API&lt;/code&gt;) e adicione-os como obrigatórios.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;O Resultado:&lt;/strong&gt; A partir de agora, o botão verde de Merge no GitHub ficará &lt;strong&gt;bloqueado&lt;/strong&gt;. Ele só será liberado se o nosso GitHub Actions rodar, compilar o Angular, passar nos testes do .NET e retornar a luz verde.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusão da Série
&lt;/h2&gt;

&lt;p&gt;Parabéns! Se você aplicou os conceitos desta série de 4 partes, você evoluiu de "alguém que arrasta arquivos para o FTP" para um administrador de infraestrutura ágil, segura e profissional.&lt;/p&gt;

&lt;p&gt;Dominar pipelines, gestão de secrets, runners locais e versionamento semântico são habilidades que diferenciam desenvolvedores de alto nível no mercado. O GitHub Actions é uma ferramenta incrivelmente poderosa que vai muito além de apenas subir código.&lt;/p&gt;

&lt;p&gt;Como ficou a sua esteira de CI/CD? Qual foi o tempo que você conseguiu economizar usando o sistema de &lt;em&gt;Caches&lt;/em&gt;? Compartilhe o link do seu repositório (ou os perrengues que passou configurando) aqui nos comentários!&lt;/p&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Versionamento Profissional: Automatizando Tags, Releases e Changelog (Parte 3)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Mon, 03 Aug 2026 17:15:32 +0000</pubDate>
      <link>https://dev.to/erickg123/versionamento-profissional-automatizando-tags-releases-e-changelog-parte-3-4cde</link>
      <guid>https://dev.to/erickg123/versionamento-profissional-automatizando-tags-releases-e-changelog-parte-3-4cde</guid>
      <description>&lt;p&gt;Se você acompanhou as partes anteriores desta série, seu projeto Full-Stack (Angular + .NET) já está sendo testado e compilado automaticamente em um &lt;em&gt;Self-Hosted Runner&lt;/em&gt; gratuito. A infraestrutura está perfeita.&lt;/p&gt;

&lt;p&gt;Mas e a organização do código? &lt;/p&gt;

&lt;p&gt;Imagine a seguinte situação: você trabalha com mais três desenvolvedores. Vocês abrem PRs, fazem &lt;em&gt;merge&lt;/em&gt; na branch &lt;code&gt;main&lt;/code&gt; e o deploy acontece. Chega sexta-feira e o cliente pergunta: &lt;em&gt;"O que exatamente entrou na versão 1.2.0 que acabou de ir pro ar?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Se você responde revirando um histórico de commits cheio de &lt;code&gt;"fix bug"&lt;/code&gt;, &lt;code&gt;"ajuste no layout"&lt;/code&gt;, ou &lt;code&gt;"wip"&lt;/code&gt;, nós temos um problema. &lt;/p&gt;

&lt;p&gt;Nesta &lt;strong&gt;Parte 3&lt;/strong&gt;, vamos transformar seu repositório bagunçado em uma máquina de versionamento profissional. Vamos padronizar os commits, gerar o &lt;code&gt;CHANGELOG.md&lt;/code&gt; magicamente e usar o GitHub Actions para criar &lt;em&gt;Releases&lt;/em&gt; visuais.&lt;/p&gt;




&lt;h2&gt;
  
  
  Passo 1: O Fim do "Commit Bagunça"
&lt;/h2&gt;

&lt;p&gt;A automação de versões depende de previsibilidade. O robô não sabe ler mentes, mas ele sabe ler padrões. É aqui que entra o &lt;strong&gt;Conventional Commits&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Em vez de escrever o que vier à cabeça, você passa a iniciar seus commits com prefixos específicos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;feat: adiciona dark mode no dashboard&lt;/code&gt; (Uma nova funcionalidade - vai gerar uma nova &lt;em&gt;minor version&lt;/em&gt; ex: 1.1.0 -&amp;gt; 1.2.0)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;fix: corrige erro no grid do canvas&lt;/code&gt; (Uma correção de bug - vai gerar um &lt;em&gt;patch&lt;/em&gt; ex: 1.2.0 -&amp;gt; 1.2.1)&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;chore: atualiza dependências do Angular&lt;/code&gt; (Tarefas de manutenção que não afetam o usuário final)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Se você tem dificuldade de lembrar as regras, recomendo usar a biblioteca &lt;a href="https://github.com/commitizen/cz-cli" rel="noopener noreferrer"&gt;Commitizen&lt;/a&gt;. Ela transforma o comando &lt;code&gt;git commit&lt;/code&gt; em um questionário interativo no seu terminal, forçando o padrão correto.&lt;/p&gt;




&lt;h2&gt;
  
  
  Passo 2: Gerando a Versão Magicamente
&lt;/h2&gt;

&lt;p&gt;Agora que seus commits estão organizados no projeto, vamos usar uma ferramenta maravilhosa chamada &lt;code&gt;commit-and-tag-version&lt;/code&gt; (um fork moderno do antigo &lt;code&gt;standard-version&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Como nosso frontend é em Angular, podemos instalar isso facilmente na pasta do projeto usando o NPM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;frontend
npm i &lt;span class="nt"&gt;-D&lt;/span&gt; commit-and-tag-version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora, abra o seu &lt;code&gt;package.json&lt;/code&gt; e adicione este script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"release"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commit-and-tag-version"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;O que esse comando faz?&lt;/strong&gt; Quando você rodar &lt;code&gt;npm run release&lt;/code&gt;, a ferramenta vai:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ler todo o seu histórico de commits desde a última versão.&lt;/li&gt;
&lt;li&gt;Descobrir automaticamente qual é a próxima versão (baseado nos seus &lt;code&gt;feat:&lt;/code&gt; e &lt;code&gt;fix:&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Atualizar o número da versão dentro do &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Criar ou atualizar um arquivo &lt;code&gt;CHANGELOG.md&lt;/code&gt; com um resumo lindíssimo de tudo que foi feito.&lt;/li&gt;
&lt;li&gt;Fazer um commit automático com esses arquivos.&lt;/li&gt;
&lt;li&gt;Criar uma &lt;strong&gt;Git Tag&lt;/strong&gt; (ex: &lt;code&gt;v1.2.0&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Passo 3: O Workflow de Release no GitHub
&lt;/h2&gt;

&lt;p&gt;O nosso repositório local já está tagueado e o changelog foi gerado. Agora precisamos que o GitHub Actions perceba isso e crie uma aba de "Release" oficial lá no site do GitHub, para que qualquer pessoa possa baixar os binários ou ver as notas de atualização.&lt;/p&gt;

&lt;p&gt;Vamos criar um &lt;strong&gt;novo arquivo&lt;/strong&gt; de workflow. Crie &lt;code&gt;.github/workflows/release.yml&lt;/code&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;Generate GitHub Release&lt;/span&gt;

&lt;span class="c1"&gt;# Esse robô NÃO roda no push convencional. Ele só acorda quando uma Tag é enviada.&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;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;v*'&lt;/span&gt; &lt;span class="c1"&gt;# Aciona quando a tag começa com "v", ex: v1.0.0&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;create-release&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;Create Official Release&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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@v4&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;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# Essencial: baixa o histórico completo para ler as tags anteriores&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;Create GitHub Release&lt;/span&gt;
        &lt;span class="c1"&gt;# Uma action super popular para gerar a interface visual de Release no GitHub&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;softprops/action-gh-release@v2&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;generate_release_notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# O próprio GitHub ajuda a agrupar as PRs na tela&lt;/span&gt;
          &lt;span class="c1"&gt;# files: se quiser, pode anexar um .zip do backend compilado aqui!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  O Fluxo de Trabalho Completo (Dia a Dia)
&lt;/h2&gt;

&lt;p&gt;Parece muita coisa, mas olha como a sua vida e da sua equipe fica simples no dia a dia:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Você trabalha no seu código normalmente.&lt;/li&gt;
&lt;li&gt;Faz o commit usando o padrão: &lt;code&gt;git commit -m "feat: integra API C# com o kanjidex"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Quando a equipe decide que é hora de ir para produção, você roda:
&lt;code&gt;npm run release&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A ferramenta processa tudo, cria a tag e o &lt;code&gt;CHANGELOG.md&lt;/code&gt; localmente.&lt;/li&gt;
&lt;li&gt;Você envia tudo para o GitHub com um comando especial que empurra as tags junto com o código:
&lt;code&gt;git push --follow-tags&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pronto!&lt;/strong&gt; O seu workflow principal da Parte 1 vai fazer o deploy da aplicação, e o nosso novo workflow da Parte 3 vai criar uma Release oficial no repositório. Documentação em dia sem você precisar escrever uma única linha de relatório.&lt;/p&gt;




&lt;h2&gt;
  
  
  Resumo e Próximos Passos
&lt;/h2&gt;

&lt;p&gt;Temos integração contínua (CI), entrega contínua (CD), servidores gratuitos e versionamento semântico automatizado. É uma arquitetura de DevOps invejável!&lt;/p&gt;

&lt;p&gt;Contudo, conforme o repositório fica gigante, as execuções começam a demorar. Ficar baixando a pasta &lt;code&gt;node_modules&lt;/code&gt; e os pacotes &lt;code&gt;NuGet&lt;/code&gt; do zero a cada execução não faz o menor sentido e atrasa a esteira.&lt;/p&gt;

&lt;p&gt;Na &lt;strong&gt;Parte 4 (O Grande Final)&lt;/strong&gt;, vamos turbinar a performance do nosso pipeline implementando &lt;em&gt;Caches&lt;/em&gt; inteligentes e explorando as &lt;em&gt;Matrix Builds&lt;/em&gt; para testar múltiplos ambientes de uma só vez.&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A Conta Chegou? Como Fugir do Limite de 2.000 Minutos do GitHub Actions (Parte 2)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Mon, 03 Aug 2026 17:12:41 +0000</pubDate>
      <link>https://dev.to/erickg123/a-conta-chegou-como-fugir-do-limite-de-2000-minutos-do-github-actions-parte-2-cf9</link>
      <guid>https://dev.to/erickg123/a-conta-chegou-como-fugir-do-limite-de-2000-minutos-do-github-actions-parte-2-cf9</guid>
      <description>&lt;p&gt;No &lt;a href="https://dev.to/erickg123/do-zero-ao-deploy-seu-primeiro-pipeline-de-cicd-full-stack-com-github-actions-parte-1-3eg6"&gt;episódio anterior desta série&lt;/a&gt;, nós configuramos um pipeline incrível que compila e testa nossa aplicação Full-Stack (Angular e .NET) em paralelo a cada &lt;em&gt;push&lt;/em&gt;. A sensação de ver tudo verde e o deploy acontecendo sozinho é indescritível.&lt;/p&gt;

&lt;p&gt;Mas então, o projeto cresce. A equipe começa a mandar dezenas de &lt;em&gt;Pull Requests&lt;/em&gt; por dia. O tempo de &lt;em&gt;build&lt;/em&gt; aumenta. E de repente, você recebe aquele e-mail assustador do GitHub: &lt;strong&gt;"You have used 100% of your included Action minutes"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;A lua de mel com a automação acabou. A conta chegou.&lt;/p&gt;

&lt;p&gt;No artigo de hoje, vamos resolver esse problema pela raiz. Vou te ensinar a configurar um &lt;strong&gt;Self-Hosted Runner&lt;/strong&gt;: um jeito de fazer o GitHub rodar o seu pipeline de graça usando a sua própria máquina (ou uma VPS de 5 dólares).&lt;/p&gt;




&lt;h2&gt;
  
  
  O Problema dos 2.000 Minutos
&lt;/h2&gt;

&lt;p&gt;Se o seu repositório for público (Open Source), o GitHub Actions é 100% gratuito e ilimitado. Porém, se o seu repositório for &lt;strong&gt;privado&lt;/strong&gt; (o que é o caso de 99% dos projetos de empresas e startups), o GitHub te dá uma cota de &lt;strong&gt;2.000 minutos por mês&lt;/strong&gt; no plano gratuito.&lt;/p&gt;

&lt;p&gt;Parece muito, mas faça as contas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Seu &lt;em&gt;build&lt;/em&gt; de Angular demora 2 minutos.&lt;/li&gt;
&lt;li&gt;  Seu &lt;em&gt;build&lt;/em&gt; e testes de .NET demoram 3 minutos.&lt;/li&gt;
&lt;li&gt;  Total: 5 minutos por execução.&lt;/li&gt;
&lt;li&gt;  Com 20 &lt;em&gt;pushes&lt;/em&gt; por dia em uma equipe média, você queima 100 minutos por dia. Em 20 dias úteis, sua cota zerou.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depois disso, o GitHub começa a cobrar por minuto excedente, e a fatura em dólar pode assustar.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Solução: Self-Hosted Runners
&lt;/h2&gt;

&lt;p&gt;Por padrão, quando escrevemos &lt;code&gt;runs-on: ubuntu-latest&lt;/code&gt; no nosso arquivo YAML, estamos alugando uma máquina virtual dos servidores da Microsoft/GitHub para rodar nossos comandos.&lt;/p&gt;

&lt;p&gt;Um &lt;strong&gt;Self-Hosted Runner&lt;/strong&gt; é um agente (um programinha) que você instala em um computador seu. Ele fica ouvindo o GitHub e diz: &lt;em&gt;"Ei, não precisa alugar uma máquina. Pode mandar os comandos pra cá que eu executo localmente!"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vantagens:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fim do limite de minutos (você roda quantas vezes quiser de graça).&lt;/li&gt;
&lt;li&gt;Você pode usar uma máquina muito mais potente que a do GitHub.&lt;/li&gt;
&lt;li&gt;O agente pode acessar seu banco de dados local ou sua rede interna com facilidade.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Mão na Massa: Criando o seu Runner
&lt;/h3&gt;

&lt;p&gt;Vamos configurar um runner na sua própria máquina para testes (o processo é idêntico se você for fazer em uma VPS Linux na nuvem).&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 1: Gerando o Token no GitHub
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Vá até o seu repositório no GitHub.&lt;/li&gt;
&lt;li&gt;Clique em &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Actions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Runners&lt;/strong&gt; (na barra lateral esquerda).&lt;/li&gt;
&lt;li&gt;Clique no botão verde &lt;strong&gt;New self-hosted runner&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Escolha o Sistema Operacional da máquina onde você vai instalar o agente (Linux, Windows ou macOS).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O GitHub vai gerar uma tela com vários comandos prontos. É só copiar e colar no seu terminal.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 2: Instalando o Agente (Exemplo em Linux/WSL)
&lt;/h4&gt;

&lt;p&gt;Abra o seu terminal e cole os comandos fornecidos pelo GitHub. Geralmente, eles se parecem com isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Cria uma pasta para o runner e entra nela&lt;/span&gt;
&lt;span class="nb"&gt;mkdir &lt;/span&gt;actions-runner &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;actions-runner

&lt;span class="c"&gt;# 2. Baixa o pacote do runner&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; actions-runner-linux-x64-2.311.0.tar.gz &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;https://github.com/actions/runner/releases/download/]&lt;span class="o"&gt;(&lt;/span&gt;https://github.com/actions/runner/releases/download/&lt;span class="o"&gt;)&lt;/span&gt;...

&lt;span class="c"&gt;# 3. Extrai os arquivos&lt;/span&gt;
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf ./actions-runner-linux-x64-2.311.0.tar.gz

&lt;span class="c"&gt;# 4. Configura o runner e vincula ao seu repositório (O GitHub já coloca seu token aqui automaticamente)&lt;/span&gt;
./config.sh &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;https://github.com/SEU_USUARIO/SEU_REPOSITORIO]&lt;span class="o"&gt;(&lt;/span&gt;https://github.com/SEU_USUARIO/SEU_REPOSITORIO&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;--token&lt;/span&gt; ABCD1234EFGH5678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Durante a configuração, ele vai pedir um nome para o seu runner. Pode dar &lt;em&gt;Enter&lt;/em&gt; para aceitar o padrão ou chamar de &lt;code&gt;meu-servidor-01&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Passo 3: Ligando o Motor
&lt;/h4&gt;

&lt;p&gt;Para ligar o agente, basta rodar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Você verá a mensagem: &lt;code&gt;Connected to GitHub&lt;/code&gt; e &lt;code&gt;Listening for Jobs&lt;/code&gt;. Pronto! Sua máquina agora é uma extensão oficial do GitHub.&lt;/p&gt;




&lt;h2&gt;
  
  
  Atualizando o seu YAML (A Mágica Acontece)
&lt;/h2&gt;

&lt;p&gt;Agora precisamos dizer para o nosso pipeline da Parte 1 parar de usar as máquinas pagas do GitHub e começar a usar a nossa.&lt;/p&gt;

&lt;p&gt;Abra o seu arquivo &lt;code&gt;.github/workflows/main.yml&lt;/code&gt;. Vá nos seus &lt;em&gt;jobs&lt;/em&gt; e troque a linha &lt;code&gt;runs-on: ubuntu-latest&lt;/code&gt; por &lt;code&gt;runs-on: self-hosted&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Veja como fica:&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build-frontend&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;Build Angular App&lt;/span&gt;
    &lt;span class="c1"&gt;# A MÁGICA ESTÁ AQUI 👇&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;self-hosted&lt;/span&gt;
    &lt;span class="na"&gt;defaults&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="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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@v4&lt;/span&gt;
      &lt;span class="c1"&gt;# ... resto dos passos iguais ...&lt;/span&gt;

  &lt;span class="na"&gt;build-backend&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;Build &amp;amp; Test .NET API&lt;/span&gt;
    &lt;span class="c1"&gt;# A MÁGICA ESTÁ AQUI 👇&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;self-hosted&lt;/span&gt;
    &lt;span class="na"&gt;defaults&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="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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@v4&lt;/span&gt;
      &lt;span class="c1"&gt;# ... resto dos passos iguais ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Faça um &lt;em&gt;commit&lt;/em&gt; dessa alteração e olhe para o seu terminal. Você vai ver os comandos do Angular e do .NET passando voando na sua própria tela!&lt;/p&gt;




&lt;h2&gt;
  
  
  Dica de Ouro: Rodando em Background
&lt;/h2&gt;

&lt;p&gt;Se você fechar o terminal onde rodou o &lt;code&gt;./run.sh&lt;/code&gt;, o runner morre e seu pipeline para de funcionar. Para um ambiente de produção (como uma VPS), você precisa instalar o runner como um serviço do sistema, para que ele ligue sozinho se o servidor reiniciar.&lt;/p&gt;

&lt;p&gt;O GitHub já manda o script pronto para isso. Dentro da pasta do runner, basta parar a execução (&lt;code&gt;Ctrl+C&lt;/code&gt;) e rodar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./svc.sh &lt;span class="nb"&gt;install
sudo&lt;/span&gt; ./svc.sh start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora ele está rodando silenciosamente no fundo (background) e você pode fechar o terminal tranquilamente.&lt;/p&gt;




&lt;h2&gt;
  
  
  O Que Vem a Seguir?
&lt;/h2&gt;

&lt;p&gt;Se livrar dos custos com &lt;em&gt;Self-Hosted Runners&lt;/em&gt; é um alívio gigante, especialmente em projetos corporativos. Agora você tem infraestrutura de sobra.&lt;/p&gt;

&lt;p&gt;Mas, à medida que a equipe desenvolve e lança novas &lt;em&gt;features&lt;/em&gt;, surge outro problema: como saber exatamente o que foi para produção? Como organizar as versões (&lt;code&gt;v1.0.0&lt;/code&gt;, &lt;code&gt;v1.1.0&lt;/code&gt;) do seu software sem fazer isso na mão?&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;próximo episódio&lt;/strong&gt; desta série, vamos transformar nosso pipeline em uma máquina de versionamento profissional usando automação de &lt;em&gt;Tags&lt;/em&gt;, &lt;em&gt;Releases&lt;/em&gt; e criação de &lt;em&gt;Changelogs&lt;/em&gt; automáticos.&lt;/p&gt;

</description>
      <category>github</category>
      <category>devops</category>
      <category>infrastructure</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Do Zero ao Deploy: Seu Primeiro Pipeline de CI/CD Full-Stack com GitHub Actions (Parte 1)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Wed, 29 Jul 2026 13:45:24 +0000</pubDate>
      <link>https://dev.to/erickg123/do-zero-ao-deploy-seu-primeiro-pipeline-de-cicd-full-stack-com-github-actions-parte-1-3eg6</link>
      <guid>https://dev.to/erickg123/do-zero-ao-deploy-seu-primeiro-pipeline-de-cicd-full-stack-com-github-actions-parte-1-3eg6</guid>
      <description>&lt;p&gt;Seja honesto: quantas vezes você já terminou uma feature incrível, testou na sua máquina, e na hora de colocar em produção teve que rodar uma dezena de comandos manuais no terminal? Ou pior, teve que zipar pastas e arrastar para um servidor via FTP?&lt;/p&gt;

&lt;p&gt;Fazer deploy manual não é apenas chato; é uma receita garantida para erros humanos. Esquecer de rodar os testes, subir com a &lt;em&gt;connection string&lt;/em&gt; errada ou esquecer de instalar um pacote novo são clássicos do desenvolvimento de software.&lt;/p&gt;

&lt;p&gt;Nesta série, vamos resolver isso de uma vez por todas. Hoje, na &lt;strong&gt;Parte 1&lt;/strong&gt;, vamos criar um "robô" no GitHub Actions que vai testar e compilar sua aplicação Full-Stack (Frontend e Backend) &lt;strong&gt;em paralelo&lt;/strong&gt; toda vez que você fizer um &lt;em&gt;push&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que é CI/CD de forma simples?
&lt;/h2&gt;

&lt;p&gt;Esqueça as definições acadêmicas complexas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;CI (Continuous Integration):&lt;/strong&gt; É a garantia de que o seu código novo não quebrou o que já funcionava. Nosso pipeline vai baixar o código e rodar o &lt;em&gt;build&lt;/em&gt; e os testes automaticamente.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;CD (Continuous Deployment):&lt;/strong&gt; Se o CI passar e tudo estiver verde, o código é enviado automaticamente para o servidor de produção.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  O Cenário Real: Angular + C# (.NET)
&lt;/h2&gt;

&lt;p&gt;Em vez de um tutorial genérico com um site estático, vamos simular a vida real. Temos um repositório com uma API robusta em C# (.NET) e um Frontend dinâmico em Angular. &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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhijzhjglxqphrim1sz3.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqhijzhjglxqphrim1sz3.png" alt="Estrutura de Pastas" width="800" height="145"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Queremos que o GitHub Actions rode os dois processos simultaneamente para economizar tempo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Criando o nosso Workflow
&lt;/h3&gt;

&lt;p&gt;No seu repositório, crie um arquivo no seguinte caminho: &lt;code&gt;.github/workflows/main.yml&lt;/code&gt;. É aqui que a mágica acontece.&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;Full-Stack CI/CD Pipeline&lt;/span&gt;

&lt;span class="c1"&gt;# Quando esse robô deve trabalhar?&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="c1"&gt;# Roda sempre que houver código novo na main&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# JOB 1: O Frontend (Angular)&lt;/span&gt;
  &lt;span class="na"&gt;build-frontend&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;Build Angular App&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;defaults&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="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./frontend&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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@v4&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 Node.js&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@v4&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="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;22'&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;Install Dependencies &amp;amp; Build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;npm ci&lt;/span&gt;
          &lt;span class="s"&gt;npm run build&lt;/span&gt;

  &lt;span class="c1"&gt;# JOB 2: O Backend (.NET C#) - Roda em paralelo com o Frontend!&lt;/span&gt;
  &lt;span class="na"&gt;build-backend&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;Build &amp;amp; Test .NET API&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;defaults&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="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./backend&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&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@v4&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 .NET&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-dotnet@v4&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;dotnet-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;8.0.x'&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;Restore, Build, and Test&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;dotnet restore&lt;/span&gt;
          &lt;span class="s"&gt;dotnet build --no-restore&lt;/span&gt;
          &lt;span class="s"&gt;dotnet test --no-build --verbosity normal&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="c1"&gt;# Injetando variáveis de ambiente seguras no ambiente de teste&lt;/span&gt;
          &lt;span class="na"&gt;DB_CONNECTION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.DB_CONNECTION_STRING }}&lt;/span&gt;

  &lt;span class="c1"&gt;# JOB 3: O Deploy (Só roda se os dois de cima passarem)&lt;/span&gt;
  &lt;span class="na"&gt;deploy&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 Production&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;build-frontend&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;build-backend&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# A regra de ouro&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploying Magic&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;echo "🚀 Fazendo deploy seguro para o servidor..."&lt;/span&gt;
        &lt;span class="c1"&gt;# Aqui entrariam os scripts da sua nuvem (AWS, Azure, Vercel, etc.)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Entendendo a anatomia do YAML
&lt;/h3&gt;

&lt;p&gt;Se você nunca lidou com GitHub Actions, essas palavras podem parecer confusas. Vamos traduzir o que acabamos de escrever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;on:&lt;/strong&gt; Define o "gatilho" (trigger). É aqui que dizemos ao GitHub quando rodar nosso pipeline. No nosso caso, configuramos push na branch main. Ou seja: enviou código novo para a main, o robô acorda.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;jobs:&lt;/strong&gt; São as tarefas maiores que precisam ser feitas. Cada job (como build-frontend e build-backend) roda em um ambiente isolado. Por padrão, se você não disser o contrário, o GitHub tenta rodar todos os jobs ao mesmo tempo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;runs-on:&lt;/strong&gt; Diz ao GitHub qual sistema operacional queremos usar. ubuntu-latest significa que o GitHub vai nos emprestar uma máquina virtual Linux novinha e limpa para cada execução.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;steps:&lt;/strong&gt; É a receita do bolo. É a lista sequencial de passos que devem ser executados dentro de um Job.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;uses:&lt;/strong&gt; Quando usamos uses, estamos pegando "atalhos" — ações pré-fabricadas pela comunidade. Por exemplo, actions/checkout@v4 é uma ação pronta que diz: "baixe o código desse repositório para dentro da máquina virtual".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;run:&lt;/strong&gt; É aqui que você digita comandos de terminal, exatamente como faria na sua máquina local (ex: npm run build ou dotnet test).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  O Poder do Paralelismo e a Regra do Deploy
&lt;/h3&gt;

&lt;p&gt;Repare que dividimos nossa automação em partes estratégicas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paralelismo:&lt;/strong&gt; Como colocamos &lt;code&gt;build-frontend&lt;/code&gt; e &lt;code&gt;build-backend&lt;/code&gt; como &lt;em&gt;jobs&lt;/em&gt; separados, o GitHub Actions vai rodar os dois ao mesmo tempo. Isso corta o tempo do seu CI pela metade!&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdtz7ujfi3l48ylt65ta.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdtz7ujfi3l48ylt65ta.png" alt="Deploy em Paralelo" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Como você pode ver, enquanto o Angular é compilado, a API .NET já está sendo construída e testada.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Regra do Deploy (&lt;code&gt;needs&lt;/code&gt;):&lt;/strong&gt; O job de &lt;code&gt;deploy&lt;/code&gt; tem a propriedade &lt;code&gt;needs: [build-frontend, build-backend]&lt;/code&gt;. Isso significa que ele vai esperar os dois &lt;em&gt;builds&lt;/em&gt; terminarem.&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f806mhomctuixgxxkov.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f806mhomctuixgxxkov.png" alt="Deploy Concluído" width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Se o teste do C# quebrar, o deploy é cancelado e o código com bug não vai para produção. Tudo verde? O deploy é liberado!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Você também pode inspecionar cada etapa clicando nos jobs. É fantástico ver seus comandos sendo executados passo a passo em uma máquina virtual limpa:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm08jkdywx4kcuadnsizd.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm08jkdywx4kcuadnsizd.png" alt="Logs do .NET" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Os logs mostram detalhadamente desde o setup do .NET até a execução dos testes.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Segurança Real: O uso de Secrets
&lt;/h2&gt;

&lt;p&gt;No job do Backend, usamos &lt;code&gt;${{ secrets.DB_CONNECTION_STRING }}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nunca suba credenciais, senhas ou chaves de API no seu código-fonte!&lt;/strong&gt;&lt;br&gt;
Para passar essas informações de forma segura para o GitHub Actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vá na aba &lt;strong&gt;Settings&lt;/strong&gt; do seu repositório no GitHub.&lt;/li&gt;
&lt;li&gt;Na barra lateral, clique em &lt;strong&gt;Secrets and variables&lt;/strong&gt; &amp;gt; &lt;strong&gt;Actions&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjurvz7e0yrqtvzr3vlh1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjurvz7e0yrqtvzr3vlh1.png" alt="Aba de Actions" width="799" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Acessando a área de configuração segura do repositório.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clique no botão verde &lt;strong&gt;New repository secret&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Defina o nome (exatamente como você chamou no arquivo YAML) e cole o valor real da sua string de conexão.&lt;/li&gt;
&lt;/ol&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frx7vs1ioxgm97ez6o4ea.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frx7vs1ioxgm97ez6o4ea.png" alt="Criando o Secret" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;O valor inserido aqui é criptografado e nunca mais poderá ser lido diretamente, apenas atualizado ou apagado.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Uma vez salvo, o GitHub Actions vai injetar essa senha dinamicamente durante a execução, mantendo seus dados a salvo!&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhrdupuqlu9ncv5mbxtw.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Frhrdupuqlu9ncv5mbxtw.png" alt="Secret Criado" width="797" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Secret configurado com sucesso.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  E agora?
&lt;/h2&gt;

&lt;p&gt;Missão cumprida! Com esse workflow, você elevou o padrão tecnológico do seu projeto. Ter um processo de validação automatizado garante que o seu código seja testado de forma isolada, limpa e padronizada.&lt;/p&gt;

&lt;p&gt;Mas há um detalhe que ninguém te conta quando você começa a automatizar tudo: &lt;strong&gt;o limite gratuito.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;O GitHub te dá 2.000 minutos grátis por mês para rodar essas Actions. Com uma aplicação Full-Stack e a equipe crescendo, esses minutos evaporam rápido. Quando a cota acaba, a conta chega (literalmente).&lt;/p&gt;

&lt;p&gt;No &lt;strong&gt;próximo episódio da série&lt;/strong&gt;, vou te ensinar como fugir dessa limitação hospedando um robô do GitHub (&lt;em&gt;Self-Hosted Runner&lt;/em&gt;) de graça na sua própria máquina ou em uma VPS barata. Não perca!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>devops</category>
      <category>angular</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Além da Teoria: Implementando WCAG no Angular Moderno (v21+)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Tue, 21 Jul 2026 17:02:11 +0000</pubDate>
      <link>https://dev.to/erickg123/alem-da-teoria-implementando-wcag-no-angular-moderno-v21-4d0</link>
      <guid>https://dev.to/erickg123/alem-da-teoria-implementando-wcag-no-angular-moderno-v21-4d0</guid>
      <description>&lt;p&gt;Acessibilidade web (WCAG) é o tipo de tema que todo mundo concorda que é crucial, mas que raramente recebe a atenção prática que merece durante a nossa formação. Seja na faculdade ou na grande maioria dos cursos de desenvolvimento, o assunto ou é completamente ignorado ou é tratado de forma puramente teórica. São raros os conteúdos que mostram como aplicar as diretrizes da WCAG na realidade de um framework componentizado.&lt;/p&gt;

&lt;p&gt;Recentemente, passei pela experiência de implementar conformidade com a WCAG em um sistema corporativo real utilizando as versões mais recentes do Angular. Neste artigo, vamos entender o que é essa sopa de letrinhas, por que ela importa e como aplicar 4 abordagens práticas no ecossistema do Angular moderno.&lt;/p&gt;




&lt;h2&gt;
  
  
  Entendendo a WCAG: O que é e por que devemos nos importar?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;WCAG&lt;/strong&gt; significa &lt;em&gt;Web Content Accessibility Guidelines&lt;/em&gt; (Diretrizes de Acessibilidade para Conteúdo Web). Desenvolvido pelo W3C (World Wide Web Consortium), trata-se do padrão ouro global que define como tornar o conteúdo da web mais acessível para pessoas com deficiências visuais, auditivas, físicas, cognitivas e neurológicas.&lt;/p&gt;

&lt;p&gt;As diretrizes são organizadas sob 4 princípios fundamentais conhecidos como &lt;strong&gt;POUR&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Perceptível:&lt;/strong&gt; A informação e os componentes da interface devem ser apresentados de forma que os usuários possam percebê-los (ex: texto alternativo para imagens, contraste adequado).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operável:&lt;/strong&gt; Os componentes da interface e a navegação devem ser operáveis através de diferentes dispositivos (ex: navegação completa apenas via teclado, sem armadilhas de foco).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compreensível:&lt;/strong&gt; A informação e a operação da interface devem ser fáceis de entender (ex: mensagens de erro claras em formulários).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robusto:&lt;/strong&gt; O conteúdo deve ser robusto o suficiente para ser interpretado de forma confiável por uma ampla variedade de tecnologias assistivas (como leitores de tela).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Por que devemos seguir a WCAG?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inclusão e Alcance:&lt;/strong&gt; Desenvolver pensando na WCAG garante que o seu software possa ser utilizado por qualquer pessoa, independentemente de suas limitações permanentes, temporárias ou situacionais.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qualidade de Engenharia:&lt;/strong&gt; Código acessível exige HTML semântico. Interfaces acessíveis possuem uma estrutura de árvore do DOM muito mais limpa, o que melhora indiretamente o SEO (Search Engine Optimization) e a manutenibilidade do projeto.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conformidade Legal:&lt;/strong&gt; Em escala global, governos e empresas estão tornando a acessibilidade um requisito obrigatório por lei. Negligenciar a WCAG pode resultar em barreiras comerciais e até processos jurídicos para sistemas corporativos.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Longe da teoria dos slides, o jogo muda quando precisamos abrir o repositório. Vamos ao código.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Atributos ARIA Dinâmicos com Signals
&lt;/h2&gt;

&lt;p&gt;Acessibilidade em Single Page Applications (SPAs) precisa ser reativa. Quando o estado da interface muda, o leitor de tela precisa ser notificado imediatamente.&lt;/p&gt;

&lt;p&gt;Em formulários de login, por exemplo, a ação de alternar a visibilidade da senha exige que o &lt;code&gt;aria-label&lt;/code&gt; mude dinamicamente para que o usuário saiba exatamente o que o botão fará a seguir. Com a reatividade dos &lt;strong&gt;Signals&lt;/strong&gt;, conseguimos vincular isso diretamente ao DOM utilizando o prefixo &lt;code&gt;attr.&lt;/code&gt;.&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input-group"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; 
    &lt;span class="na"&gt;[type]=&lt;/span&gt;&lt;span class="s"&gt;"showPassword() ? 'text' : 'password'"&lt;/span&gt; 
    &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; 
    &lt;span class="na"&gt;formControlName=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; 
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; 
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
    &lt;span class="na"&gt;[attr.aria-label]=&lt;/span&gt;&lt;span class="s"&gt;"showPassword() ? 'Esconder senha' : 'Mostrar senha'"&lt;/span&gt;
    &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"togglePasswordVisibility()"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;[class]=&lt;/span&gt;&lt;span class="s"&gt;"showPassword() ? 'pi pi-eye-slash' : 'pi pi-eye'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Navegação por Teclado e Gerenciamento de Foco
&lt;/h2&gt;

&lt;p&gt;Um dos maiores problemas de acessibilidade na web moderna é a quebra de navegação por teclado. Elementos nativos como &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; e &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; já possuem comportamento de foco nativo, mas quando criamos componentes customizados (como timelines ou itens de menu baseados em &lt;code&gt;div&lt;/code&gt;), eles ficam invisíveis para a tecla &lt;code&gt;Tab&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Para resolver isso, precisamos injetar explicitamente o &lt;code&gt;tabindex="0"&lt;/code&gt; (colocando o elemento na sequência natural de tabulação) e capturar os eventos de teclado correspondentes ao clique (&lt;code&gt;Enter&lt;/code&gt; ou &lt;code&gt;Espaço&lt;/code&gt;).&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;div&lt;/span&gt; 
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"timeline-item"&lt;/span&gt; 
  &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
  &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt;
  &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"selectEvent(event)"&lt;/span&gt;
  &lt;span class="na"&gt;(keydown.enter)=&lt;/span&gt;&lt;span class="s"&gt;"selectEvent(event)"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"timeline-marker"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"timeline-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h3&amp;gt;&lt;/span&gt;{{ event.title }}&lt;span class="nt"&gt;&amp;lt;/h3&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ event.description }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Papéis Semânticos (Roles) Explícitos para Interfaces Ricas
&lt;/h2&gt;

&lt;p&gt;Quando a árvore do DOM é gerada através de múltiplos componentes aninhados do Angular, a semântica nativa do HTML pode se perder facilmente em meio a um mar de tags customizadas e invólucros estruturais.&lt;/p&gt;

&lt;p&gt;Se você está construindo estruturas complexas, como uma barra de navegação ou um menu de configurações, o uso do atributo &lt;code&gt;role&lt;/code&gt; ajuda o leitor de tela a mapear a árvore de acessibilidade corretamente.&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;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sidebar-menu"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  @for (item of menuItems(); track item.id) {
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"menu-item"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"menuitem"&lt;/span&gt; &lt;span class="na"&gt;tabindex=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;(keydown.enter)=&lt;/span&gt;&lt;span class="s"&gt;"navigate(item.path)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;[class]=&lt;/span&gt;&lt;span class="s"&gt;"item.icon"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;{{ item.label }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    @if (item.hasSeparator) {
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"menu-separator"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"separator"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    }
  }
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Alternativas de Texto para Botões Apenas com Ícones
&lt;/h2&gt;

&lt;p&gt;Botões que contêm apenas ícones (como botões de busca com uma lupa, exclusão com uma lixeira ou fechamento com um "X") são visualmente limpos, mas completamente mudos para um leitor de tela se não forem tratados. O software de acessibilidade tentará ler a classe CSS do ícone (ex: &lt;code&gt;pi-search&lt;/code&gt;), resultando em uma experiência confusa.&lt;/p&gt;

&lt;p&gt;Adicionar um &lt;code&gt;aria-label&lt;/code&gt; descritivo garante que a função do botão seja anunciada perfeitamente.&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;button&lt;/span&gt; 
  &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; 
  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-button-rounded"&lt;/span&gt;
  &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Pesquisar registros"&lt;/span&gt;
  &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"executeSearch()"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;i&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pi pi-search"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/i&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusão e Fluxo de Testes
&lt;/h2&gt;

&lt;p&gt;Escrever código acessível não aumenta a complexidade da sua arquitetura; pelo contrário, força a escrita de um HTML mais limpo, semântico e robusto. Acessibilidade não é uma feature secundária para entregar no final do projeto, é parte fundamental da qualidade da engenharia do software.&lt;/p&gt;

&lt;p&gt;Para validar essas implementações no dia a dia, recomendo fortemente integrar testes manuais ao seu fluxo de desenvolvimento:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Desconecte o mouse:&lt;/strong&gt; Tente realizar o fluxo principal do seu sistema (como autenticação e navegação) usando apenas as teclas &lt;code&gt;Tab&lt;/code&gt;, &lt;code&gt;Shift + Tab&lt;/code&gt; e &lt;code&gt;Enter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Leitores Reais:&lt;/strong&gt; Utilize ferramentas como o &lt;strong&gt;NVDA&lt;/strong&gt; (Windows) ou o &lt;strong&gt;VoiceOver&lt;/strong&gt; (macOS) em conjunto com o navegador para ouvir como a sua aplicação está se comportando em tempo real.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O ecossistema do Angular nos dá todas as ferramentas necessárias para criar aplicações inclusivas. Cabe a nós, desenvolvedores, virar a chave da teoria para a prática.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>architecture</category>
      <category>angular</category>
    </item>
    <item>
      <title>Angular 22: O Framework finalmente encontrou sua identidade?</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Fri, 12 Jun 2026 17:38:45 +0000</pubDate>
      <link>https://dev.to/erickg123/angular-22-o-framework-finalmente-encontrou-sua-identidade-3ba5</link>
      <guid>https://dev.to/erickg123/angular-22-o-framework-finalmente-encontrou-sua-identidade-3ba5</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;Durante anos, uma crítica acompanhou o Angular em praticamente toda discussão sobre Front-end:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"O Angular é poderoso, mas complexo."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;E, para ser justo, essa crítica tinha fundamento.&lt;br&gt;
NgModules, Zone.js, Change Detection global, decorators em excesso, Reactive Forms verbosos e uma curva de aprendizado considerável fizeram muita gente migrar para alternativas consideradas mais simples.&lt;/p&gt;

&lt;p&gt;Mas algo interessante aconteceu entre o Angular 16 e o Angular 22.&lt;/p&gt;

&lt;p&gt;Pela primeira vez desde o lançamento do Ivy, não parece que estamos vendo apenas uma sequência de novas funcionalidades. Estamos vendo uma direção arquitetural clara.&lt;/p&gt;

&lt;p&gt;O Angular 22 não é importante por causa de uma única feature. Ele é importante porque consolida uma transformação iniciada anos atrás: &lt;strong&gt;Angular agora é oficialmente um framework Signal-First.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  O Angular de 2026 é muito diferente do Angular de 2020
&lt;/h2&gt;

&lt;p&gt;Se você ficou alguns anos longe do framework, provavelmente lembrará de algo assim:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppModule&lt;/li&gt;
&lt;li&gt;SharedModule&lt;/li&gt;
&lt;li&gt;Guards em Classes&lt;/li&gt;
&lt;li&gt;Change Detection padrão&lt;/li&gt;
&lt;li&gt;Zone.js&lt;/li&gt;
&lt;li&gt;Reactive Forms&lt;/li&gt;
&lt;li&gt;Webpack&lt;/li&gt;
&lt;li&gt;RxJS para praticamente tudo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Hoje um projeto Angular moderno nasce com:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standalone Components&lt;/li&gt;
&lt;li&gt;Functional Guards&lt;/li&gt;
&lt;li&gt;&lt;code&gt;inject()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Signals&lt;/li&gt;
&lt;li&gt;Signal Forms&lt;/li&gt;
&lt;li&gt;Resource API&lt;/li&gt;
&lt;li&gt;OnPush por padrão&lt;/li&gt;
&lt;li&gt;Hydration&lt;/li&gt;
&lt;li&gt;Esbuild + Vite&lt;/li&gt;
&lt;li&gt;SSR de primeira classe&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A quantidade de conceitos obrigatórios diminuiu drasticamente. E talvez essa seja a maior evolução do framework.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. OnPush finalmente virou o padrão
&lt;/h2&gt;

&lt;p&gt;Durante anos praticamente todo desenvolvedor Angular experiente fazia isso:&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="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-dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./dashboard.component.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;changeDetection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChangeDetectionStrategy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OnPush&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;DashboardComponent&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Por quê?&lt;/strong&gt; Porque o comportamento padrão verificava componentes demais.&lt;br&gt;
Agora o Angular oficializou essa prática. Você não precisa mais adicionar &lt;code&gt;OnPush&lt;/code&gt; manualmente em cada componente.&lt;/p&gt;

&lt;p&gt;Parece uma mudança pequena. &lt;strong&gt;Não é.&lt;/strong&gt; Ela mostra que o framework assumiu definitivamente uma arquitetura baseada em reatividade explícita.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Menos verificações globais.&lt;/li&gt;
&lt;li&gt;Menos trabalho para CPU.&lt;/li&gt;
&lt;li&gt;Mais previsibilidade.&lt;/li&gt;
&lt;li&gt;Mais performance.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  2. Signals deixaram de ser novidade e viraram fundação
&lt;/h2&gt;

&lt;p&gt;Quando Signals apareceram no Angular 16, muita gente tratou como uma funcionalidade interessante. No Angular 22 eles já fazem parte da identidade do framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Antes:&lt;/strong&gt;&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;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterComponent&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;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&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="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;p&gt;&lt;strong&gt;Agora:&lt;/strong&gt;&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;signal&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CounterComponent&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="nf"&gt;signal&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="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&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="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Template:&lt;/strong&gt;&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;button&lt;/span&gt; &lt;span class="na"&gt;(click)=&lt;/span&gt;&lt;span class="s"&gt;"increment()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  {{ count() }}
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A principal diferença é que o Angular sabe exatamente quem depende daquele estado. Nada de verificações desnecessárias.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Computed Signals: reatividade sem esforço
&lt;/h2&gt;

&lt;p&gt;Uma das APIs mais elegantes introduzidas pelo framework.&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;signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PedidoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;itens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;valor&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="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;computed&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;itens&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&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;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;valor&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="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;&lt;strong&gt;Template:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;Total: {{ total() }}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sempre que a lista mudar, o total será recalculado automaticamente.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sem subscriptions.&lt;/li&gt;
&lt;li&gt;Sem Subjects.&lt;/li&gt;
&lt;li&gt;Sem RxJS.&lt;/li&gt;
&lt;li&gt;Sem código extra.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Signal Forms finalmente ficaram prontos para produção
&lt;/h2&gt;

&lt;p&gt;Quando os Signals foram lançados, a pergunta era inevitável: &lt;em&gt;"Mas e os formulários?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A resposta demorou alguns releases. Agora chegou. Signal Forms se tornaram uma alternativa moderna aos tradicionais Reactive Forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reactive Forms:&lt;/strong&gt;&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="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FormGroup&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;nome&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;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;email&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;FormControl&lt;/span&gt;&lt;span class="p"&gt;(&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Abordagem baseada em Signals:&lt;/strong&gt;&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;signal&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsuarioComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;atualizarNome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nome&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt; &lt;span class="o"&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="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;nome&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;p&gt;Os formulários ficam mais próximos da arquitetura reativa moderna do framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Menos boilerplate.&lt;/li&gt;
&lt;li&gt;Mais previsibilidade.&lt;/li&gt;
&lt;li&gt;Melhor tipagem.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Resource API: a evolução mais subestimada do Angular
&lt;/h2&gt;

&lt;p&gt;Essa talvez seja a feature mais importante que pouca gente está comentando.&lt;br&gt;
Historicamente tínhamos duas opções: &lt;code&gt;Observable&lt;/code&gt; ou &lt;code&gt;Promise&lt;/code&gt;.&lt;br&gt;
Agora temos &lt;strong&gt;Resources&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo simplificado:&lt;/strong&gt;&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;resource&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="nx"&gt;usuarios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;loader&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="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;/api/users&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;r&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Template:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;@if (usuarios.isLoading()) {
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Carregando...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
}

@if (usuarios.hasValue()) {
  &lt;span class="nt"&gt;&amp;lt;app-user-list&lt;/span&gt;
    &lt;span class="na"&gt;[users]=&lt;/span&gt;&lt;span class="s"&gt;"usuarios.value()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/app-user-list&amp;gt;&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Resource encapsula: Dados, Loading, Error, Reload e Cancelamento. Tudo integrado com Signals. Não substitui RxJS, mas elimina uma enorme quantidade de código para casos simples.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. &lt;code&gt;inject()&lt;/code&gt; mudou a forma de escrever Angular
&lt;/h2&gt;

&lt;p&gt;Durante anos escrevemos isso:&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="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Router&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;&lt;strong&gt;Agora:&lt;/strong&gt;&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;private&lt;/span&gt; &lt;span class="nx"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;router&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ou dentro de uma Functional Guard:&lt;/strong&gt;&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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authGuard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CanActivateFn&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="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AuthService&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;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isLoggedIn&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;A API ficou mais limpa, mais funcional e mais fácil de compor.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. O Angular está cada vez mais Zone-less
&lt;/h2&gt;

&lt;p&gt;Se existe uma palavra que define a evolução recente do Angular, ela é: &lt;strong&gt;Controle&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Durante anos o framework monitorava tudo através do &lt;code&gt;Zone.js&lt;/code&gt;. Hoje temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Signals&lt;/li&gt;
&lt;li&gt;OnPush&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;li&gt;Renderização mais previsível&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tudo aponta para a mesma direção: Menos mágica. Mais controle. Mais performance. O Angular ainda suporta Zone.js. Mas é evidente que o futuro não gira mais em torno dele.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. SSR e Hydration estão amadurecendo rapidamente
&lt;/h2&gt;

&lt;p&gt;Durante muito tempo SSR parecia uma funcionalidade opcional. Hoje não.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuração básica:&lt;/strong&gt;&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="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;provideClientHydration&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O Angular reutiliza o HTML renderizado pelo servidor em vez de reconstruir toda a tela.&lt;br&gt;
Benefícios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Melhor SEO&lt;/li&gt;
&lt;li&gt;Melhor LCP&lt;/li&gt;
&lt;li&gt;Melhor experiência mobile&lt;/li&gt;
&lt;li&gt;Menos JavaScript executado&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  9. O HTTP Client também evoluiu
&lt;/h2&gt;

&lt;p&gt;Outra mudança pouco comentada. Agora é possível utilizar &lt;code&gt;Fetch&lt;/code&gt; como backend principal:&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="nf"&gt;bootstrapApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="nf"&gt;provideHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nf"&gt;withFetch&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="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso aproxima o Angular dos padrões modernos da Web. Menos dependências legadas. Mais alinhamento com o ecossistema JavaScript.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Angular e IA: o início de uma nova fase
&lt;/h2&gt;

&lt;p&gt;O time do Angular está investindo cada vez mais em integração com ferramentas de IA. Estamos vendo iniciativas envolvendo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebMCP&lt;/li&gt;
&lt;li&gt;Agent Skills&lt;/li&gt;
&lt;li&gt;Ferramentas para assistentes inteligentes&lt;/li&gt;
&lt;li&gt;Melhor suporte a automação&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ainda é cedo para saber o impacto real. Mas o sinal é claro: O Angular quer ser um framework preparado para um futuro onde IA participa ativamente do desenvolvimento.&lt;/p&gt;

&lt;h2&gt;
  
  
  O que esperar do Angular 23, 24 e além?
&lt;/h2&gt;

&lt;p&gt;Se eu tivesse que apostar no futuro do framework, apostaria em cinco movimentos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Menos RxJS obrigatório:&lt;/strong&gt; RxJS continuará relevante, mas cada vez mais opcional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mais APIs baseadas em Signals:&lt;/strong&gt; Signals se tornaram o centro da arquitetura. Tudo novo gira em torno deles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zone.js cada vez menos relevante:&lt;/strong&gt; A direção do framework é clara.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build ainda mais rápido:&lt;/strong&gt; Esbuild e Vite foram apenas o começo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IA integrada ao fluxo de desenvolvimento:&lt;/strong&gt; O Angular já começou a investir nessa direção.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Angular 22 não impressiona por uma única funcionalidade. Ele impressiona porque fecha vários ciclos iniciados anos atrás.&lt;/p&gt;

&lt;p&gt;Signals amadureceram. Signal Forms amadureceram. Resources amadureceram. OnPush virou padrão. SSR evoluiu. O ecossistema de build ficou absurdamente rápido. O framework ficou mais previsível, mais performático e mais alinhado com a Web moderna.&lt;/p&gt;

&lt;p&gt;Depois de acompanhar a evolução do Angular desde a era dos NgModules gigantes e do Webpack dominando tudo, talvez a melhor definição seja esta:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O Angular finalmente parece um framework que sabe exatamente para onde está indo.&lt;/strong&gt; E isso é algo que não acontecia há bastante tempo.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;E você?&lt;/strong&gt; Qual foi a mudança mais importante do Angular nos últimos anos? Deixe nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Desconstruindo o Build: A Revolução do Angular (E a diferença entre Compilador e Bundler)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:40 +0000</pubDate>
      <link>https://dev.to/erickg123/desconstruindo-o-build-a-revolucao-do-angular-e-a-diferenca-entre-compilador-e-bundler-4p9f</link>
      <guid>https://dev.to/erickg123/desconstruindo-o-build-a-revolucao-do-angular-e-a-diferenca-entre-compilador-e-bundler-4p9f</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;Na nossa jornada de migração do YMS (do Angular 16 para o 21), mencionei no primeiro artigo que o tempo de compilação e o &lt;em&gt;hot reload&lt;/em&gt; despencaram. A experiência de desenvolvimento foi para outro patamar. Mas por que isso aconteceu?&lt;/p&gt;

&lt;p&gt;Muitos desenvolvedores acreditam que o Angular "trocou de compilador" nas versões recentes. Mas isso é um mito. Para entender o que realmente deixou o framework tão rápido, precisamos separar duas ferramentas fundamentais que rodam no seu terminal: o &lt;strong&gt;Compilador&lt;/strong&gt; e o &lt;strong&gt;Bundler&lt;/strong&gt; (Empacotador).&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Desfazendo a confusão: Compilador vs. Bundler
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A. O Compilador (Ivy)&lt;/strong&gt;&lt;br&gt;
O compilador é o tradutor. O navegador não entende TypeScript, nem entende os decorators do Angular (&lt;code&gt;@Component&lt;/code&gt;, &lt;code&gt;@Injectable&lt;/code&gt;) ou a sintaxe de template do HTML (&lt;code&gt;@if&lt;/code&gt;, &lt;code&gt;{{ variavel }}&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;O papel do compilador do Angular (chamado de &lt;strong&gt;Ivy&lt;/strong&gt;) é ler esse código e transformá-lo em instruções JavaScript puras. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A grande sacada aqui é:&lt;/strong&gt; O compilador não mudou. O Angular usa o Ivy desde a versão 9. Tanto o nosso projeto legado no Angular 16 quanto a versão nova no Angular 21 rodam o mesmíssimo compilador por baixo dos panos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;B. O Bundler (O Empacotador)&lt;/strong&gt;&lt;br&gt;
O &lt;em&gt;Bundler&lt;/em&gt; é o gerente de logística. Depois que o Ivy traduz os arquivos, você fica com milhares de pequenos arquivos JS espalhados. O &lt;em&gt;Bundler&lt;/em&gt; pega tudo isso, resolve as dependências (quem importa quem), aplica o &lt;em&gt;Tree-Shaking&lt;/em&gt; (que explicamos no artigo anterior), minifica o código e empacota tudo em um ou mais arquivos finais para o navegador baixar.&lt;/p&gt;

&lt;p&gt;E é aqui que a mágica da nossa migração aconteceu: nós trocamos o gerente de logística.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. O Passado: A Era do Webpack
&lt;/h3&gt;

&lt;p&gt;No Angular 16, o padrão absoluto para empacotar a aplicação era o &lt;strong&gt;Webpack&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;O Webpack é uma ferramenta fantástica, mas tem um problema de arquitetura para o modo de desenvolvimento: ele precisa construir a aplicação inteira antes de poder servi-la.&lt;/p&gt;

&lt;p&gt;Em um sistema corporativo pesado como o nosso YMS (cheio de telas, regras logísticas e componentes densos do PrimeNG), o Webpack precisava rastrear milhares de arquivos, compilar tudo, empacotar em memória e só então liberar a tela no &lt;code&gt;localhost&lt;/code&gt;. Qualquer mudança num CSS fazia o Webpack recalcular uma parte gigantesca desse pacote. O resultado? Segundos (ou até minutos) olhando para o terminal esperando o &lt;em&gt;reload&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. O Presente: A Revolução do Esbuild + Vite
&lt;/h3&gt;

&lt;p&gt;A partir das versões mais recentes (consolidado como padrão no 17+), o Angular chutou o Webpack e reescreveu todo o seu &lt;em&gt;pipeline&lt;/em&gt; de &lt;em&gt;build&lt;/em&gt; utilizando duas ferramentas absurdamente rápidas: o &lt;strong&gt;Esbuild&lt;/strong&gt; e o &lt;strong&gt;Vite&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Esbuild:&lt;/strong&gt; É um &lt;em&gt;bundler&lt;/em&gt; escrito em Go (uma linguagem compilada e de altíssima performance). Ao contrário do Webpack (escrito em JavaScript), o Esbuild paraleliza o trabalho usando todos os núcleos do seu processador. Ele constrói dependências pesadas (como o PrimeNG ou o RxJS) em milissegundos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vite:&lt;/strong&gt; Essa é a estrela do modo de desenvolvimento (&lt;code&gt;ng serve&lt;/code&gt;). O Vite inverte a lógica do Webpack. Ele não constrói a aplicação inteira antes de iniciar. Ele inicia o servidor instantaneamente e deixa o navegador pedir os arquivos &lt;strong&gt;sob demanda&lt;/strong&gt; (usando &lt;em&gt;Native ES Modules&lt;/em&gt;). Se você está na tela de "Login", o Vite só pede para o Angular compilar e entregar os arquivos do Login. O resto do YMS fica ignorado até você navegar para lá.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. O Impacto na Prática
&lt;/h3&gt;

&lt;p&gt;Essa mudança do Webpack para o Esbuild/Vite mudou a nossa vida no projeto. O &lt;em&gt;Hot Module Replacement&lt;/em&gt; (HMR) agora é instantâneo. Você altera a cor de um botão no arquivo SCSS, e a tela pisca e atualiza em frações de segundo, sem perder o estado da página.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nós não escrevemos código mais rápido, mas paramos de esperar a máquina trabalhar. O ciclo de &lt;em&gt;feedback&lt;/em&gt; rápido destrava a produtividade de qualquer equipe de Front-end.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;O Angular 21 não é mais rápido porque tem um novo compilador, mas sim porque o ecossistema de &lt;em&gt;build&lt;/em&gt; ao redor dele evoluiu para ferramentas de próxima geração. &lt;/p&gt;

&lt;p&gt;Se você ainda está preso em versões antigas do Angular, atualize. Nem que seja apenas para sentir o prazer de um &lt;code&gt;ng serve&lt;/code&gt; que inicia em menos de 2 segundos.&lt;/p&gt;

&lt;p&gt;Você já notou essa diferença de tempo de &lt;em&gt;build&lt;/em&gt; nos seus projetos atualizados? Quanto tempo demorava o seu &lt;code&gt;ng serve&lt;/code&gt; mais lento na época do Webpack? Deixa aí nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Desconstruindo o Build: Como o Tree-Shaking realmente funciona (e por que o Bundle importa)</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:38 +0000</pubDate>
      <link>https://dev.to/erickg123/desconstruindo-o-build-como-o-tree-shaking-realmente-funciona-e-por-que-o-bundle-importa-1hc7</link>
      <guid>https://dev.to/erickg123/desconstruindo-o-build-como-o-tree-shaking-realmente-funciona-e-por-que-o-bundle-importa-1hc7</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;No primeiro artigo da nossa série sobre a migração do YMS (do Angular 16 para o 21), mencionei que uma das maiores vitórias de abandonar o &lt;code&gt;app.module.ts&lt;/code&gt; e adotar os &lt;em&gt;Standalone Components&lt;/em&gt; foi a melhora drástica no &lt;strong&gt;Tree-Shaking&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Teoria é legal, mas na nossa área o que manda são os números. Durante essa refatoração estrutural, matando Módulos, limpando arquivos sem uso e ajustando lógicas legadas, nós conseguimos reduzir o tamanho da nossa pasta de build de assustadores &lt;strong&gt;40MB&lt;/strong&gt; para cerca de &lt;strong&gt;15MB&lt;/strong&gt;. Uma redução de mais de 60% no "peso" do sistema!&lt;/p&gt;

&lt;p&gt;Como nós, desenvolvedores, adoramos entender como as engrenagens rodam por baixo dos panos, decidi fazer esta pausa na série principal para desconstruir esse processo. Como exatamente o framework conseguiu arrancar 25MB de "gordura" do nosso projeto?&lt;/p&gt;

&lt;p&gt;A resposta atende por dois nomes: o novo &lt;em&gt;bundler&lt;/em&gt; (Esbuild/Vite) e um &lt;em&gt;Tree-Shaking&lt;/em&gt; finalmente eficiente. Mas antes de balançarmos a árvore, precisamos entender exatamente o que é o "cesto de frutas" que estamos enviando para o navegador do nosso usuário.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Mas primeiro: O que é esse tal de "Bundle"?
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;Bundle&lt;/em&gt; (ou empacotamento) é o resultado final do processo de &lt;em&gt;build&lt;/em&gt; do Angular.&lt;/p&gt;

&lt;p&gt;Quando você escreve o código do seu YMS, você cria centenas (ou milhares, num projeto de 5 anos!) de arquivos TypeScript, HTML e CSS. Mas o navegador do seu usuário não entende TypeScript e nem sabe como carregar essa estrutura complexa de pastas.&lt;/p&gt;

&lt;p&gt;O papel do &lt;em&gt;Bundler&lt;/em&gt; é ler todo esse código, processá-lo, compilá-lo para JavaScript nativo e juntar tudo em apenas um (ou alguns poucos) arquivos. É esse pacote único que o navegador baixa e executa para rodar o seu sistema.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Qual o impacto prático do Bundle?
&lt;/h3&gt;

&lt;p&gt;O tamanho do &lt;em&gt;Bundle&lt;/em&gt; tem um impacto direto e brutal tanto na &lt;em&gt;Developer Experience&lt;/em&gt; (DX) quanto na &lt;em&gt;User Experience&lt;/em&gt; (UX):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Velocidade do Build:&lt;/strong&gt; Durante o desenvolvimento, um &lt;em&gt;bundle&lt;/em&gt; menor significa que o &lt;em&gt;hot reload&lt;/em&gt; (ver a alteração na tela ao salvar o arquivo) é quase instantâneo, o que melhora muito a nossa produtividade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo de Carregamento Inicial:&lt;/strong&gt; Para o usuário, um &lt;em&gt;bundle&lt;/em&gt; menor significa um download mais rápido. Se o seu YMS tem um pacote de dezenas de megabytes, o usuário vai ficar olhando para uma tela branca por muito tempo, especialmente em redes móveis ou conexões instáveis de armazéns logísticos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tempo de Análise e Execução:&lt;/strong&gt; O navegador não apenas baixa o arquivo; ele precisa interpretar e executar todo o JavaScript. Um arquivo maior consome mais CPU e tempo, o que pode travar a interface e gerar uma experiência péssima.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Resumo da ópera:&lt;/strong&gt; O &lt;em&gt;bundle&lt;/em&gt; é o arquivo final que roda o seu sistema, e o tamanho dele dita a velocidade da aplicação. Otimizá-lo é uma prioridade absoluta em sistemas &lt;em&gt;Enterprise&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  3. A Analogia da Árvore: Entendendo o Tree-Shaking
&lt;/h3&gt;

&lt;p&gt;Imagine que o seu projeto é uma árvore frutífera. O tronco é o seu &lt;code&gt;main.ts&lt;/code&gt; e os galhos são os seus componentes, serviços e bibliotecas externas (como o PrimeNG ou o RxJS). As folhas são as funções e métodos escritos no código.&lt;/p&gt;

&lt;p&gt;Quando chega a hora de enviar esse projeto para produção (o momento do &lt;em&gt;build&lt;/em&gt;), o seu &lt;em&gt;Bundler&lt;/em&gt; balança essa árvore com força. O objetivo? Fazer com que todas as folhas mortas (código que você escreveu ou importou da biblioteca, mas nunca usou de fato na tela) caiam no chão e não sejam enviadas para o pacote final do usuário.&lt;/p&gt;

&lt;p&gt;Isso é o &lt;strong&gt;Tree-Shaking&lt;/strong&gt;: a eliminação de código morto (&lt;em&gt;dead-code elimination&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Como o Bundler sabe o que é código morto?&lt;/strong&gt;&lt;br&gt;
O &lt;em&gt;Tree-Shaking&lt;/em&gt; só é possível graças à estrutura estática dos módulos do JavaScript moderno (a famosa sintaxe de &lt;code&gt;import&lt;/code&gt; e &lt;code&gt;export&lt;/code&gt;). Como essa sintaxe não pode ser condicional (você não pode colocar um &lt;code&gt;import&lt;/code&gt; dentro de um &lt;code&gt;if&lt;/code&gt;), o &lt;em&gt;bundler&lt;/em&gt; consegue ler todos os seus arquivos antes de executá-los e montar um &lt;strong&gt;Grafo de Dependências&lt;/strong&gt; perfeito (um mapa exato de quem chama quem).&lt;/p&gt;

&lt;p&gt;Se você importa uma biblioteca inteira de utilitários, mas só usa a função &lt;code&gt;ordenar()&lt;/code&gt;, o &lt;em&gt;bundler&lt;/em&gt; rastreia isso. As outras 50 funções da biblioteca são marcadas como "código morto" e podadas da árvore.&lt;/p&gt;


&lt;h3&gt;
  
  
  4. O Problema: Por que o NgModule era o inimigo do Tree-Shaking?
&lt;/h3&gt;

&lt;p&gt;Aqui entra o pulo do gato e o motivo pelo qual nosso &lt;em&gt;build&lt;/em&gt; antigo batia a assustadora casa dos 40MB.&lt;/p&gt;

&lt;p&gt;Os Módulos do Angular agrupavam as coisas. Pense no famoso &lt;code&gt;SharedModule&lt;/code&gt;. Nós costumávamos colocar absolutamente tudo lá dentro: botões, diretivas, &lt;em&gt;pipes&lt;/em&gt; de formatação de data, dezenas de componentes de modal do PrimeNG, etc.&lt;/p&gt;

&lt;p&gt;Quando você importava o &lt;code&gt;SharedModule&lt;/code&gt; no seu &lt;code&gt;DashboardModule&lt;/code&gt;, o &lt;em&gt;bundler&lt;/em&gt; olhava para aquilo e pensava: &lt;em&gt;"Opa, ele importou o módulo inteiro. Como o Angular injeta isso de forma dinâmica em tempo de execução, eu não tenho certeza de quais partes desse SharedModule o Dashboard realmente vai usar. Na dúvida, vou empacotar TUDO para não quebrar a aplicação em produção."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O resultado?&lt;/strong&gt; Se o seu Dashboard precisasse de apenas um botão, ele acabava carregando o peso de todos os modais, tabelas e &lt;em&gt;pipes&lt;/em&gt; de outras partes do sistema. A árvore não balançava direito. Estávamos enviando código morto para o navegador o tempo todo.&lt;/p&gt;


&lt;h3&gt;
  
  
  5. A Solução: A Transparência dos Standalone Components
&lt;/h3&gt;

&lt;p&gt;É por isso que os componentes &lt;em&gt;Standalone&lt;/em&gt; são uma revolução de performance, e não apenas de sintaxe. Ao remover o Módulo genérico da jogada, o contrato de dependência fica explícito diretamente no componente:&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="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-dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;standalone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// O bundler vê EXATAMENTE o que está sendo usado&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ButtonModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DatePipe&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;button&amp;gt;Clique aqui: {{ dataAtual | date }}&amp;lt;/button&amp;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;DashboardComponent&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;p&gt;Agora, o &lt;em&gt;bundler&lt;/em&gt; consegue montar um mapa preciso. Ele sabe que o &lt;code&gt;DashboardComponent&lt;/code&gt; só usa o botão e o &lt;em&gt;pipe&lt;/em&gt; de data. Todo o resto do PrimeNG ou de componentes compartilhados que não estão nesse &lt;em&gt;array&lt;/em&gt; de &lt;code&gt;imports&lt;/code&gt; é sumariamente descartado no processo de &lt;em&gt;build&lt;/em&gt;. A tesoura finalmente funciona!&lt;/p&gt;




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

&lt;p&gt;Migrar um projeto maduro e complexo como o nosso YMS para componentes &lt;em&gt;Standalone&lt;/em&gt; dá um trabalho considerável, mas o pagamento vem na balança: &lt;strong&gt;25MB a menos&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O JavaScript que o navegador do usuário baixa fica estritamente limitado ao que a tela atual precisa. &lt;em&gt;Menos código = carregamento mais rápido = operadores logísticos muito mais felizes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;E você, já chegou a analisar o tamanho do &lt;em&gt;bundle&lt;/em&gt; do seu projeto com ferramentas como o &lt;code&gt;source-map-explorer&lt;/code&gt; antes e depois do Standalone? Compartilha os resultados aí nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Desconstruindo o Build: Chunks, Raio-X e a Anatomia do Navegador</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:36 +0000</pubDate>
      <link>https://dev.to/erickg123/desconstruindo-o-build-chunks-raio-x-e-a-anatomia-do-navegador-5d68</link>
      <guid>https://dev.to/erickg123/desconstruindo-o-build-chunks-raio-x-e-a-anatomia-do-navegador-5d68</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;No nosso último artigo sobre a desconstrução do &lt;em&gt;build&lt;/em&gt;, mostrei como reduzimos o pacote do nosso YMS de 40MB para 15MB através de &lt;em&gt;Standalone Components&lt;/em&gt; e &lt;em&gt;Tree-Shaking&lt;/em&gt;. Mas, como bons engenheiros, não paramos por aí. 15MB ainda é muita coisa.&lt;/p&gt;

&lt;p&gt;Sempre que rodamos o comando &lt;code&gt;ng build&lt;/code&gt;, o terminal nos joga uma sopa de letrinhas com centenas de arquivos (&lt;em&gt;chunks&lt;/em&gt;) e tamanhos variados. Mas o que exatamente o Angular está gerando? Como o navegador "mastiga" essa pasta de &lt;em&gt;build&lt;/em&gt;? E, mais importante, como descobrimos o que está escondido dentro desses megabytes?&lt;/p&gt;

&lt;p&gt;Hoje, vamos abrir a caixa preta da compilação, entender a matemática da performance e fazer um Raio-X da nossa aplicação.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. Como o navegador entende a sua pasta de Build?
&lt;/h3&gt;

&lt;p&gt;Quando você programa em Angular, você escreve TypeScript, usa SCSS e cria templates dinâmicos. Mas o navegador (Chrome, Edge, Safari) é "burro" para isso. Ele só entende o tripé sagrado da web: &lt;strong&gt;HTML, CSS e JavaScript puro&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;O papel do seu &lt;em&gt;Bundler&lt;/em&gt; (no Angular 21, o Esbuild) é traduzir a sua engenharia complexa para esse formato básico. O resultado cai na pasta &lt;code&gt;dist/&lt;/code&gt;. Mas como o navegador lê isso?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Porta de Entrada:&lt;/strong&gt; O navegador baixa o &lt;code&gt;index.html&lt;/code&gt;. Ele é um arquivo minúsculo que não tem quase nada na tela, mas contém as tags &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; para o seu CSS e &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; para o seu JavaScript.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O Download e o Bloqueio:&lt;/strong&gt; O navegador começa a baixar o seu arquivo principal (&lt;code&gt;main.js&lt;/code&gt;). É aqui que a mágica (ou a tragédia) acontece. Diferente de uma imagem de 2MB que apenas aparece na tela, um arquivo JavaScript de 2MB precisa ser &lt;strong&gt;Baixado, Interpretado (Parsed), Compilado e Executado&lt;/strong&gt; pela &lt;em&gt;Main Thread&lt;/em&gt; (a linha de execução principal) do navegador.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Tela Branca:&lt;/strong&gt; Enquanto o navegador está executando esse JavaScript pesado, ele "trava". Nenhuma interface é desenhada e nenhum clique funciona. É o famoso gargalo de &lt;strong&gt;TTI&lt;/strong&gt; (&lt;em&gt;Time to Interactive&lt;/em&gt;). É por isso que arquivos grandes são mortais. O peso do JS custa caro na rede (download) e caríssimo na CPU do celular ou do computador do usuário (execução).&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. Lendo o Terminal: O que são os "Chunks"?
&lt;/h3&gt;

&lt;p&gt;Sabendo que arquivos gigantes travam o navegador, o Angular usa a tática de "dividir para conquistar". Quando rodamos o &lt;em&gt;build&lt;/em&gt; do nosso YMS, recebemos o seguinte log:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Initial chunk files                 | Names       | Raw size
styles.css                          | styles      | 1.10 MB 
main.js                             | main        | 19.33 kB 
chunk-DXO7V6OT.js                   | -           | 26.94 kB 
                                    | Initial total | 1.18 MB

Lazy chunk files                    | Names                       | Raw size
chunk-QPFHIJ3Z.js                   | -                           | 513.35 kB 
editar.component-US2MQII7.js        | editar-component            | 342.09 kB 
painel.component-CX2TJGIN.js        | painel-component            | 281.48 kB 
...and 390 more lazy chunks files. Use "--verbose" to show all the files.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para um desenvolvedor desavisado, ver "390 arquivos" gerados pode parecer um erro. Na verdade, é a prova de uma arquitetura de sucesso.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que é um Chunk?&lt;/strong&gt; É um fragmento isolado do seu sistema. O código alfanumérico no nome (&lt;code&gt;DXO7V6OT&lt;/code&gt;) serve para o &lt;em&gt;Cache Busting&lt;/em&gt;: se você alterar apenas esse arquivo no futuro, o nome muda, forçando o navegador a baixar a nova versão e reaproveitar o resto que está intocado no cache.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Initial Chunk Files (O Kit de Sobrevivência):&lt;/strong&gt; Essa é a métrica mais importante do seu Front-end. O nosso &lt;em&gt;Initial total&lt;/em&gt; deu &lt;strong&gt;1.18 MB&lt;/strong&gt;. Esse é o pacote absoluto que o navegador precisa baixar e executar para exibir a primeira tela (como o Login). Manter isso baixo é o que garante que o usuário não fique olhando para uma tela branca.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lazy Chunk Files (A Sobremesa sob Demanda):&lt;/strong&gt; O Angular pegou nossa tela gigantesca de &lt;code&gt;painel.component&lt;/code&gt;, isolou as dependências dela e gerou um arquivo separado de 281 kB. O navegador &lt;strong&gt;nunca&lt;/strong&gt; fará o download desses 281 kB a menos que o usuário clique no botão para acessar o painel. Dividimos 15MB em fatias cirúrgicas de carregamento!&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  3. Qual é o "Tamanho Ideal" e os Performance Budgets?
&lt;/h3&gt;

&lt;p&gt;Com base em tudo isso, definimos limites estritos (&lt;em&gt;Performance Budgets&lt;/em&gt;). No Angular, você pode configurar isso no &lt;code&gt;angular.json&lt;/code&gt; para que o &lt;em&gt;build&lt;/em&gt; "quebre" (falhe no CI/CD) se você passar do limite.&lt;/p&gt;

&lt;p&gt;O nosso alvo corporativo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;O Initial Bundle&lt;/strong&gt; deve ficar abaixo de 2MB (descompactado). Isso garante que, mesmo em um armazém logístico com internet 3G oscilante, a tela de login apareça em menos de 3 segundos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Os Lazy Chunks&lt;/strong&gt; devem ter no máximo 500KB. Se um componente Lazy passa disso, significa que a tela está fazendo coisas demais e precisa ser quebrada em sub-rotas ou blocos &lt;code&gt;@defer&lt;/code&gt; no HTML.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. O Raio-X do Bundle: Achando a "Gordura"
&lt;/h3&gt;

&lt;p&gt;Tínhamos os limites definidos, tínhamos 15MB totais divididos em 390 &lt;em&gt;chunks&lt;/em&gt;, mas queríamos saber: o que exatamente tem dentro desses &lt;em&gt;chunks&lt;/em&gt; mais pesados?&lt;/p&gt;

&lt;p&gt;Na era do Angular 16 (Webpack), usávamos a biblioteca &lt;code&gt;source-map-explorer&lt;/code&gt;. Mas com o Esbuild (Angular 17+), a compilação é tão agressiva que as ferramentas antigas quebram.&lt;/p&gt;

&lt;p&gt;A solução oficial agora é gerar o relatório nativo do compilador:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng build &lt;span class="nt"&gt;--configuration&lt;/span&gt; production &lt;span class="nt"&gt;--stats-json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depois, basta jogar esse arquivo &lt;code&gt;stats.json&lt;/code&gt; no site oficial do &lt;strong&gt;Esbuild Bundle Analyzer&lt;/strong&gt; (&lt;code&gt;esbuild.github.io/analyze&lt;/code&gt;). O resultado é um mapa visual interativo que mostra cada &lt;em&gt;byte&lt;/em&gt; do sistema. Ao rodar essa auditoria no YMS, encontramos três "vazamentos" clássicos de sistemas corporativos que estavam devorando nossos megabytes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Guerra dos Gráficos:&lt;/strong&gt; Estávamos empacotando TRÊS bibliotecas de gráficos simultaneamente em telas diferentes: ECharts (~1MB), ApexCharts (~1MB) e Chart.js (~190KB). Padronizar a empresa para usar apenas uma delas limparia 1.2MB numa tacada só.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;O Mistério do Service Gigante:&lt;/strong&gt; Achamos um serviço (&lt;code&gt;modelo-carroceria.service.ts&lt;/code&gt;) pesando inacreditáveis 500KB. Serviços normais têm 2KB! O motivo? Um JSON estático gigantesco (uma base de dados de caminhões) estava "chumbado" direto no código TypeScript, em vez de vir via API ou de um arquivo JSON estático na pasta &lt;code&gt;assets&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geradores de PDF Duplicados:&lt;/strong&gt; O sistema importava a biblioteca &lt;code&gt;jspdf&lt;/code&gt; isoladamente, mas também importava um componente pronto de terceiros que já trazia o &lt;code&gt;jspdf&lt;/code&gt; embutido. O compilador não conseguiu unificar os dois, cobrando o peso em dobro.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Saber codificar telas bonitas é o básico do desenvolvimento web. Mas entender a anatomia do navegador, dominar a geração de &lt;em&gt;chunks&lt;/em&gt; e saber medir o impacto de cada importação usando o &lt;em&gt;Esbuild Analyzer&lt;/em&gt; é o que separa "fazer código" de &lt;strong&gt;Engenharia de Software&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Você já abriu a caixa preta do &lt;em&gt;build&lt;/em&gt; no seu projeto Angular mais recente? Tomou algum susto com o tamanho de alguma biblioteca escondida? Compartilhem as experiências nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Migrando um YMS de 5 anos: Do Angular 16 ao 21 (Parte 9) - UX Corporativa: Dark Mode, Grids Dinâmicos e PrimeNG na prática</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:30 +0000</pubDate>
      <link>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-9-ux-corporativa-dark-mode-grids-2bj7</link>
      <guid>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-9-ux-corporativa-dark-mode-grids-2bj7</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;Chegamos ao nono e &lt;strong&gt;último artigo&lt;/strong&gt; da nossa série documentando a evolução estrutural de um YMS (&lt;em&gt;Yard Management System&lt;/em&gt;) gigante, saindo do Angular 16 direto para o 21. Já refatoramos o núcleo, as rotas, os &lt;em&gt;Signals&lt;/em&gt;, a estrutura de pastas e a internacionalização. &lt;/p&gt;

&lt;p&gt;Mas, para o usuário final, a arquitetura invisível do código não importa. O que importa é a tela. E hoje, os usuários de sistemas corporativos B2B (Backoffice, ERPs, YMS) não aceitam mais interfaces cinzas com cara de Windows 95. Eles exigem a mesma fluidez, UX e beleza dos aplicativos que usam no celular.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. A Evolução do PrimeNG e o Padrão Ouro dos Grids
&lt;/h3&gt;

&lt;p&gt;Nossa interface sempre foi alicerçada no &lt;strong&gt;PrimeNG&lt;/strong&gt;. O pulo de 5 versões do Angular exigiu adequações estruturais pesadas na forma como lidávamos com os estilos. A biblioteca evoluiu muito para adotar um sistema de design baseado em &lt;em&gt;tokens&lt;/em&gt; (&lt;em&gt;CSS Variables&lt;/em&gt;) e uma integração profunda com &lt;em&gt;Utility Classes&lt;/em&gt; (o PrimeFlex).&lt;/p&gt;

&lt;p&gt;Sistemas logísticos respiram dados. Tabelas (&lt;code&gt;&amp;lt;p-table&amp;gt;&lt;/code&gt;) não são apenas para visualização; elas são a principal ferramenta de trabalho do operador. &lt;/p&gt;

&lt;p&gt;Implementamos recursos modernos que mudaram completamente a percepção de performance e usabilidade do usuário:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Filtros e Ordenação no lado do Servidor:&lt;/strong&gt; Absolutamente essencial quando você tem milhões de registros na base de dados e não pode travar o navegador tentando filtrar isso no Front-end.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scroll Virtual (Lazy Loading UI):&lt;/strong&gt; Substituindo a paginação tradicional por um &lt;em&gt;scroll&lt;/em&gt; infinito suave. O Angular destrói as linhas HTML que sobem pela tela e recria as que aparecem embaixo. Isso consome recursos de renderização da CPU apenas para as linhas que estão visíveis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Salvamento de Estado (Stateful Grids):&lt;/strong&gt; O usuário reordena as colunas, ajusta as larguras, sai da tela e, ao voltar no dia seguinte, a tabela "lembra" exatamente da preferência dele usando o &lt;em&gt;Local Storage&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  2. A Inevitável Chegada do Dark Mode
&lt;/h3&gt;

&lt;p&gt;O &lt;em&gt;Dark Mode&lt;/em&gt; (Modo Escuro) não é mais um "frufru" visual. Para operadores logísticos que passam 10 horas por dia olhando para painéis de controle e gráficos de pátio em salas escuras de monitoramento, é uma questão de saúde visual e ergonomia.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Mágica dos Tokens:&lt;/strong&gt; Com a arquitetura de tokens CSS das versões modernas do Angular e do PrimeNG, a alternância de temas parou de exigir a recarga inteira da página ou a inserção manual de dezenas de classes no HTML com JavaScript. Agora, mudar para o tema escuro é apenas uma substituição de variáveis nativas CSS (como &lt;code&gt;--surface-a&lt;/code&gt; ou &lt;code&gt;--text-color&lt;/code&gt;) na raiz do documento (&lt;code&gt;:root&lt;/code&gt;). A transição é instantânea e extremamente leve para o navegador.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Conclusão: O Veredito da Jornada
&lt;/h3&gt;

&lt;p&gt;Pular 5 versões de um ecossistema complexo exige sangue frio, testes extensivos e muita leitura de &lt;em&gt;changelogs&lt;/em&gt;. Mas o resultado final faz cada erro de compilação no terminal valer a pena:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um código absurdamente mais limpo (Adeus, &lt;code&gt;app.module&lt;/code&gt; e &lt;code&gt;ngOnDestroy&lt;/code&gt;!).&lt;/li&gt;
&lt;li&gt;Uma compilação instantânea no ambiente de desenvolvimento (graças ao novo &lt;em&gt;bundler&lt;/em&gt; com &lt;em&gt;Vite&lt;/em&gt; e &lt;em&gt;esbuild&lt;/em&gt;).&lt;/li&gt;
&lt;li&gt;Uma aplicação rápida como um raio no navegador do usuário (com &lt;em&gt;Signals&lt;/em&gt; e &lt;em&gt;Zoneless&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manter sistemas atualizados não é apenas perseguir a novidade tecnológica pelo &lt;em&gt;hype&lt;/em&gt;. É garantir &lt;strong&gt;agilidade e segurança&lt;/strong&gt; para continuar entregando valor ao negócio nos próximos 5 anos, sem que o código vire um legado intocável que ninguém na equipe tem coragem de mexer.&lt;/p&gt;

&lt;p&gt;Espero que essa série de 9 artigos tenha ajudado a desmistificar alguns conceitos modernos do Angular e inspirado você a encarar a modernização das suas bases de código por aí.&lt;/p&gt;

&lt;p&gt;Um grande abraço e até a próxima refatoração! 🚀&lt;/p&gt;

&lt;p&gt;Quais foram os maiores desafios de UI/UX que vocês já enfrentaram em sistemas corporativos internos? Deixem nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Migrando um YMS de 5 anos: Do Angular 16 ao 21 (Parte 8) - i18n Enterprise e por que escolhemos o Transloco</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:27 +0000</pubDate>
      <link>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-8-i18n-enterprise-e-a-batalha-das-5733</link>
      <guid>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-8-i18n-enterprise-e-a-batalha-das-5733</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;Nesta jornada modernizando o nosso YMS, já passamos por performance, estrutura de pastas e padrões de código. Mas quando falamos de sistemas &lt;em&gt;Enterprise&lt;/em&gt;, um requisito não-funcional frequentemente assombra as equipes de Front-end: a Internacionalização (i18n).&lt;/p&gt;

&lt;p&gt;Muitos tutoriais ensinam a traduzir um botão de "Salvar" para "Save". Mas na trincheira de um sistema logístico real e de grande porte, as coisas são muito mais complexas. Não se trata apenas de traduzir palavras, mas de definir &lt;em&gt;como&lt;/em&gt; essa tradução será processada na arquitetura da aplicação.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. O Desafio Numérico (Muito além do texto)
&lt;/h3&gt;

&lt;p&gt;Antes de falar de bibliotecas de tradução, precisamos lembrar que i18n afeta a matemática da tela. O peso de um caminhão no Brasil é &lt;code&gt;45.500,00 kg&lt;/code&gt;. Nos EUA, precisa ser renderizado obrigatoriamente como &lt;code&gt;45,500.00 kg&lt;/code&gt;. Uma vírgula no lugar errado em um sistema logístico gera multas milionárias nas rodovias.&lt;/p&gt;

&lt;p&gt;Felizmente, aproveitando os &lt;em&gt;Pipes&lt;/em&gt; nativos (&lt;code&gt;DecimalPipe&lt;/code&gt; e &lt;code&gt;DatePipe&lt;/code&gt;) combinados com a injeção do &lt;code&gt;LOCALE_ID&lt;/code&gt; correto na inicialização da aplicação, o Angular resolve isso sozinho:&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;span&amp;gt;&lt;/span&gt;Peso Lido: {{ pesoTotalCapturado | number:'1.2-2' }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Data: {{ momentoPesagem | date:'short' }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. O Dilema Arquitetural: Runtime vs. Build-time
&lt;/h3&gt;

&lt;p&gt;Quando fomos refatorar a tradução dos textos e &lt;em&gt;labels&lt;/em&gt; do sistema, esbarramos na grande dúvida: Abraçar o nativo &lt;code&gt;@angular/localize&lt;/code&gt; ou utilizar bibliotecas de terceiros?&lt;/p&gt;

&lt;p&gt;Para entender a nossa decisão, precisamos separar as abordagens em duas categorias:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Tradução em Tempo de Build (AOT) - &lt;code&gt;@angular/localize&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
A solução nativa do Angular é fantástica para a performance da tela, pois ela embute os textos direto no HTML. Mas ela faz isso gerando &lt;strong&gt;uma versão inteira do sistema para cada idioma&lt;/strong&gt; durante o &lt;code&gt;ng build&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;O Problema no YMS:&lt;/strong&gt; Se temos 3 idiomas (PT, EN, ES), o nosso tempo de &lt;em&gt;build&lt;/em&gt; no CI/CD triplica. Para um sistema gigante, gerar e hospedar múltiplas pastas de &lt;em&gt;build&lt;/em&gt; (uma para cada língua) começou a travar a nossa esteira de &lt;em&gt;deploy&lt;/em&gt;. Além disso, a troca de idioma exigia o recarregamento total da página.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;B. Tradução em Tempo de Execução (Runtime) - `@jsverse/transloco&lt;/strong&gt;`&lt;br&gt;
Foi aqui que a biblioteca &lt;strong&gt;Transloco&lt;/strong&gt; brilhou para nós. Ela carrega arquivos JSON com as traduções &lt;em&gt;enquanto&lt;/em&gt; o usuário navega.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A Vitória da Manutenção:&lt;/strong&gt; Com o Transloco, nós fazemos &lt;strong&gt;apenas um build&lt;/strong&gt;. A grande sacada arquitetural dessa biblioteca são os &lt;strong&gt;Escopos (Lazy Load Scopes)&lt;/strong&gt;. Se o usuário acessa o módulo de Balança, o Transloco não baixa o dicionário do sistema inteiro; ele baixa apenas um micro-JSON de 2KB exclusivo daquela tela. O impacto na performance de rede é mínimo, a troca de idioma é em tempo real, e a nossa esteira de CI/CD agradece.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;
  
  
  3. Na Prática: Escrevendo código com o Transloco
&lt;/h3&gt;

&lt;p&gt;O Transloco nos oferece uma Developer Experience (DX) incrível, permitindo usar &lt;em&gt;Pipes&lt;/em&gt; ou diretivas estruturais, mantendo o HTML limpo e otimizado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No HTML:&lt;/strong&gt;&lt;br&gt;
Em vez de usar &lt;em&gt;Pipes&lt;/em&gt; isolados para cada palavra (o que força o Angular a criar múltiplas inscrições por baixo dos panos), usamos a diretiva estrutural &lt;code&gt;*transloco&lt;/code&gt;. Ela injeta a função de tradução apenas naquele bloco:&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;ng-container&lt;/span&gt; &lt;span class="na"&gt;*transloco=&lt;/span&gt;&lt;span class="s"&gt;"let t; read: 'balanca'"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-primary"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {{ t('btnConfirmarPesagem') }}
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
    {{ t('msgFila', { qtdCaminhoes: 5 }) }}
  &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;No TypeScript:&lt;/strong&gt;&lt;br&gt;
Para casos onde o texto precisa nascer dentro do código (como notificações de &lt;em&gt;Toast&lt;/em&gt; dinâmicas ou mensagens de validação vindas da API), injetamos o &lt;code&gt;TranslocoService&lt;/code&gt;:&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;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;inject&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MessageService&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;primeng/api&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;TranslocoService&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;@jsverse/transloco&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="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;OperacaoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;translocoService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TranslocoService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;finalizarOperacao&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Buscando a tradução em tempo real no TypeScript&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msgSucesso&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;operacao.toastSucesso&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;severity&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="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;msgSucesso&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;h3&gt;
  
  
  Conclusão
&lt;/h3&gt;

&lt;p&gt;O nativo &lt;code&gt;@angular/localize&lt;/code&gt; é o rei da performance absoluta de renderização. Porém, para o nosso cenário corporativo, o &lt;strong&gt;Transloco&lt;/strong&gt; entregou o equilíbrio perfeito: resolveu o gargalo do nosso tempo de &lt;em&gt;build&lt;/em&gt; no CI/CD, evitou a complexidade de gerenciar múltiplos &lt;em&gt;deploys&lt;/em&gt; e manteve a performance da aplicação alta graças ao carregamento sob demanda (Lazy Loading) dos dicionários.&lt;/p&gt;

&lt;p&gt;No nosso &lt;strong&gt;nono e último artigo&lt;/strong&gt; da série, vamos fechar com chave de ouro falando sobre &lt;strong&gt;UX Corporativa&lt;/strong&gt;: como implementamos o tão pedido &lt;em&gt;Dark Mode&lt;/em&gt; e dominamos as customizações de Grids pesadas do &lt;em&gt;PrimeNG&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;E vocês, preferem o modelo em tempo de execução (&lt;code&gt;Transloco&lt;/code&gt;/&lt;code&gt;ngx-translate&lt;/code&gt;) ou já adotaram o empacotamento em tempo de &lt;em&gt;build&lt;/em&gt; do Angular? Conta aí nos comentários! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>code</category>
    </item>
    <item>
      <title>Migrando um YMS de 5 anos: Do Angular 16 ao 21 (Parte 7) - Clean Architecture: A nova estrutura de pastas por domínios</title>
      <dc:creator>Erick Gabriel dos Santos Alves</dc:creator>
      <pubDate>Thu, 04 Jun 2026 01:40:25 +0000</pubDate>
      <link>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-7-clean-architecture-a-nova-estrutura-de-17dh</link>
      <guid>https://dev.to/erickg123/migrando-um-yms-de-5-anos-do-angular-16-ao-21-parte-7-clean-architecture-a-nova-estrutura-de-17dh</guid>
      <description>&lt;p&gt;Fala, comunidade dev! 👋&lt;/p&gt;

&lt;p&gt;Nas últimas 6 partes dessa série, mergulhamos fundo no código: &lt;em&gt;Standalone Components&lt;/em&gt;, Rotas, &lt;em&gt;Signals&lt;/em&gt; e &lt;em&gt;Zoneless&lt;/em&gt;. Mas refatorar a arquitetura técnica sem arrumar a "casa" (a estrutura de pastas) é colocar motor de Ferrari em chassi de fusca.&lt;/p&gt;

&lt;p&gt;Um projeto de 5 anos geralmente sofre do mesmo mal genérico de organização, e hoje vou mostrar como aplicamos conceitos de &lt;strong&gt;Clean Architecture&lt;/strong&gt; e &lt;strong&gt;Domain-Driven Design (DDD)&lt;/strong&gt; no Front-end para salvar a manutenção do nosso YMS (&lt;em&gt;Yard Management System&lt;/em&gt;).&lt;/p&gt;




&lt;h3&gt;
  
  
  1. O Erro Clássico: Organização por Tipo Técnico
&lt;/h3&gt;

&lt;p&gt;Lá no Angular 14/16, a literatura (e as ferramentas de CLI) nos ensinava a agrupar arquivos pelo que eles &lt;em&gt;eram&lt;/em&gt;, e não pelo que eles &lt;em&gt;faziam&lt;/em&gt;. A estrutura clássica de um sistema parecia assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/
 ├── components/ (misturava botões com painéis de negócio)
 ├── models/     (centenas de interfaces jogadas aqui)
 ├── services/   (tudo que era API ficava aqui)
 └── views/      (as páginas em si)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O Pesadelo Cognitivo:&lt;/strong&gt; Para alterar a tela de "Agendamento", o desenvolvedor precisava abrir a pasta de &lt;code&gt;views&lt;/code&gt; para achar o HTML, depois pular para a pasta de &lt;code&gt;models&lt;/code&gt; para entender a interface, e depois caçar a chamada de API na pasta de &lt;code&gt;services&lt;/code&gt;. O código que mudava junto morava em bairros completamente diferentes do projeto.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  2. A Virada: Estrutura Orientada a Domínios (Features)
&lt;/h3&gt;

&lt;p&gt;Na migração para o Angular 21, pivotamos a arquitetura para &lt;strong&gt;domínios de negócio&lt;/strong&gt;. A regra de ouro virou: &lt;em&gt;se o código muda junto, ele deve morar junto.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Nossa nova arquitetura isola responsabilidades. O módulo (agora &lt;em&gt;Standalone&lt;/em&gt;) de &lt;code&gt;balanca&lt;/code&gt; não faz a menor ideia do que acontece dentro de &lt;code&gt;agendamento&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/
 ├── core/       (Interceptors, Auth, Guards - estritamente técnico e Singleton)
 ├── shared/     (Botões, Pipes, componentes UI "burros" e reaproveitáveis)
 └── features/   (Os Domínios do Negócio)
      ├── agendamento/
      │    ├── models/
      │    ├── services/
      │    └── components/
      ├── balanca/
      │    ├── models/
      │    ├── services/
      │    └── components/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Por que isso muda o jogo?
&lt;/h3&gt;

&lt;p&gt;Organizar arquivos pode parecer preciosismo estético, mas em bases de código maduras e sistemas &lt;em&gt;Enterprise&lt;/em&gt;, é a linha tênue entre entregar uma &lt;em&gt;feature&lt;/em&gt; em 2 horas ou em 2 dias.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Onboarding rápido:&lt;/strong&gt; Um desenvolvedor júnior entra no time hoje para arrumar um &lt;em&gt;bug&lt;/em&gt; na tela da Balança. Ele abre a pasta &lt;code&gt;features/balanca&lt;/code&gt; e absolutamente tudo que ele precisa para entender aquele contexto está lá dentro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalabilidade e Desacoplamento:&lt;/strong&gt; Se o negócio crescer absurdamente, nós podemos extrair a pasta &lt;code&gt;balanca&lt;/code&gt; inteira e transformá-la em uma biblioteca independente (Angular Workspace/Nx) ou até mesmo em um &lt;strong&gt;Micro-frontend&lt;/strong&gt; sem esforço, pois ela não compartilha "lixo" com outros domínios.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Ter um código moderno usando &lt;em&gt;Signals&lt;/em&gt; e rodando sem o &lt;code&gt;zone.js&lt;/code&gt; é maravilhoso, mas é a arquitetura de pastas que dita a velocidade e a sanidade mental do time no longo prazo.&lt;/p&gt;

&lt;p&gt;No próximo post (&lt;strong&gt;Parte 8&lt;/strong&gt;), vamos abordar um desafio &lt;em&gt;Enterprise&lt;/em&gt; raiz que costuma dar muita dor de cabeça em sistemas legados: a &lt;strong&gt;Internacionalização de dados e traduções dinâmicas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;E como está a pasta &lt;code&gt;src/app&lt;/code&gt; dos projetos de vocês hoje? Mais parecida com o primeiro modelo (técnico) ou com o segundo modelo (orientado a domínio)? Comentem aí! 👇&lt;/p&gt;

</description>
      <category>angular</category>
      <category>typescript</category>
      <category>frontend</category>
      <category>braziliandevs</category>
    </item>
  </channel>
</rss>
