<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Fernando Miguel - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Fernando Miguel - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 06 Jul 2026 15:53:00 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/author/fernando-miguel/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Processos filhos em Node.js: tudo o que você precisa saber ]]>
                </title>
                <description>
                    <![CDATA[ Como usar spawn(), exec(), execFile() e fork() > Atualização: este artigo agora faz parte do livro "Node.js Beyond The Basics" do autor. Leia a versão atualizada deste conteúdo e mais sobre o Node em  jscomplete.com/node-beyond-basics [https://jscomplete.com/g/node-cps] (em inglês). O desempenho sem bloqueios e em thread única do Node.js funciona ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/processos-filhos-em-node-js-tudo-o-que-voce-precisa-saber/</link>
                <guid isPermaLink="false">63300f0b5c046e06ec87a978</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Miguel ]]>
                </dc:creator>
                <pubDate>Wed, 09 Nov 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_I56pPhzO1VQw8SIsv8wYNA.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/node-js-child-processes-everything-you-need-to-know-e69498fe970a/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Node.js Child Processes: Everything you need to know</a>
      </p><h4 id="como-usar-spawn-exec-execfile-e-fork-"><strong>Como usar<strong> spawn(), exec(), execFile() </strong>e<strong> fork()</strong></strong><br></h4><blockquote><strong>Atualização<strong>:</strong></strong> este artigo agora faz parte do livro "Node.js Beyond The Basics" do autor.<br><br>Leia a versão atualizada deste conteúdo e mais sobre o Node em <strong><strong><a href="https://jscomplete.com/g/node-cps" rel="noopener">jscomplete.com/node-beyond-basics</a></strong></strong> (em inglês).</blockquote><p>O desempenho sem bloqueios e em <em>thread</em> única do Node.js funciona muito bem para um único processo. Eventualmente, no entanto, um processo em uma CPU não será suficiente para lidar com a crescente carga de trabalho de sua aplicação.</p><p>Não importa se o seu servidor é ou não muito poderoso. Uma <em>thread </em>única pode suportar apenas uma carga limitada.</p><p>O fato de que o Node.js funciona em <em>thread </em>única não significa que não podemos tirar proveito de múltiplos processos e, é claro, de múltiplas máquinas também.</p><p>O uso de múltiplos processos é a melhor maneira de dimensionar uma aplicação do Node. O Node.js é projetado para construir aplicações distribuídas com muitos nós. É por isso que ele é chamado Node (nó, em português). A escalabilidade é parte da plataforma e não é algo em que se comece a pensar mais tarde no ciclo de vida de uma aplicação.</p><blockquote>Este artigo é um resumo de parte do <a href="https://www.pluralsight.com/courses/nodejs-advanced" rel="noopener">curso do autor na Pluralsight sobre o Node.js</a>. Nele, o autor aborda conteúdo similar em formato de vídeo (em inglês).</blockquote><p>Observe que você precisará de um bom entendimento de <em><em>event</em>o<em>s</em></em> e <em><em>streams</em></em> do Node.js antes de ler este artigo. Se você ainda não leu, recomendo, primeiramente, que leia estes dois outros artigos (primeiro texto em inglês):</p><ul><li><strong><strong><a href="https://www.freecodecamp.org/news/understanding-node-js-event-driven-architecture-223292fcbc2d/">Understanding Node.js Event-Driven Architecture</a></strong></strong></li><li><strong><a href="https://www.freecodecamp.org/portuguese/news/streams-em-node-js-tudo-o-que-voce-precisa-saber/">Streams em Node.js: tudo o que você precisa saber</a></strong></li></ul><h3 id="o-m-dulo-de-processos-filhos"><strong>O módulo de processos filhos</strong></h3><p>Podemos facilmente iniciar um processo filho usando o módulo <code>child_process</code> do Node. Esses processos filhos podem se comunicar facilmente uns com os outros usando um sistema de mensagens.</p><p>O módulo <code>child_process</code> nos permite acessar as funcionalidades do sistema operacional executando qualquer comando de sistema dentro de um processo filho.</p><p>Podemos controlar esse fluxo de entrada do processo filho e acompanhar seu fluxo de saída. Também podemos controlar os argumentos a serem passados para o comando do sistema operacional subjacente e podemos fazer o que quisermos com a saída desse comando. Podemos, por exemplo, usar pipes na saída de um comando como a entrada para outro (assim como fazemos no Linux), pois todas as entradas e saídas desses comandos podem ser apresentadas usando <a href="https://www.freecodecamp.org/portuguese/news/streams-em-node-js-tudo-o-que-voce-precisa-saber/">streams do Node.js</a>.</p><p><em>Note que os exemplos que estarei usando neste artigo são todos baseados no Linux. No Windows, você precisará trocar os comandos que eu uso por suas alternativas do Windows.</em></p><p>Há quatro maneiras diferentes de se criar um processo filho no Node: <code>spawn()</code>, <code>fork()</code>, <code>exec()</code> e <code>execFile()</code>.</p><p>Vamos ver as diferenças entre essas quatro funções e quando usar cada uma delas.</p><h4 id="processos-filhos-usando-spawn-"><strong>Processos filhos usando s<strong>pawn</strong>()</strong></h4><p>A função <code>spawn()</code> executa um comando em um novo processo. Podemos passar a esse comando quaisquer argumentos. Por exemplo, aqui está o código para gerar um novo processo que executará o comando <code>pwd</code>.</p><pre><code>const { spawn } = require('child_process');

const child = spawn('pwd');</code></pre><p>Nós simplesmente desestruturamos a função <code>spawn()</code> do módulo <code>child_process</code> e a executamos com o comando do sistema operacional como o primeiro argumento.</p><p>O resultado da execução da função <code>spawn()</code> (o objeto <code>child</code> acima) é uma instância de <code>ChildProcess</code> que implementa a <a href="https://www.freecodecamp.org/news/understanding-node-js-event-driven-architecture-223292fcbc2d">EventEmitter API</a> (texto em inglês). Isso significa que podemos registrar diretamente os manipuladores de eventos sobre esse objeto filho. Por exemplo, podemos fazer qualquer coisa ao término do processo filho, registrando um manipulador (em inglês, <em>handler</em>) para o evento <code>exit</code>:</p><pre><code class="language-js">child.on('exit', function (code, signal) {
  console.log('processo filho encerrado com ' +
              `código ${code} e sinal ${signal}`);
});</code></pre><p>O manipulador acima nos dá as saídas de <code>code</code> para o processo filho e o <code>signal</code>, se houver algum, usado para encerrar o processo filho. Essa variável <code>signal</code>tem o valor <code>null</code> quando a saída do processo filho se dá normalmente.</p><p>Os outros eventos para os quais podemos registrar os manipuladores com as instâncias de <code>ChildProcess</code> são <code>disconnect</code>, <code>error</code>, <code>close</code> e <code>message</code>.</p><ul><li>O evento <code>disconnect</code> é emitido quando o processo pai chama manualmente a função <code>child.disconnect</code>.</li><li>O evento <code>error</code> é emitido se o processo não puder ser gerado ou terminado.</li><li>O evento <code>close</code> é emitido quando a <em>stream </em><code>stdio</code> de um processo filho se encerra.</li><li>O evento <code>message</code> é o mais importante. Ele é emitido quando o processo filho utiliza a função <code>process.send()</code> para enviar mensagens. É assim que os processos pai/filho podem se comunicar uns com os outros. Veremos um exemplo disso abaixo.</li></ul><p>Cada processo filho também recebe os três padrões da <em>stream </em><code>stdio</code>, aos quais podemos ter acesso usando <code>child.stdin</code>, <code>child.stdout</code> e <code>child.stderr</code>.</p><p>Quando essas <em>streams</em> forem fechadas, o processo filho que as estava usando emitirá o evento <code>close</code>. Esse evento <code>close</code> é diferente do evento <code>exit</code>, pois múltiplos processos filhos podem compartilhar a mesma <em>stream</em> <code>stdio</code> e, portanto, a saída de um processo filho não significa que as <em>streams </em>tenham sido fechadas.</p><p>Como todas as <em>streams </em>são emissoras de eventos, podemos acompanhar diferentes eventos sobre essas <em>streams </em><code>stdio</code>, que estão ligadas a cada processo filho. Ao contrário de um processo normal, em um processo filho, as <em>streams </em><code>stdout</code>/<code>stderr</code> são <em>streams </em>de leitura, enquanto <code>stdin</code> é uma <em>stream </em>de escrita. Esse é, basicamente, o inverso dos tipos anteriores, como encontrado em um processo principal. Os eventos que podemos usar para essas <em>streams </em>são os padrões. Mais importante ainda, nas <em>streams </em>de leitura, podemos acompanhar o evento <code>data</code>, que terá a saída do comando ou qualquer erro encontrado durante a execução do comando:</p><pre><code class="language-js">child.stdout.on('data', (data) =&gt; {
  console.log(`stdout filho:\n${data}`);
});

child.stderr.on('data', (data) =&gt; {
  console.error(`stderr filho:\n${data}`);
});</code></pre><p>Os dois manipuladores acima registrarão os dois casos nos processos principais, <code>stdout</code> e <code>stderr</code>. Quando executarmos a função <code>spawn</code>, a saída do comando <code>pwd</code> é impresso e o processo filho termina com o código <code>0</code>, o que significa que não ocorreu nenhum erro.</p><p>Podemos passar argumentos para o comando executado pela função <code>spawn</code> utilizando o segundo argumento da função <code>spawn</code>, que é um array de todos os argumentos a serem passados para o comando. Por exemplo, para executar o comando <code>find</code> no diretório atual com um argumento <code>-type f</code> (apenas para listar arquivos), podemos fazer:</p><pre><code class="language-js">const child = spawn('find', ['.', '-type', 'f']);</code></pre><p>Se ocorrer um erro durante a execução do comando – por exemplo, se dermos um destino inválido acima – o manipulador de evento <code>data</code> de <code>child.stderr</code> será acionado e o manipulador de evento <code>exit</code> relatará um código de saída <code>1</code>, o que significa que ocorreu um erro. Os valores de erro realmente dependem do sistema operacional do host e do tipo de erro.</p><p>O processo filho <code>stdin</code> é uma <em>stream </em>de escrita. Podemos usá-lo para enviar um comando com alguma entrada. Assim como qualquer <em>stream </em>de escrita, a maneira mais fácil de consumi-la é usando a função <code>pipe</code>. Simplesmente usamos <code>pipe</code> com uma stream de leitura. Uma vez que o processo principal <code>stdin</code> é uma <em>stream </em>de leitura, podemos usar <code>pipe</code> com um processo filho stream <code>stdin</code>. Por exemplo:</p><pre><code class="language-js">const { spawn } = require('child_process');

const child = spawn('wc');

process.stdin.pipe(child.stdin)

child.stdout.on('data', (data) =&gt; {
  console.log(`stdout filho:\n${data}`);
});</code></pre><p>No exemplo acima, o processo filho invoca o comando <code>wc</code>, que conta linhas, palavras e caracteres no Linux. Em seguida, usamos <code>pipe</code> com o processo principal <code>stdin</code> (que é uma <em>stream </em>de leitura) no processo filho <code>stdin</code> (que é uma <em>stream </em>de escrita). O resultado dessa combinação é que obtemos um modo de entrada padrão onde podemos digitar algo e, quando pressionamos <code>Ctrl+D</code>, o que digitamos será usado como entrada do comando <code>wc</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_s9dQY9GdgkkIf9zC1BL6Bg.gif" class="kg-image" alt="1_s9dQY9GdgkkIf9zC1BL6Bg" width="800" height="450" loading="lazy"><figcaption>Gif capturado do curso do autor na Pluralsight sobre Node.js avançado</figcaption></figure><p>Também podemos usar <code>pipe</code> na entrada/saída padrão de múltiplos processos, uns sobre os outros, assim como podemos fazer com os comandos Linux. Por exemplo, podemos usar <code>pipe</code> com <code>stdout</code> do comando <code>find</code> para o stdin do comando <code>wc</code> para contar todos os arquivos do diretório atual:</p><pre><code class="language-js">const { spawn } = require('child_process');

const find = spawn('find', ['.', '-type', 'f']);
const wc = spawn('wc', ['-l']);

find.stdout.pipe(wc.stdin);

wc.stdout.on('data', (data) =&gt; {
  console.log(`Número de arquivos ${data}`);
});</code></pre><p>Eu adicionei o argumento <code>-l</code> no comando <code>wc</code> para que conte apenas as linhas. Ao ser executado, o código acima emitirá uma contagem de todos os arquivos em todos os diretórios sob o diretório atual.</p><h4 id="sintaxe-do-shell-e-a-fun-o-exec"><strong>Sintaxe do s<strong>hell</strong> e a função<strong> exec</strong></strong></h4><p>Por padrão, a função <code>spawn</code> não cria um <em><em>shell</em></em> para executar o comando que passamos para ele. Isso o torna um pouco mais eficiente do que a função <code>exec</code>, que cria um <em>shell</em>. A função <code>exec</code> tem uma outra grande diferença. Ela cria um <em><em>buffer</em></em> da saída gerada pelo comando e passa todo o valor de saída para uma função de retorno (em vez de usar <em>streams</em>, que é o que <code>spawn</code> faz).</p><p>Aqui está o exemplo anterior <code>find | wc </code> implementado com a função <code>exec</code>.</p><pre><code class="language-js">const { exec } = require('child_process');

exec('find . -type f | wc -l', (err, stdout, stderr) =&gt; {
  if (err) {
    console.error(`erro exec: ${err}`);
    return;
  }

  console.log(`Número de arquivos ${stdout}`);
});</code></pre><p>Como a função <code>exec</code> usa um <em>shell </em>para executar o comando, podemos usar a sintaxe do <em>shell<em> </em></em>diretamente aqui, fazendo uso do recurso <code>pipe</code> do <em>shell</em>.</p><p>Note que o uso da sintaxe do <em>shell </em>representa um <a href="https://blog.liftsecurity.io/2014/08/19/Avoid-Command-Injection-Node.js/" rel="noopener">risco de segurança</a> (texto em inglês) se você estiver executando qualquer tipo de entrada dinâmica fornecida externamente. Um usuário pode simplesmente fazer um ataque de injeção de comando usando caracteres de sintaxe de <em>shell</em> como ; e $ (por exemplo, <code>command + ’; rm -rf ~’</code> ).</p><p>A função <code>exec</code> cria <em>buffers </em>de saída e passa para a função de <em>callback </em>(o segundo argumento de <code>exec</code>) como um argumento <code>stdout</code>. Esse argumento <code>stdout</code> é a saída do comando que queremos imprimir.</p><p>A função <code>exec</code> é uma boa escolha se você precisar usar a sintaxe do <em>shell </em>e se o tamanho dos dados esperados do comando for pequeno (lembre-se, <code>exec</code> criará um buffer de todos dados inteiros em memória antes de retorná-los).</p><p>A função <code>spawn</code> é uma escolha muito melhor quando o tamanho dos dados esperados do comando é grande, porque esses dados serão transmitidos com os objetos padrão de entrada/saída.</p><p>Podemos fazer com que o processo filho gerado herde os objetos padrão de E/S de seus pais, se quisermos. Porém, mais importante ainda, podemos fazer com que a função <code>spawn</code> também use a sintaxe do <em>shell</em>. Aqui está o mesmo comando <code>find | wc</code> implementado com a função <code>spawn</code>:</p><pre><code class="language-js">const child = spawn('find . -type f | wc -l', {
  stdio: 'inherit',
  shell: true
});</code></pre><p>Por causa da opção <code>stdio: 'inherit'</code> acima, quando executamos o código, o processo filho herda o processo principal <code>stdin</code>, <code>stdout</code> e <code>stderr</code>. Isso faz com que os manipuladores de eventos de dados do processo filho sejam acionados na <em>stream </em>principal &nbsp;<code>process.stdout</code>, fazendo com que o script dê o resultado imediatamente.</p><p>Por causa da opção <code>shell: true</code> &nbsp;acima, pudemos usar a sintaxe do <em>shell </em>no comando passado, exatamente como fizemos com <code>exec</code>. Com esse código, entretanto, ainda temos a vantagem do <em>streaming</em> de dados que a função <code>spawn</code> nos dá. <em>Esse é, realmente, o melhor dos dois mundos.</em></p><p>Há algumas outras boas opções que podemos usar no último argumento para a função <code>child_process</code> além de <code>shell</code> e <code>stdio</code>. Podemos, por exemplo, usar a opção <code>cwd</code> para mudar o diretório de trabalho do script. Por exemplo, aqui está o mesmo exemplo de contagem de todos os arquivos feito com uma função <code>spawn</code> usando um <em>shell </em>e com um diretório de trabalho definido para minha pasta Downloads. A opção <code>cwd</code> fará com que o <em>script</em> conte todos os arquivos que eu tenho em &nbsp;<code>~/Downloads</code>:</p><pre><code class="language-js">const child = spawn('find . -type f | wc -l', {
  stdio: 'inherit',
  shell: true,
  cwd: '/Users/samer/Downloads'
});</code></pre><p>Outra opção que podemos utilizar é a opção <code>env</code> para especificar as variáveis de ambiente que serão visíveis para o novo processo filho. O padrão para essa opção é <code>process.env</code>, que dá acesso a qualquer comando ao ambiente de processo atual. Se quisermos anular esse comportamento, podemos simplesmente passar um objeto vazio como a opção <code>env</code> ou novos valores a serem considerados como as únicas variáveis de ambiente:</p><pre><code class="language-js">const child = spawn('echo $ANSWER', {
  stdio: 'inherit',
  shell: true,
  env: { ANSWER: 42 },
});</code></pre><p>O comando <code>echo</code> acima não tem acesso às variáveis de ambiente do processo pai. Ele não pode, por exemplo, acessar <code>$HOME</code>, mas pode acessar <code>$ANSWER</code>, pois esse foi passado como uma variável de ambiente personalizada através da opção <code>env</code>.</p><p>Uma última opção importante do processo filho a ser explicada aqui é a opção <code>detached</code>, que faz com que o processo filho seja executado independentemente de seus processos pais.</p><p>Assumindo que temos um arquivo <code>timer.js</code>, que mantém o ciclo de eventos ocupado:</p><pre><code class="language-js">setTimeout(() =&gt; {  
  // mantém o ciclo de eventos ocupado
}, 20000);</code></pre><p>Podemos executá-lo em segundo plano usando a opção <code>detached</code>:</p><pre><code class="language-js">const { spawn } = require('child_process');

const child = spawn('node', ['timer.js'], {
  detached: true,
  stdio: 'ignore'
});

child.unref();</code></pre><p>O comportamento exato dos processos filhos em modo <code>detached</code> (em português, <em>separado</em>) depende do sistema operacional. No Windows, o processo filho em modo <code>detached</code>, terá sua própria janela de console, enquanto no Linux o processo filho em modo <code>detached</code> se tornará o líder de um novo grupo e sessão de processo.</p><p>Se a função <code>unref</code> é chamada no processo em modo <code>detached</code>, os processos pais podem sair independentemente do filho. Isso pode ser útil se o filho estiver executando um processo de longa duração, mas, para mantê-lo em segundo plano, as configurações do processo filho <code>stdio</code> também têm que ser independentes dos pais.</p><p>O exemplo acima executará um script (<code>timer.js</code>) do Node em segundo plano, separando-se e também ignorando seu pai, descritor de arquivos, <code>stdio</code> para que os pais possam terminar enquanto o filho continua rodando em segundo plano.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_WhvMs8zv-WS6v7nDXmDUzw.gif" class="kg-image" alt="1_WhvMs8zv-WS6v7nDXmDUzw" width="800" height="450" loading="lazy"><figcaption>Gif capturado do curso do autor na Pluralsight sobre Node.js avançado</figcaption></figure><h4 id="a-fun-o-execfile"><strong>A função<strong> execFile</strong></strong></h4><p>Se você precisar executar um arquivo sem usar um <em>shell</em>, a função <code>execFile</code> é o que você precisa. Ela se comporta exatamente como a função <code>exec</code>, mas não usa um <em>shell</em>, o que a torna um pouco mais eficiente. No Windows, alguns arquivos não podem ser executados por conta própria, como arquivos <code>.bat</code> ou <code>.cmd</code>. Esses arquivos não podem ser executados com <code>execFile</code>. <code>exec</code> ou <code>spawn</code>, com o <em>shell </em>definido como verdadeiro, é o necessário para executá-los.</p><h4 id="a-fun-o-sync"><strong>A função<strong> *Sync</strong></strong></h4><p>As funções <code>spawn</code>, <code>exec</code> e <code>execFile</code> do módulo <code>child_process</code> também têm versões de bloqueio síncronas, que aguardarão até que o processo filho termine.</p><pre><code>const { 
  spawnSync, 
  execSync, 
  execFileSync,
} = require('child_process');</code></pre><p>Essas versões síncronas são potencialmente úteis ao tentar simplificar as tarefas de script ou qualquer tarefa de processamento de inicialização. Caso contrário, elas devem ser evitadas.</p><h4 id="a-fun-o-fork-"><strong>A função<strong> fork()</strong></strong></h4><p>A função <code>fork</code> é uma variação da função <code>spawn</code> para geração de processos do Node. A maior diferença entre <code>spawn</code> e <code>fork</code> é que um canal de comunicação é estabelecido para o processo filho quando se usa <code>fork</code>, para que possamos usar a função <code>send</code> sobre o processo do qual o <em>fork </em>foi realizado juntamente com o objeto de processo <code>process</code> global para trocar mensagens entre os processos pai e aquele do qual se fez o <em>fork</em>. Fazemos isso através da interface do módulo <code>EventEmitter</code>. Aqui está um exemplo:</p><p>Arquivo pai, <code>parent.js</code>:</p><pre><code class="language-js">const { fork } = require('child_process');

const forked = fork('child.js');

forked.on('message', (msg) =&gt; {
  console.log('Mensagem do filho', msg);
});

forked.send({ hello: 'world' });</code></pre><p>Arquivo filho, <code>child.js</code>:</p><pre><code class="language-js">process.on('message', (msg) =&gt; {
  console.log('Mensagem do pai:', msg);
});

let counter = 0;

setInterval(() =&gt; {
  process.send({ counter: counter++ });
}, 1000);</code></pre><p>No arquivo pai acima, dividimos <code>child.js</code> (que executará o arquivo com o comando <code>node</code>). Depois, acompanhamos o evento <code>message</code>. O evento <code>message</code> será emitido sempre que o filho usar <code>process.send</code>, o que estamos fazendo a cada segundo.</p><p>Para passar mensagens dos pais para o filho, podemos executar a função <code>send</code> sobre o próprio objeto do qual fizemos o <em>fork</em> e, então, no <em>script </em>filho, podemos acompanhar o evento <code>message</code> no objeto global <code>process</code>.</p><p>Ao executar o arquivo <code>parent.js</code> acima, ele enviará primeiro o objeto <code>{ hello: 'world' }</code> para ser impresso pelo processo filho, aquele do qual fizemos o <em>fork, </em>e então o processo filho enviará um valor de contador incremental a cada segundo para ser impresso pelo processo pai.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_GOIOTAZTcn40qZ3JwgsrNA.gif" class="kg-image" alt="1_GOIOTAZTcn40qZ3JwgsrNA" width="800" height="450" loading="lazy"><figcaption>Gif capturado do curso do autor na Pluralsight sobre Node.js avançado</figcaption></figure><p>Vamos fazer um exemplo mais prático sobre a função <code>fork</code>.</p><p>Digamos que temos um servidor de http que lida com dois <em>endpoints</em>. Um desses endpoints (<code>/compute</code>, abaixo) é computacionalmente caro e levará alguns segundos para ser concluído. Podemos usar um laço <em>for</em> extenso para simular isso:</p><pre><code class="language-js">const http = require('http');

const longComputation = () =&gt; {
  let sum = 0;
  for (let i = 0; i &lt; 1e9; i++) {
    sum += i;
  };
  return sum;
};

const server = http.createServer();

server.on('request', (req, res) =&gt; {
  if (req.url === '/compute') {
    const sum = longComputation();
    return res.end(`Sum is ${sum}`);
  } else {
    res.end('Ok')
  }
});

server.listen(3000);</code></pre><p>Esse programa tem um grande problema. Quando o <em>endpoint</em> <code>/compute</code> é solicitado, o servidor não será capaz de lidar com quaisquer outras solicitações porque o laço <em>for </em>do evento estará ocupado com o tempo de operação.</p><p>Há algumas maneiras de se resolver esse problema, dependendo da natureza da operação longa, mas uma solução que funciona para todas as operações é simplesmente mover a operação computacional para outro processo usando <code>fork</code>.</p><p>Primeiro, movemos toda a função <code>longComputation</code> em seu próprio arquivo e invocamos essa função quando indicado através de uma mensagem do processo principal:</p><p>Em um novo arquivo, <code>compute.js</code>:</p><pre><code class="language-js">const longComputation = () =&gt; {
  let sum = 0;
  for (let i = 0; i &lt; 1e9; i++) {
    sum += i;
  };
  return sum;
};

process.on('message', (msg) =&gt; {
  const sum = longComputation();
  process.send(sum);
});</code></pre><p>Agora, em vez de fazer a longa operação no circuito principal de eventos do processo, podemos aplicar <code>fork</code> no arquivo <code>compute.js</code> e usar a interface de mensagens para comunicar mensagens entre o servidor e o processo dividido.</p><pre><code class="language-js">const http = require('http');
const { fork } = require('child_process');

const server = http.createServer();

server.on('request', (req, res) =&gt; {
  if (req.url === '/compute') {
    const compute = fork('compute.js');
    compute.send('start');
    compute.on('message', sum =&gt; {
      res.end(`Sum is ${sum}`);
    });
  } else {
    res.end('Ok')
  }
});

server.listen(3000);</code></pre><p>Quando um pedido para <code>/compute</code> acontece com o código acima, simplesmente enviamos uma mensagem para o processo do qual fizemos o <em>fork</em> para iniciar a execução da longa operação. O ciclo de eventos do processo principal não será bloqueado.</p><p>Uma vez que o processo, com essa longa operação, é finalizado, ele pode enviar seu resultado de volta para o processo pai usando <code>process.send</code>.</p><p>No processo pai, esperamos o evento <code>message</code> no próprio processo filho. Quando tivermos esse evento, teremos um valor <code>sum</code> pronto para enviarmos ao usuário solicitante pelo http.</p><p>O código acima é, naturalmente, limitado pelo número de processos que podemos dividir, mas, quando o executamos e solicitamos o <em>endpoint </em>da longa tarefa computacional no http, o servidor principal não é bloqueado de modo algum e ele pode aceitar outras solicitações.</p><p>O módulo <code>cluster</code> do Node, que é o tema do meu próximo artigo, é baseado nesta ideia de processo filho em <em>fork</em> e no balanceamento de carga das solicitações entre os diversos <em>forks</em> que podemos criar em qualquer sistema.</p><p>Isso é tudo o que eu tinha para apresentar sobre este tópico. Obrigado pela leitura e até a próxima!</p><p>Está aprendendo React ou Node? Confira os livros do autor (em inglês):</p><ul><li><a href="http://amzn.to/2peYJZj" rel="noopener">Learn React.js by Building Games</a></li><li><a href="http://amzn.to/2FYfYru" rel="noopener">Node.js Beyond the Basics</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como usar o Webpack com o React: um tutorial detalhado ]]>
                </title>
                <description>
                    <![CDATA[ Atualizado para o Babel 7 Neste tutorial, veremos o básico sobre o Webpack com o React para você começar, incluindo React Router [https://github.com/ReactTraining/react-router], Hot Module Replacement [https://github.com/gaearon/react-hot-loader] (HMR, ou substituição rápida de módulos), Code Splitting (ou divisão de código, em português) por rota [https://github.com/theKashey/react-imported-component] e por fornecedor [https://webpack.js.org/plugins/commons-chunk-plugin/], configuração de ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/como-usar-o-webpack-com-o-react-um-tutorial-detalhado/</link>
                <guid isPermaLink="false">632b4f105c046e06ec87896d</guid>
                
                    <category>
                        <![CDATA[ Webpack ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Fernando Miguel ]]>
                </dc:creator>
                <pubDate>Mon, 10 Oct 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/1_6PbJ291MHulQWCmPW9fzDg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/learn-webpack-for-react-a36d4cac5060/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to use Webpack with React: an in-depth tutorial</a>
      </p><p><em>Atualizado para<em> </em>o <em>Babel 7</em></em></p><p>Neste tutorial, veremos o básico sobre o Webpack com o React para você começar, incluindo <a href="https://github.com/ReactTraining/react-router" rel="noopener">React Router</a>, <a href="https://github.com/gaearon/react-hot-loader" rel="noopener">Hot Module Replacement</a> (HMR, ou substituição rápida de módulos), Code Splitting (ou divisão de código, em português) por <a href="https://github.com/theKashey/react-imported-component" rel="noopener">rota</a> e por <a href="https://webpack.js.org/plugins/commons-chunk-plugin/" rel="noopener">fornecedor</a>, configuração de produção e mais.</p><p>Antes de começarmos, aqui está uma lista completa dos recursos que vamos configurar juntos neste tutorial:</p><ul><li>React 16</li><li>React Router 5</li><li>Semantic UI como o Framework CSS</li><li>Hot Module Replacement (HMR)</li><li>Autoprefixador do CSS</li><li>Módulos do CSS</li><li>@babel/plugin-proposal-class-properties</li><li>@babel/plugin-syntax-dynamic-import</li><li>Webpack 4</li><li>Code Splitting por rota e por fornecedor</li><li>Analisador de pacotes do Webpack</li></ul><blockquote><strong><em>Nota do tradutor</em></strong>: no momento da tradução, algumas das bibliotecas principais deste tutorial estão em versões bem mais atualizadas (React está na versão 18, React Router na versão 6 e o Webpack na versão 5). Sugerimos, na hora da instalação, utilizar as versões acima. Para isso, use a notação com @. Exemplo: em vez de instalar o React usando <code>yarn add react</code>, use &nbsp;<code>yarn add react@16.2.0</code>. Você evitará, desse modo, problemas de incompatibilidade com as versões mais recentes. A lista completa das versões a serem instaladas, você encontra nas dependências listadas no <code>package.json</code> abaixo.</blockquote><h4 id="pr-requisitos"><strong>Pré-requisitos</strong></h4><p>Ter o seguinte pré-instalado:</p><ul><li><a href="https://yarnpkg.com/" rel="noopener">Yarn</a> — gestor de pacotes, similar ao <a href="https://www.npmjs.com/" rel="noopener">npm</a></li><li><a href="https://nodejs.org/en/" rel="noopener">Node</a></li></ul><p>Você deve ter ao menos algum conhecimento básico de React e React Router.</p><p><em><strong>Observação</strong><em><strong><strong>:</strong></strong> </em>você pode usar o npm em vez do Yarn, se desejar, embora os comandos variem um pouco<em>.</em></em></p><h4 id="depend-ncias-iniciais">Dependências<strong> iniciais</strong></h4><p>Vamos iniciar criando nosso diretório e o arquivo <code>package.json</code>.</p><p>Em seu terminal, digite o seguinte:</p><pre><code>mkdir webpack-for-react &amp;&amp; cd $_
yarn init -y</code></pre><p>O primeiro comando criará nosso diretório e entrará nele. Então, iniciamos o <code>package.json</code> aceitando as opções padrão. <br>Se você o inspecionar, verá a configuração básica:</p><pre><code class="language-js">{
  "name": "webpack-for-react",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT"
}</code></pre><p>Agora, instalaremos nossas dependências iniciais de produção e as dependências de desenvolvimento. <br>No seu terminal, digite o seguinte:</p><pre><code>yarn add react react-dom prop-types react-router-dom semantic-ui-react
yarn add @babel/core babel-loader @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-syntax-dynamic-import css-loader style-loader html-webpack-plugin webpack webpack-dev-server webpack-cli -D</code></pre><blockquote><strong><em>Nota do tradutor:</em></strong> Conforme mencionamos anteriormente, é no comando acima que você instalará as dependências pela versão específica.</blockquote><p>As dependências de desenvolvimento serão usadas somente, conforme o que se espera, durante a fase de desenvolvimento, enquanto as dependências de produção serão o que nossa aplicação precisa em produção.</p><pre><code class="language-js">{
  "name": "webpack-for-react",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "prop-types": "^15.6.2",
    "react-router-dom": "^4.2.2",
    "semantic-ui-react": "^0.77.1"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.0.0",
    "@babel/plugin-syntax-dynamic-import": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-react": "^7.0.0", 
    "babel-loader": "^8.0.1",
    "css-loader": "^0.28.10",
    "html-webpack-plugin": "^3.0.4",
    "style-loader": "^0.19.1",
    "webpack": "^4.0.0",
    "webpack-cli": "^2.0.14",
    "webpack-dev-server": "^3.0.0"
  }
}</code></pre><p><em><strong>Observação 1</strong><em><strong><strong>:</strong></strong> </em>as alterações em arquivos criados anteriormente estarão em negrito<em>.</em></em><br><em><strong>Observação 2</strong><em><strong><strong>:</strong></strong> </em>as versões de dependências podem ser diferentes das suas desde o momento em que esse artigo foi escrito<em>.</em></em></p><ul><li><a href="https://reactjs.org/" rel="noopener">react</a> — Tenho certeza de que você sabe o que é React</li><li><a href="https://reactjs.org/docs/react-dom.html" rel="noopener">react-dom</a> — Fornece métodos específicos do DOM para o navegador</li><li><a href="https://github.com/facebook/prop-types" rel="noopener">prop-types</a> — Verificação do tipo em tempo de execução para props do React</li><li><a href="https://github.com/ReactTraining/react-router" rel="noopener">react-router-dom</a> — Fornece recursos de roteamento para React no navegador</li><li><a href="https://react.semantic-ui.com/introduction" rel="noopener">semantic-ui-react</a> — Framework de CSS</li><li><a href="https://babeljs.io/docs/en/babel-core/" rel="noopener">@babel/core</a> — Principais dependências para Babel</li><li><a href="https://babeljs.io/" rel="noopener">Babel</a> é um transpilador que compila JavaScript ES6 para JavaScript ES5, permitindo escrever JavaScript "do futuro" para que os navegadores atuais o entendam. <a href="https://www.quora.com/What-exactly-is-BabelJs-Why-does-it-understand-JSX-React-components" rel="noopener">Descrição detalhada no Quora</a> (em inglês).</li><li><a href="https://webpack.js.org/loaders/babel-loader/" rel="noopener">babel-loader</a> — Este pacote permite a transpilação de arquivos JavaScript usando Babel e o Webpack</li><li><a href="https://babeljs.io/docs/en/next/babel-preset-env.html" rel="noopener">@babel/preset-env</a> — Com ele, você não precisa especificar se você vai escrever ES2015, ES2016 ou ES2017. O Babel detectará e fará a transpilação automaticamente de acordo</li><li><a href="https://babeljs.io/docs/en/babel-preset-react/" rel="noopener">@babel/preset-react</a> — Diz ao Babel que usaremos o React</li><li><a href="https://babeljs.io/docs/en/babel-plugin-proposal-class-properties" rel="noopener">@babel/plugin-proposal-class-properties </a>— Usa propriedades de classe. Nós não usamos propriedades de classe neste projeto, mas é mais do que provável que você as use no seu</li><li><a href="https://babeljs.io/docs/en/babel-plugin-syntax-dynamic-import" rel="noopener">@babel/plugin-syntax-dynamic-import</a> — Possibilita utilizar importações dinâmicas</li><li><a href="https://webpack.js.org/loaders/css-loader/" rel="noopener">css-loader</a> — Interpreta <code>@import </code>e <code>url()</code> como <code>import/require()</code> e fará sua resolução</li><li><a href="https://webpack.js.org/plugins/html-webpack-plugin/" rel="noopener">html-webpack-plugin</a> — Pode gerar um arquivo HTML para sua aplicação, ou você pode fornecer um modelo</li><li><a href="https://webpack.js.org/loaders/style-loader/" rel="noopener">style-loader</a> — Adiciona CSS ao DOM, injetando uma tag <code>&lt;style&gt;</code></li><li><a href="https://webpack.js.org/" rel="noopener">webpack</a> — bundler de módulos</li><li><a href="https://github.com/webpack/webpack-cli" rel="noopener">webpack-cli</a> — Interface de Linha de Comando, necessária para o Webpack 4.0.1 e versões mais recentes</li><li><a href="https://webpack.js.org/configuration/dev-server/" rel="noopener">webpack-dev-server</a> — Fornece um servidor de desenvolvimento para sua aplicação</li></ul><h3 id="configurando-o-babel"><strong>Configurando o Babel</strong></h3><p>No diretório raiz (<code>webpack-for-react</code>), criaremos o arquivo de configuração do Babel.</p><pre><code>touch .babelrc</code></pre><p>Neste ponto, você pode abrir seu editor favorito (a propósito, o meu é o VS Code) e depois apontar o editor para a raiz deste projeto, abrindo o arquivo <code>.babelrc</code> e copiando o seguinte:</p><pre><code class="language-js">{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-class-properties"
  ]
}</code></pre><p>Isto diz ao Babel para utilizar as pré-definições (plug-ins) que instalamos anteriormente. Mais tarde, quando chamarmos o <code>babel-loader</code> do Webpack, é aqui que ele vai procurar saber o que fazer.</p><h3 id="configurando-o-webpack"><strong>Configurando o Webpack</strong></h3><p>Agora, a diversão começa! Vamos criar o arquivo de configuração do Webpack.</p><p>Em seu terminal, digite o seguinte:</p><pre><code>touch webpack.config.js</code></pre><p>Abra o arquivo <code>webpack.config.js</code> e copie o seguinte:</p><pre><code class="language-js">const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const port = process.env.PORT || 3000;

module.exports = {
  // A configuração do Webpack vai aqui
};</code></pre><p>Este é o <em><em>shell</em></em> básico para o Webpack. Nós precisamos do <code>webpack</code> e do <code>html-webpack-plugin</code>. Forneça uma porta padrão se a variável de ambiente PORT não existir e exporte o módulo.</p><p>Será acrescentado o seguinte ao arquivo <code>webpack.config.js</code> (um após o outro).</p><pre><code class="language-js">...
module.exports = {
  mode: 'development',
};</code></pre><p><code>mode</code> diz ao Webpack que esta configuração será para <code>development</code> ou <code>production</code>. "O modo de desenvolvimento [é] otimizado para velocidade e experiência do desenvolvedor... Os padrões de produção darão a você um conjunto de padrões úteis para a implantação de sua aplicação" (Fonte: <a href="https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a" rel="noopener">Webpack 4: mode and optimization</a> - texto em inglês).</p><pre><code class="language-js">...
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.[hash].js'
  },
};</code></pre><p>Para ter um exemplo do Webpack em funcionamento, precisamos do seguinte:</p><ul><li><code>entry</code> — Especifica o ponto de entrada de sua aplicação – é aqui que sua aplicação do React vive e onde o processo de empacotamento começará (<a href="https://webpack.js.org/concepts/entry-points/" rel="noopener">documentação</a>)</li></ul><p><em>O <em>Webpack 4 </em>introduziu alguns padrões. Então, se você não incluir <em><code>entry</code> </em>em suas configurações, ele assumirá que seu ponto de entrada está localizado sob o diretório <em><code>./src</code> ,</em> tornando <em><code>entry</code> </em>opcional, ao contrário do<em> </em>que ocorria no <em>Webpack 3. </em>Para este <em>tutorial</em>, eu decidi deixar<em> <code>entry</code></em>,<em> </em>pois torna óbvio onde nosso ponto de entrada estará. Você, no entanto, é mais do que bem-vindo para removê-lo se assim o decidir<em>.</em></em></p><ul><li><code>output</code> — Diz ao Webpack como escrever os arquivos compilados em disco (<a href="https://webpack.js.org/concepts/output/" rel="noopener">documentação</a>)</li><li><code>filename</code> — Este será o nome do arquivo do pacote da aplicação. A porção <code>[hash]</code> do nome do arquivo será substituída por um hash gerado pelo Webpack toda vez que sua aplicação mudar e for recompilada (ajuda com caching).</li></ul><pre><code class="language-js">...
module.exports = {
  ...
  devtool: 'inline-source-map',
};</code></pre><p><code>devtool</code> criará <a href="https://developer.mozilla.org/en-US/docs/Tools/Debugger/How_to/Use_a_source_map" rel="noopener"><em>source maps</em></a> (texto em inglês) para ajudar você na depuração de sua aplicação. Há vários tipos de <em>source maps.</em> O mapa <code>inline-source-map</code>, em particular, é para ser usado somente no desenvolvimento (consulte a <a href="https://webpack.js.org/configuration/devtool/" rel="noopener">documentação</a> para ver mais opções).</p><pre><code class="language-js">...
module.exports = {
  ...
  module: {
    rules: [

      // Primeira regra
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },

      // Segunda regra
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              localsConvention: 'camelCase',
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
};</code></pre><ul><li><a href="https://webpack.js.org/configuration/module/" rel="noopener">module</a> — Que tipos de módulos sua aplicação incluirá. Em nosso caso, daremos suporte aos Módulos ESNext (Babel) e CSS</li><li><a href="https://webpack.js.org/configuration/module/#module-rules" rel="noopener">rules</a> — Como lidamos com cada tipo diferente de módulo</li></ul><h4 id="primeira-regra"><strong>Primeira regra</strong></h4><p>Testamos arquivos com uma extensão <code>.js</code>, excluindo o diretório <code>node_modules</code>, e usando Babel, por meio do <code>babel-loader</code>, para executar uma transpilação para JavaScript puro (basicamente, procurando por nossos arquivos do React).</p><p>Se lembra de nossa configuração em <code>.babelrc</code>? É aqui que o Babel procura por esse arquivo.</p><h4 id="segunda-regra"><strong>Segunda regra</strong></h4><p>Buscamos os arquivos de CSS pela extensão <code>.css</code>. Aqui, usamos dois <em>loaders </em>(em português, carregadores), <code>style-loader</code> e <code>css-loader</code>, para tratar nossos arquivos em CSS. Em seguida, instruímos <code>css-loader</code> para usar Módulos do CSS, formatar em <em>camel case</em> e criar os <em>source maps</em>.</p><p><strong><strong>Módul</strong>o<strong>s</strong> CSS<strong> </strong>e<strong> </strong>a formatação em <em>c<strong>amel </strong>c<strong>ase</strong></em></strong></p><p>Isto nos dá a capacidade de usar a sintaxe <code>import Styles from './styles.css'</code> (ou de usar desestruturação, assim: <code>import { style1, style2 } from ‘./styles.css’</code>).</p><p>Então, podemos usar isso deste modo em uma aplicação do React:</p><pre><code class="language-js">...
&lt;div className={Style.style1}&gt;Olá Mundo&lt;/div&gt;
// ou com a sintaxe de desestruturação
&lt;div className={style1}&gt;Olá Mundo&lt;/div&gt;
...</code></pre><p>O <em>camel case</em> nos dá a capacidade de escrever nossas regras de CSS desta forma:</p><pre><code>.home-button {...}</code></pre><p>Podemos utilizá-lo em nossos arquivos do React, assim:</p><pre><code>...
import { homeButton } from './styles.css'
...
...
module.exports = {
  ...
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      favicon: 'public/favicon.ico'
    })
  ],
};</code></pre><p>Esta seção é onde configuramos (como o nome indica) os plug-ins.</p><p><code>html-webpack-plugin</code> aceita um objeto com diferentes opções. Em nosso caso, especificamos o modelo HTML que estaremos usando e o favicon. (Consulte a <a href="https://github.com/jantimon/html-webpack-plugin#configuration" rel="noopener">documentação</a> para ver mais opções).</p><p>Mais tarde, adicionaremos outros plug-ins para o analisador de pacotes e para o HMR (substituição rápida de módulos).</p><pre><code>...
module.exports = {
  ...
  devServer: {
    host: 'localhost',
    port: port,
    historyApiFallback: true,
    open: true
  }
};</code></pre><p>Por fim, vamos configurar o servidor de desenvolvimento. Especificamos <code>localhost</code> como o host e atribuímos a variável <code>port</code> como a porta (se você se lembra, atribuímos a porta 3000 a esta variável). Definimos <code>historyApiFallback</code> como true e <code>open</code> como true. Isto abrirá o navegador automaticamente e iniciará sua aplicação em <a href="http://localhost:3000." rel="noopener">http://localhost:3000</a> (veja a <a href="https://webpack.js.org/configuration/dev-server/" rel="noopener">documentação</a>).</p><p>Agora, abaixo está a configuração completa do Webpack (<code>webpack.config.js</code>):</p><pre><code>const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const port = process.env.PORT || 3000;

module.exports = {
  mode: 'development',  
  entry: './src/index.js',
  output: {
    filename: 'bundle.[hash].js'
  },
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              localsConvention: 'camelCase',
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      favicon: 'public/favicon.ico'
    })
  ],
  devServer: {
    host: 'localhost',
    port: port,
    historyApiFallback: true,
    open: true
  }
};</code></pre><h3 id="criando-a-aplica-o-em-react"><strong>Criando a aplicação em React</strong></h3><p>Estaremos criando uma simples para a aplicação <code>Hello World</code> com três rotas: uma <em><em>home</em></em>, uma <em><em>p</em>ágina não encontrada<em> </em></em>e uma <em>página dinâmica,</em> que carregaremos de modo assíncrono quando implementarmos mais tarde o <em>code splitting</em> (divisão de código, em português).</p><p><strong><em>Observação</em><strong><em><em>:</em></em></strong></strong><em><em> </em>assumindo que você tenha um entendimento básico de <em>React </em>e<em> </em>de <em>React Router, </em>não entrarei em detalhes aqui. Destacarei apenas o que é relevante para este tutorial<em>.</em></em></p><p>Atualmente, temos a seguinte estrutura de projeto:</p><pre><code>|-- node_modules
|-- .babelrc
|-- package.json
|-- webpack.config.js
|-- yarn.lock</code></pre><p>Em seu terminal, digite o seguinte:</p><pre><code>mkdir public &amp;&amp; cd $_
touch index.html</code></pre><p>Criamos o diretório <code>public</code>, entramos no diretório e criamos o arquivo <code>index.html</code>. Também temos aqui o <code>favicon</code>. Você pode pegá-lo <a href="https://github.com/esausilva/react-starter-boilerplate-hmr/blob/master/public/favicon.ico" rel="noopener">aqui</a> e copiá-lo para o diretório <code>public</code>.</p><p>Abra o arquivo <code>index.html</code> e copie o seguinte:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;

&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
  &lt;link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.13/semantic.min.css"&gt;&lt;/link&gt;
  &lt;title&gt;webpack-for-react&lt;/title&gt;
&lt;/head&gt;

&lt;body&gt;
  &lt;div id="root"&gt;&lt;/div&gt;
&lt;/body&gt;

&lt;/html&gt;</code></pre><p>Nada demais aqui (apenas um modelo HTML padrão). Estamos somente adicionando a folha de estilo Semantic UI e criando uma <code>div</code> com o ID <code>root</code>. Aqui é onde nossa aplicação React será renderizada.</p><p>Volte ao seu terminal e digite:</p><pre><code>cd ..
mkdir src &amp;&amp; cd $_
touch index.js</code></pre><p>Abra o arquivo <code>index.js</code> e copie o seguinte:</p><pre><code>import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';

ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));</code></pre><p>Em seu terminal, digite:</p><pre><code>mkdir components &amp;&amp; cd $_
touch App.js Layout.js Layout.css Home.js DynamicPage.js NoMatch.js
</code></pre><p>Após a criação dos arquivos de componentes do React, temos a seguinte estrutura de projeto:</p><pre><code>|-- node_modules
|-- public
    |-- index.html
    |-- favicon.ico
|-- src
    |-- components
        |-- App.js
        |-- DynamicPage.js
        |-- Home.js
        |-- Layout.css
        |-- Layout.js
        |-- NoMatch.js
    |-- index.js
|-- .babelrc
|-- package.json
|-- webpack.config.js
|-- yarn.lock</code></pre><p>Abra o arquivo <code>App.js</code> e copie o seguinte:</p><pre><code class="language-js">import React from 'react';
import { Switch, BrowserRouter as Router, Route } from 'react-router-dom';

import Home from './Home';
import DynamicPage from './DynamicPage';
import NoMatch from './NoMatch';

const App = () =&gt; {
  return (
    &lt;Router&gt;
      &lt;div&gt;
        &lt;Switch&gt;
          &lt;Route exact path="/" component={Home} /&gt;
          &lt;Route exact path="/dynamic" component={DynamicPage} /&gt;
          &lt;Route component={NoMatch} /&gt;
        &lt;/Switch&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
};

export default App;</code></pre><p>Criamos nosso "shell" básico com React Router, contendo rotas para <em><em>home</em></em>, para a <em>página dinâmica e </em>para a <em>página não encontrada</em>.</p><p>Abra o arquivo <code>Layout.css</code> e copie o seguinte:</p><pre><code>.pull-right {
  display: flex;
  justify-content: flex-end;
}

.h1 {
  margin-top: 10px !important;
  margin-bottom: 20px !important;
}</code></pre><p>Abra o arquivo <code>Layout.js</code> e insira:</p><pre><code class="language-js">import React from 'react';
import { Link } from 'react-router-dom';
import { Header, Container, Divider, Icon } from 'semantic-ui-react';

import { pullRight, h1 } from './layout.css';

const Layout = ({ children }) =&gt; {
  return (
    &lt;Container&gt;
      &lt;Link to="/"&gt;
        &lt;Header as="h1" className={h1}&gt;
          webpack-for-react
        &lt;/Header&gt;
      &lt;/Link&gt;
      {children}
      &lt;Divider /&gt;
      &lt;p className={pullRight}&gt;
        Feito com &lt;Icon name="heart" color="red" /&gt; por Esau Silva
      &lt;/p&gt;
    &lt;/Container&gt;
  );
};

export default Layout;</code></pre><p>Este é o nosso componente de contêiner, onde definimos o layout do site. Fazendo uso dos módulos de CSS, estamos importando duas regras de CSS do <code>layout.css</code>. Observe, também, como estamos usando <em><em>camel case</em></em> para <code>pullRight</code>.</p><p>Abra o arquivo <code>Home.js</code> e copie o seguinte:</p><pre><code class="language-js">import React from 'react';
import { Link } from 'react-router-dom';

import Layout from './Layout';

const Home = () =&gt; {
  return (
    &lt;Layout&gt;
      &lt;p&gt;Olá Mundo do React e Webpack!&lt;/p&gt;
      &lt;p&gt;
        &lt;Link to="/dynamic"&gt;Navegar para a Página Dinâmica&lt;/Link&gt;
      &lt;/p&gt;
    &lt;/Layout&gt;
  );
};

export default Home;</code></pre><p>Abra o arquivo <code>DynamicPage.js</code> e insira:</p><pre><code class="language-js">import React from 'react';
import { Header } from 'semantic-ui-react';

import Layout from './Layout';

const DynamicPage = () =&gt; {
  return (
    &lt;Layout&gt;
      &lt;Header as="h2"&gt;Página Dinâmica&lt;/Header&gt;
      &lt;p&gt;Esta página foi carregada de forma assíncrona!!!&lt;/p&gt;
    &lt;/Layout&gt;
  );
};

export default DynamicPage;</code></pre><p>Abra o arquivo <code>NoMatch.js</code> e adicione:</p><pre><code class="language-js">import React from 'react';
import { Icon, Header } from 'semantic-ui-react';

import Layout from './Layout';

const NoMatch = () =&gt; {
  return (
    &lt;Layout&gt;
      &lt;Icon name="minus circle" size="big" /&gt;
      &lt;strong&gt;Página não encontrada!&lt;/strong&gt;
    &lt;/Layout&gt;
  );
};

export default NoMatch;</code></pre><p>Já terminamos de criar os componentes do React. Para uma etapa final antes de rodar nossa aplicação, abra <code>package.json</code> e faça com que tenha essa aparência:</p><pre><code class="language-js">{
  "name": "webpack-for-react",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "webpack-dev-server"
  },
  "dependencies": {
    "react": "^16.2.0",
    "react-dom": "^16.2.0",
    "prop-types": "^0.4.0",
    "react-router-dom": "^4.2.2",
    "semantic-ui-react": "^0.77.1"
  },
  "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/plugin-proposal-class-properties": "^7.0.0",
    "@babel/plugin-syntax-dynamic-import": "^7.0.0",
    "@babel/preset-env": "^7.0.0",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.1",
    "css-loader": "^0.28.10",
    "html-webpack-plugin": "^3.0.4",
    "style-loader": "^0.19.1",
    "webpack": "^4.0.0",
    "webpack-cli": "^2.0.14",
    "webpack-dev-server": "^3.0.0"
  }
}</code></pre><p>Adicionamos o elemento <code>scripts</code> e também o elemento <code>start</code>. Isto nos permitirá rodar o React com o Webpack Development Server. Se você não especificar um arquivo de configuração, <code>webpack-dev-server</code> procurará pelo arquivo <code>webpack.config.js</code> como a entrada de configuração padrão dentro do diretório raiz.</p><p>Agora, chegou o momento da verdade! Digite o seguinte em seu terminal (lembre-se de estar no diretório raiz) e ouse o yarn para chamar nosso script <code>start</code>.</p><pre><code>yarn start</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/iHJNOlQ4O11i7ONPbmXDRkbKF7WAGqZRFcCY.gif" class="kg-image" alt="iHJNOlQ4O11i7ONPbmXDRkbKF7WAGqZRFcCY" width="698" height="508" loading="lazy"><figcaption>React em execução</figcaption></figure><p>Agora temos uma aplicação do React em funcionamento, alimentada por nossa própria configuração de Webpack. No final do GIF acima, estou destacando o pacote de arquivos JavaScript gerado para nós e, como indicamos na configuração, o nome do arquivo tem um hash único, <code>bundle.d505bbab002262a9bc07.js</code>.</p><h3 id="configurando-um-hot-module-replacement-hmr-"><strong>Configurando um Hot Module Replacement (HMR)</strong></h3><p>De volta ao seu terminal, instale <a href="https://github.com/gaearon/react-hot-loader" rel="noopener">React Hot Loader</a> como dependência de desenvolvimento.</p><pre><code>yarn add react-hot-loader @hot-loader/react-dom -D</code></pre><p>Abra o arquivo <code>.babelrc</code> e acrescente as linhas <code>["@babel/preset-env", { "modules": false }],</code> (não se esqueça de incluir a vírgula (,) no final da linha) e <code>"react-hot-loader/babel"</code>:</p><pre><code class="language-js">{
  "presets": [
    ["@babel/preset-env", { "modules": false }],
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-class-properties",
    "react-hot-loader/babel"
  ]
}</code></pre><p>Abra o arquivo <code>webpack.config.js</code> e modifique-o conforme vemos abaixo.</p><p><em>Estou apenas incluindo o código relevante e omitindo o código que permaneceu o mesmo para auxiliar na brevidade<em>.</em></em></p><pre><code class="language-js">...
module.exports = {
  entry: './src/index.js',
  output: {
    ...
    publicPath: '/'
  },
  resolve: {
    alias: {
      "react-dom": "@hot-loader/react-dom",
    },
  },
  ...
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    ...
  ],
  devServer: {
    ...
    hot: true
  }
};</code></pre><ul><li><code>publicPath: '/'</code> — O <em>hot reloading</em> (recarregamento rápido) não funcionará como esperado para as rotas aninhadas sem ele</li><li><code>webpack.HotModuleReplacementPlugin</code> — Imprime nomes de módulos mais legíveis no terminal do navegador em atualizações do HMR</li><li><code>hot: true</code> — Habilita HMR no servidor</li><li><code>resolve: alias</code> —  substitui <code>react-dom</code> pelo <code>react-dom</code> customizado do <code>hot-loader</code></li></ul><p>Abra o arquivo <code>index.js</code> e altere-o para o seguinte:</p><pre><code class="language-js">import { hot } from "react-hot-loader/root";
import React from "react";
import ReactDOM from "react-dom";
import App from "./components/App";

import "./index.css";

const render = (Component) =&gt;
  ReactDOM.render(&lt;Component /&gt;, document.getElementById("root"));

render(hot(App));</code></pre><p>Agora, estamos prontos para testar o HMR! De volta ao terminal, execute sua aplicação, faça uma mudança e veja como a aplicação é atualizada sem uma atualização de página inteira.</p><pre><code>yarn start</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/tBaz3tT6Vsnxk7ijy1xFl03YFWmktaaktUWH.gif" class="kg-image" alt="tBaz3tT6Vsnxk7ijy1xFl03YFWmktaaktUWH" width="698" height="655" loading="lazy"><figcaption>HMR em ação</figcaption></figure><p>Após a atualização do arquivo, a página muda sem uma atualização completa. Para mostrar essa mudança no navegador, seleciono <strong><strong>Rendering -&gt; Paint flash</strong>ing</strong> em nas ferramentas de desenvolvedor do Chrome, que destaca as áreas da página que mudaram na cor verde. Destaco também, no Terminal, a mudança do Webpack, enviado para o navegador para que isso aconteça.</p><h3 id="code-splitting"><strong>Code Splitting</strong></h3><p>Com o <a href="https://webpack.js.org/guides/code-splitting/" rel="noopener"><em>code splitting</em></a><em> </em>(divisão de código, em português), em vez de ter sua aplicação em um grande pacote, você pode ter vários pacotes, cada um carregando de modo assíncrono ou em paralelo. Você também pode separar o código de outros fornecedores do código de sua aplicação, o que pode diminuir potencialmente o tempo de carregamento.</p><h4 id="por-rota"><strong>Por rota</strong></h4><p>Há várias maneiras de conseguirmos o <em>code splitting</em> por rota. No entanto, em nosso caso, usaremos o <a href="https://github.com/theKashey/react-imported-component" rel="noopener">react-imported-component</a>.</p><p>Gostaríamos, também, de mostrar um <em><em>spinner</em></em> <em>de carregamento </em>quando o usuário navega para uma rota diferente. Essa é uma boa prática, pois não queremos que o usuário fique apenas olhando para uma tela em branco enquanto espera que a nova página seja carregada. Assim, criaremos um componente <em><em>Loading</em></em>.</p><p>No entanto, se a nova página carregar muito rápido, não queremos que o usuário veja um spinner de carregamento piscando por alguns milissegundos. Assim, vamos atrasar o componente <em><em>Loading</em></em> em 300 milissegundos. Para conseguir isso, usaremos o <a href="https://github.com/arnthor3/react-delay-render" rel="noopener">React-Delay-Render</a>.</p><p>Comece instalando as duas dependências adicionais.</p><p>Em seu terminal, digite:</p><pre><code>yarn add react-imported-component react-delay-render</code></pre><p>Agora, vamos criar o componente <em><em>Loading</em></em>.</p><p>Em seu terminal, digite:</p><pre><code>touch ./src/components/Loading.js</code></pre><p>Abra o arquivo <code>Loading.js</code> e copie o seguinte:</p><pre><code class="language-js">import React from 'react';
import { Loader } from 'semantic-ui-react';
import ReactDelayRender from 'react-delay-render';

const Loading = () =&gt; &lt;Loader active size="massive" /&gt;;

export default ReactDelayRender({ delay: 300 })(Loading);</code></pre><p>Agora que temos o componente <em><em>Loading</em></em>, abra o arquivo <code>App.js</code> e modifique-o assim:</p><pre><code class="language-js">import React from 'react';
import { Switch, BrowserRouter as Router, Route } from 'react-router-dom';
import importedComponent from 'react-imported-component';

import Home from './Home';
import Loading from './Loading';

const AsyncDynamicPAge = importedComponent(
  () =&gt; import(/* webpackChunkName:'DynamicPage' */ './DynamicPage'),
  {
    LoadingComponent: Loading
  }
);
const AsyncNoMatch = importedComponent(
  () =&gt; import(/* webpackChunkName:'NoMatch' */ './NoMatch'),
  {
    LoadingComponent: Loading
  }
);

const App = () =&gt; {
  return (
    &lt;Router&gt;
      &lt;div&gt;
        &lt;Switch&gt;
          &lt;Route exact path="/" component={Home} /&gt;
          &lt;Route exact path="/dynamic" component={AsyncDynamicPAge} /&gt;
          &lt;Route component={AsyncNoMatch} /&gt;
        &lt;/Switch&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
};

export default App;</code></pre><p>Isto criará três pacotes, ou partes, uma para o componente <code>DynamicPage</code>, outra para o componente <code>NoMatch</code>, e uma terceira para a aplicação principal.</p><p>Vamos também mudar o nome do arquivo de pacote. Abra o arquivo <code>webpack.config.js</code> e modifique-o assim:</p><pre><code class="language-js">...
module.exports = {
  ...
  output: {
    filename: '[name].[hash].js',
    ...
  },
}</code></pre><p>É hora de rodar a aplicação e dar uma olhada no <em>code splitting</em> por rota em ação.</p><pre><code>yarn start</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/dNGa5cqDKitNHQAKtH7ZDce3fvrCCWuE1zYh.gif" class="kg-image" alt="dNGa5cqDKitNHQAKtH7ZDce3fvrCCWuE1zYh" width="698" height="684" loading="lazy"><figcaption><em>Code splitting</em> por rota</figcaption></figure><p>No GIF, primeiro, destaco as três partes diferentes criadas pelo Webpack no terminal. Depois, destaco que, na execução da aplicação, apenas a parte principal foi carregada. Por fim, vemos que, ao clicar em <em>Navigate to Dynamic Page </em>(Navegar para a página dinâmica), a parte correspondente a essa página é carregada de modo assíncrono.</p><p>Vemos também que a parte correspondente à <em><em>pá</em>gina não encontrada</em> nunca foi carregada, economizando a largura de banda do usuário.</p><h4 id="por-fornecedor"><strong>Por fornecedor</strong></h4><p>Agora vamos dividir a aplicação por fornecedor (em inglês, <em>vendor</em>). Abra o arquivo <code>webpack.config.js</code> e faça as seguintes mudanças:</p><pre><code class="language-js">...
module.exports = {
  entry: {
    vendor: ['semantic-ui-react'],
    app: './src/index.js'
  },
  ...
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        },
        vendor: {
          chunks: 'initial',
          test: 'vendor',
          name: 'vendor',
          enforce: true
        }
      }
    }
  },
  ...
};</code></pre><ul><li><code>entry.vendor: ['semantic-ui-react']</code> — Especifica de qual biblioteca queremos extrair de nossa aplicação principal para a parte do <em><em>vendor</em></em></li><li><code>optimization </code>— Se você deixar de fora esta entrada, o Webpack ainda dividirá sua aplicação por fornecedor. Entretanto, notei que os tamanhos dos pacotes eram grandes e, depois de adicionar essa entrada, os tamanhos dos pacotes foram reduzidos significativamente (descobri isso em <em><a href="https://github.com/webpack/webpack/issues/6357" rel="noopener">Webpack 4 migration draft</a> <em>CommonsChunkPlugin -&gt; Initial vendor ch</em>unk</em> - texto em inglês)</li></ul><p><em><strong>Observação</strong><em><strong><strong>:</strong></strong> </em>anteriormente, o Webpack 3 fazia uso do<em> </em></em><code><em><em>CommonsChunkPlugin</em></em></code><em><em> </em>para dividir o código por fornecedor e/ou commons. Porém, ele foi depreciado no Webpack 4 e muitas de suas características estão agora habilitadas por padrão.<em> </em>Com a remoção do<em> </em></em><code><em><em>CommonsChunkPlugin</em></em></code><em>,<em> </em></em>foi acrescentado o <code><em><em>optimization.splitChunks</em></em></code><em>,<em> </em>para aqueles que precisam de um controle de qualidade sobre sua estratégia de cache (veja </em><a href="https://gist.github.com/sokra/1522d586b8e5c0f5072d7565c2bee693" rel="noopener"><em><em>isto</em></em></a><em> para ter uma explicação detalhada<em>).</em></em></p><p>No terminal, inicie a aplicação:</p><pre><code>yarn start</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/L5D5dDH3r5DkNfhN2oilt1BaejnhCYfpdnQw.gif" class="kg-image" alt="L5D5dDH3r5DkNfhN2oilt1BaejnhCYfpdnQw" width="698" height="684" loading="lazy"><figcaption><em>Code splitting </em>por fornecedor</figcaption></figure><p>No terminal, destaco as três partes anteriores e a nova parte do <em>fornecedor (v<em>endor</em>)</em>. Depois, quando inspecionamos o HTML, vemos que as partes da aplicação principal e do fornecedor foram carregadas.</p><p>Como fizemos várias atualizações na configuração de nosso Webpack, você encontrará abaixo o arquivo completo <code>webpack.config.js</code>.</p><pre><code class="language-js">const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const port = process.env.PORT || 3000;
module.exports = {
  mode: 'development',
  entry: {
    vendor: ['semantic-ui-react'],
    app: './src/index.js'
  },
  output: {
    filename: '[name].[hash].js'
  },
  resolve: {
    alias: {
      "react-dom": "@hot-loader/react-dom",
    },
  },
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              localsConvention: 'camelCase',
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        },
        vendor: {
          chunks: 'initial',
          test: 'vendor',
          name: 'vendor',
          enforce: true
        }
      }
    }
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      favicon: 'public/favicon.ico'
    })
  ],
  devServer: {
    host: 'localhost',
    port: port,
    historyApiFallback: true,
    open: true,
    hot: true
  }
};</code></pre><h3 id="configura-o-de-produ-o"><strong>Configuração de produção</strong></h3><p>Renomeie o arquivo de configuração do Webpack de <code>webpack.config.js</code> para <code>webpack.config.<strong><strong>development</strong></strong>.js</code>. Depois, faça uma cópia dele e nomeie-o como <code>webpack.config.<strong>production</strong>.js</code>.</p><p>No seu terminal, digite o seguinte:</p><pre><code class="language-js">mv webpack.config.js webpack.config.development.js
cp webpack.config.development.js webpack.config.production.js</code></pre><p>Vamos precisar de uma dependência de desenvolvimento, <a href="https://github.com/webpack-contrib/extract-text-webpack-plugin" rel="noopener">Extract Text Plugin</a>. De acordo com sua documentação, ela "move todos os módulos <code>*.css</code> nas partes de <em>entry</em> para um arquivo CSS separado. Portanto, seus estilos não estão mais alinhados no pacote do JS, mas em um arquivo CSS em separado (<code>styles.css</code>). Se seu volume total de folha de estilo for grande, será mais rápido, pois o pacote do CSS é carregado em paralelo ao pacote do JS".</p><p>Em seu terminal, digite o seguinte:</p><pre><code>yarn add mini-css-extract-plugin -D</code></pre><p>Abra o arquivo <code>webpack.config.production.js</code> e faça as seguintes alterações:</p><blockquote><em>Observação: farei algo diferente aqui... vou acrescentar explicações com comentários em linha.</em></blockquote><pre><code class="language-js">const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
  mode: 'production',
  entry: {
    vendor: ['semantic-ui-react'],
    app: './src/index.js'
  },
  output: {
    // Queremos criar os pacotes de JavaScript sob um
    // diretório 'static'
    filename: 'static/[name].[hash].js',
    // Caminho absoluto para o diretório de saída desejado. Em nosso 
    // caso um diretório chamado 'dist'.
    // '__dirname' é uma variável de Node que nos dá o absoluto
    // caminho para nosso diretório atual. Então com 'path.resolve', 
    // juntamos diretórios
    // O Webpack 4 assume que seu caminho de saída será './dist',  
    // então você pode simplesmente deixar esta
    // entry de fora.
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  },
  // Mudança para source maps em produção
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      },
      {
        test: /\.css$/,
          use: [
            {
              // Nós configuramos 'MiniCssExtractPlugin'              
              loader: MiniCssExtractPlugin.loader,
            }, 
            {
              loader: 'css-loader',
              options: {
                modules: true,
                // Permite configurar quantos carregadores 
                // antes de css-loader deve ser aplicado
                // para recursos @import(ed)
                importLoaders: 1,
                localsConvention: 'camelCase',
                // Cria source maps para arquivos CSS
                sourceMap: true
              }
            },
            {
              // PostCSS funcionará antes do css-loader e 
              // minificar e autoprefixar nossas regras de CSS.
              loader: 'postcss-loader',
            }
          ]
      }
    ]
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        },
        vendor: {
          chunks: 'initial',
          test: 'vendor',
          name: 'vendor',
          enforce: true
        }
      }
    }
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      favicon: 'public/favicon.ico'
    }),
    
    // Criar a folha de estilos no diretório 'styles'
    new MiniCssExtractPlugin({
      filename: 'styles/styles.[hash].css'
    })
  ]
};</code></pre><p>Note que removemos a variável <code>port</code>, os plugins relacionados com HMR e o <em>entry</em> <code>devServer</code>.</p><p>Também uma vez que adicionamos o PostCSS à configuração de produção, precisamos instalá-lo e criar um arquivo de configuração para ele.</p><p>No seu terminal, digite o seguinte:</p><pre><code>yarn add postcss-loader autoprefixer cssnano postcss-preset-env -D
touch postcss.config.js</code></pre><p>Abra o arquivo <code>postcss.config.js</code> e copie o seguinte:</p><pre><code class="language-js">const postcssPresetEnv = require('postcss-preset-env');
module.exports = {
  plugins: [
    postcssPresetEnv({
      browsers: ['&gt;0.25%', 'not ie 11', 'not op_mini all']
    }),
    require('cssnano')
  ]
};</code></pre><p>Aqui, estamos especificando os navegadores para os quais queremos que o <code>autoprefixer</code>dê suporte (consulte a <a href="https://webpack.js.org/loaders/postcss-loader/" rel="noopener">Documentação</a> para mais opções) e minificando a saída do CSS.</p><p>Agora, para o último passo antes de criarmos nosso build de produção, precisamos criar um script <em><em>build</em></em> no arquivo <code>package.json</code>.</p><p>Abra o arquivo e faça as seguintes mudanças na seção <code>scripts</code>:</p><pre><code class="language-js">...
"scripts": {
  "dev":"webpack-dev-server --config webpack.config.development.js",
  "prebuild": "rimraf dist",
  "build": "cross-env NODE_ENV=production webpack -p --config webpack.config.production.js"
},
...</code></pre><p>A primeira coisa a notar aqui é que mudamos o script inicial de <code>start</code> para <code>dev</code>, então acrescentamos dois scripts adicionais, <code>prebuild</code> e <code>build</code>.</p><p>Finalmente, estamos indicando qual configuração usar quando em desenvolvimento ou produção.</p><ul><li><code>prebuild</code> — Será executado antes do script build e excluirá o diretório <code>dist</code> criado por nosso último build de produção. Utilizamos a biblioteca <a href="https://github.com/isaacs/rimraf" rel="noopener">rimraf</a> para isso</li><li><code>build</code> — Primeiro, usamos a biblioteca <a href="https://github.com/kentcdodds/cross-env" rel="noopener">cross-env</a>, no caso de alguém estar usando Windows. Desse modo, a configuração de variáveis de ambiente com <code>NODE_ENV</code> funcionará. Então, chamamos o Webpack com a flag <code>-p</code> para dizer a ele que otimize esse build para produção. Finalmente, especificamos a configuração da produção.</li></ul><p>Em seu terminal, instale as duas novas dependências que incluímos no arquivo <code>package.json</code>:</p><pre><code>yarn add rimraf cross-env -D</code></pre><p>Antes de criar o build de produção, vamos olhar para nossa nova estrutura de projeto:</p><pre><code>|-- node_modules
|-- public
    |-- index.html
    |-- favicon.ico
|-- src
    |-- components
        |-- App.js
        |-- DynamicPage.js
        |-- Home.js
        |-- Layout.css
        |-- Layout.js
        |-- Loading.js
        |-- NoMatch.js
    |-- index.js
|-- .babelrc
|-- package.json
|-- postcss.config.js
|-- webpack.config.development.js
|-- webpack.config.production.js
|-- yarn.lock</code></pre><p>Finalmente, podemos criar nosso pacote de produção.</p><p>Em seu terminal, digite o seguinte:</p><pre><code>yarn build</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/T81PYokNYP1m76WiEbGipkFrmGYKee46P4IR.gif" class="kg-image" alt="T81PYokNYP1m76WiEbGipkFrmGYKee46P4IR" width="698" height="238" loading="lazy"><figcaption>Criação <em>(build)</em> do pacote de produção</figcaption></figure><p>Como você notou, depois de executarmos o script <code>build</code>, o Webpack criou um diretório <code>dist</code> contendo nossa aplicação pronta para produção. Agora, inspecione os arquivos que foram criados e perceba que eles estão minificados. Cada um corresponde a um <em>source map</em>. Você também notará que o PostCSS adicionou a autoprefixação ao arquivo CSS.</p><p>Agora, pegamos nossos arquivos de produção e disparamos um servidor Node para servir nosso site. Este é o resultado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/A44vaXq-Jc68ClNMgWe5O0o4a3XjIfj3XLrU.gif" class="kg-image" alt="A44vaXq-Jc68ClNMgWe5O0o4a3XjIfj3XLrU" width="698" height="481" loading="lazy"><figcaption>Executando o build de produção</figcaption></figure><p><em><strong>Observação</strong><em><strong><strong>:</strong></strong> </em>estou usando </em><a href="https://github.com/esausilva/quick-node-server"><em>este servidor</em></a><em><em> </em>no<em> GIF </em>acima para<em> serv</em>ir<em> </em>nossos arquivos<em> </em>de <em>produ</em>ção<em>.</em></em></p><p>Neste ponto, temos duas configurações de Webpack em funcionamento, uma para desenvolvimento e outra para produção. No entanto, como ambas as configurações são muito semelhantes, elas compartilham muitas das mesmas opções. Se quiséssemos adicionar algo mais, teríamos que adicionar aos dois arquivos de configuração. Vamos corrigir este inconveniente.</p><h3 id="composi-o-do-webpack"><strong>Composição do Webpack</strong></h3><p>Vamos iniciar instalando <a href="https://github.com/survivejs/webpack-merge" rel="noopener">webpack-merge</a> e <a href="https://github.com/chalk/chalk" rel="noopener">Chalk</a> como dependências de desenvolvimento.</p><p>Em seu terminal, digite o seguinte:</p><pre><code>yarn add webpack-merge chalk -D</code></pre><p>Também precisaremos de novos diretórios e alguns arquivos novos.</p><p>Em seu terminal, digite o seguinte:</p><pre><code class="language-js">mkdir -p build-utils/addons
cd build-utils
touch build-validations.js common-paths.js webpack.common.js webpack.dev.js webpack.prod.js</code></pre><p>Agora, vamos olhar para nossa nova estrutura de projeto:</p><pre><code class="language-js">|-- build-utils
    |-- addons
    |-- build-validations.js
    |-- common-paths.js
    |-- webpack.common.js
    |-- webpack.dev.js
    |-- webpack.prod.js
|-- node_modules
|-- public
    |-- index.html
    |-- favicon.ico
|-- src
    |-- components
        |-- App.js
        |-- DynamicPage.js
        |-- Home.js
        |-- Layout.css
        |-- Layout.js
        |-- Loading.js
        |-- NoMatch.js
    |-- index.js
|-- .babelrc
|-- package.json
|-- postcss.config.js
|-- webpack.config.development.js
|-- webpack.config.production.js
|-- yarn.lock</code></pre><p>Abra o arquivo <code>common-paths.js</code> e copie o seguinte:</p><pre><code>const path = require('path');
const PROJECT_ROOT = path.resolve(__dirname, '../');

module.exports = {
  projectRoot: PROJECT_ROOT,
  outputPath: path.join(PROJECT_ROOT, 'dist'),
  appEntry: path.join(PROJECT_ROOT, 'src')
};</code></pre><p>Aqui definimos, como o nome sugere, os caminhos comuns para nossas configurações de Webpack. <code>PROJECT_ROOT</code> precisa procurar um diretório acima, já que estamos trabalhando sob o diretório <code>build-utils</code> (um nível abaixo do caminho raiz real em nosso projeto).</p><p>Abra o arquivo <code>build-validations.js</code> e copie o seguinte:</p><pre><code class="language-js">const chalk = require('chalk');
const ERR_NO_ENV_FLAG = chalk.red(
  `Você deve passar um --env.env flag em seu build para que o webpack funcione!`
);

module.exports = {
  ERR_NO_ENV_FLAG
};</code></pre><p>Mais tarde, quando modificarmos nosso <code>package.json</code>, vamos requerer a flag <code>–env.env</code> nos scripts. Essas validações são para verificar se a bandeira está presente. Caso contrário, ela lançará um erro.</p><p>Nos próximos três arquivos, separaremos as configurações do Webpack em configurações que são compartilhadas entre desenvolvimento e produção, configurações que são apenas para desenvolvimento e configurações apenas para produção.</p><p>Abra o arquivo <code>webpack.common.js</code> e copie o seguinte:</p><pre><code class="language-js">const commonPaths = require('./common-paths');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
  entry: {
    vendor: ['semantic-ui-react']
  },
  output: {
    path: commonPaths.outputPath,
    publicPath: '/'
  },
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /node_modules/,
        use: ['babel-loader']
      }
    ]
  },
  optimization: {
    splitChunks: {
      cacheGroups: {
        styles: {
          name: 'styles',
          test: /\.css$/,
          chunks: 'all',
          enforce: true
        },
        vendor: {
          chunks: 'initial',
          test: 'vendor',
          name: 'vendor',
          enforce: true
        }
      }
    }
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'public/index.html',
      favicon: 'public/favicon.ico'
    })
  ]
};
module.exports = config;</code></pre><p>Basicamente, extraímos o que foi compartilhado entre <code>webpack.config.development.js</code> e <code>webpack.config.production.js</code> e transferimos para este arquivo. Na parte superior, requeremos <code>common-paths.js</code> para definir o <code>output.path</code>.</p><p>Abra o arquivo <code>webpack.dev.js</code> e copie o seguinte:</p><pre><code class="language-js">const commonPaths = require('./common-paths');
const webpack = require('webpack');
const port = process.env.PORT || 3000;
const config = {
  mode: 'development',
  entry: {
    app: `${commonPaths.appEntry}/index.js`
  },
  output: {
    filename: '[name].[hash].js'
  },
  resolve: {
    alias: {
      "react-dom": "@hot-loader/react-dom",
    },
  },
  devtool: 'inline-source-map',
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: 'style-loader'
          },
          {
            loader: 'css-loader',
            options: {
              modules: true,
              localsConvention: 'camelCase',
              sourceMap: true
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ],
  devServer: {
    host: 'localhost',
    port: port,
    historyApiFallback: true,
    hot: true,
    open: true
  }
};
module.exports = config;</code></pre><p>Esse é o mesmo conceito que o do arquivo anterior. Aqui, extraímos apenas configurações de desenvolvimento.</p><p>Abra o arquivo <code>webpack.prod.js</code> e copie o seguinte:</p><pre><code class="language-js">const commonPaths = require('./common-paths');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const config = {
  mode: 'production',
  entry: {
    app: [`${commonPaths.appEntry}/index.js`]
  },
  output: {
    filename: 'static/[name].[hash].js'
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.css$/,
          use: [
            {
              // Configuramos 'MiniCssExtractPlugin'              
              loader: MiniCssExtractPlugin.loader,
            }, 
            {
              loader: 'css-loader',
              options: {
                modules: true,
                importLoaders: 1,
                localsConvention: 'camelCase',
                sourceMap: true
              }
            },
            {
              loader: 'postcss-loader'
            }
          ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: 'styles/styles.[hash].css'
    })
  ]
};
module.exports = config;</code></pre><p>Extraímos aqui apenas as configurações de produção.</p><p>Agora que temos as configurações compartilhadas e as específicas para desenvolvimento e produção em arquivos separados, é hora de colocar tudo junto.</p><p>No terminal, se você ainda estiver no diretório <code>build-utils</code>, suba um nível até a raiz do projeto, depois apague as configurações anteriores do Webpack e crie uma nova configuração do Webpack. Nomeie como <code>webpack.config.js</code>.</p><p>No seu terminal, digite o seguinte:</p><pre><code>cd ..
rm webpack.config.development.js webpack.config.production.js
touch webpack.config.js</code></pre><p>Antes de configurar o <code>webpack.config.js</code>, vamos abrir o <code>package.json</code> e atualizar a seção de <code>scripts</code>.</p><p>Modifique a seção assim:</p><pre><code class="language-js">...
"scripts": {
  "dev": "webpack-dev-server --env.env=dev",
  "prebuild": "rimraf dist",
  "build": "cross-env NODE_ENV=production webpack -p --env.env=prod"
},
...</code></pre><p>Uma vez que removemos a flag <code>–config</code>, o Webpack agora procurará a configuração padrão, que é <code>webpack.config.js</code>. Agora, usamos a flag <a href="https://webpack.js.org/guides/environment-variables/" rel="noopener">–env</a> para passar uma variável de ambiente para o Webpack, <code>env=dev</code> para desenvolvimento e <code>env=prod</code> para produção.</p><p>Abra o arquivo <code>webpack.config.js</code> e copie o seguinte:</p><p><em>Explicações com comentários em linha.</em></p><pre><code class="language-js">const buildValidations = require('./build-utils/build-validations');
const commonConfig = require('./build-utils/webpack.common');

const webpackMerge = require('webpack-merge');

// Podemos incluir plugins Webpack, através de addons, que fazem 
// com que não precisemos executá-lo toda vez que estamos desenvolvendo.
// Veremos um exemplo quando nos configurarmos 'Bundle Analyzer'
const addons = (/* string | string[] */ addonsArg) =&gt; {
  
  // Normalizar array de addons (flatten)
  let addons = [...[addonsArg]] 
    .filter(Boolean); // Se addons é indefinido, filtrá-lo

  return addons.map(addonName =&gt;
    require(`./build-utils/addons/webpack.${addonName}.js`)
  );
};

// 'env' conterá a variável ambiental da seção 'scripts' 
// no arquivo 'package.json'.
// console.log(env); =&gt; { env: 'dev' }
module.exports = env =&gt; {

  // Usamos 'buildValidations' para checar a flag 'env'
  if (!env) {
    throw new Error(buildValidations.ERR_NO_ENV_FLAG);
  }

  // Selecione a configuração do Webpack a ser usada; desenvolvimento 
  // ou produção
  // console.log(env.env); =&gt; dev
  const envConfig = require(`./build-utils/webpack.${env.env}.js`);
  
  // 'webpack-merge' combinará nossas configurações compartilhadas, 
  // as configurações específicas do ambiente e qualquer adição que 
  // estejamos incluindo
  const mergedConfig = webpackMerge(
    commonConfig,
    envConfig,
    ...addons(env.addons)
  );

  // Em seguida, retorna a configuração final para Webpack
  return mergedConfig;
};</code></pre><p>Essa pode parecer uma configuração muito extensa, mas, a longo prazo, será útil.</p><p>Neste momento, você pode rodar a aplicação ou criar (<em>build</em>) os arquivos de produção. Tudo funcionará como esperado (desculpe, sem GIF desta vez).</p><pre><code>yarn dev
yarn build</code></pre><p><strong><em>Observação</em><strong><em><em>:</em></em></strong></strong><em><em> </em>esta<em> </em>técnica de "Composição do <em>Webpack</em>"<em> </em>foi retirada<em> </em>da<em> <a href="https://webpack.academy/" rel="noopener">Webpack Academy</a>, </em>um curso gratuito de Sean Larkin que eu recomendo fazer para aprender mais sobre o Webpack. Ele não é específico para o React.</em></p><h3 id="b-nus-configurando-um-analisador-de-pacotes-do-webpack"><strong>BÔNUS: Configurando um analisador de pacotes do Webpack</strong></h3><p>Você não precisa necessariamente de um <a href="https://github.com/webpack-contrib/webpack-bundle-analyzer" rel="noopener">Webpack Bundle Analyzer</a> (analisador de pacotes do Webpack), mas ele vem a calhar quando se trata de otimizar suas criações.</p><p>Comece instalando a dependência e criando o arquivo de configuração.</p><p>Em seu terminal digite o seguinte:</p><pre><code>yarn add webpack-bundle-analyzer -D
touch build-utils/addons/webpack.bundleanalyzer.js</code></pre><p>Abra o arquivo <code>webpack.bundleanalyzer.js</code> e copie o seguinte:</p><pre><code>const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
  .BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin({
      analyzerMode: 'server'
    })
  ]
};</code></pre><p>Estamos apenas exportando a seção de plug-ins, que inclui o Webpack Bundle Analyzer. Então, o <code>webpack-merge</code> vai combiná-lo na configuração final do Webpack. Lembra-se dos <em><em>addons</em></em> no <code>webpack.config.js</code>? Bem, é aqui que eles entram em cena.</p><p>Para a etapa final, vamos abrir o <code>package.json</code> e incluir os novos scripts, deste modo:</p><pre><code>"scripts": {
  "dev": "webpack-dev-server --env.env=dev",
  "dev:bundleanalyzer": "yarn dev --env.addons=bundleanalyzer",
  "prebuild": "rimraf dist",
  "build": "cross-env NODE_ENV=production webpack -p --env.env=prod",
  "build:bundleanalyzer": "yarn build --env.addons=bundleanalyzer"
},</code></pre><ul><li><code>dev:bundleanalyzer</code> — Chama o script <code>dev</code> e passa uma nova variável de ambiente <code>addons=bundleanalyzer</code></li><li><code>build:bundleanalyzer</code> — Chama o script <code>build</code> e passa uma nova variável de ambiente <code>addons=bundleanalyzer</code></li></ul><p>Hora de rodar a aplicação com o <em>addon </em>do <em>Webpack Bundle Analyzer</em>.</p><p>Em seu terminal, digite o seguinte:</p><pre><code>yarn dev:bundleanalyzer</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/10/EFwowawQtLlHdJQGL9gwuz77O2wfhz784xW2.gif" class="kg-image" alt="EFwowawQtLlHdJQGL9gwuz77O2wfhz784xW2" width="698" height="481" loading="lazy"><figcaption>Webpack Bundle Analyzer</figcaption></figure><p>A aplicação é lançada juntamente ao <em>Webpack Bundle Analyzer</em>.</p><p>Incluir addons com a composição do Webpack pode ser muito útil, pois há muitos plug-ins que você gostaria de usar apenas em determinados momentos.</p><h3 id="conclus-o"><strong>Conclusão</strong></h3><p>Antes de mais nada, você pode obter o código completo no <a href="https://github.com/esausilva/react-starter-boilerplate-hmr">repositório do GitHub</a>.</p><p>Como você conseguiu chegar até aqui, parabéns! Agora que você conhece o básico (e um pouco mais) sobre o Webpack para o React, você pode continuar explorando e aprendendo características e técnicas mais avançadas.</p><p>Obrigado pela leitura. Espero que tenha gostado. Se você tiver alguma dúvida, sugestão ou correção, informe o autor. Não se esqueça de compartilhar o artigo para divulgar.</p><p>Você pode seguir o autor no <a href="https://medium.com/@_esausilva" rel="noopener">Medium</a>, no <a href="https://twitter.com/_esausilva" rel="noopener">Twitter</a>, no <a href="https://github.com/esausilva/" rel="noopener">GitHub</a>, no <a href="https://www.linkedin.com/in/esausilva/" rel="noopener">LinkedIn</a> ou em todos eles.</p><p>Este artigo foi originalmente publicado no <a href="https://esausilva.com/2018/01/13/learn-webpack-for-react/">blog pessoal</a> do autor.</p><hr><p><u><strong>Atualização do autor, de<strong> </strong>25<strong>/</strong>08<strong>/19:</strong></strong></u> Estou criando uma aplicação de orações, chamada "<strong><strong>My Quiet Time - A Prayer Journal</strong></strong>". Se você quiser saber das atualizações, inscreva-se através do link: <a href="http://b.link/mqt" rel="noopener noreferrer">http://b.link/mqt</a>.</p><p>A aplicação será lançada antes do final do ano. Tenho grandes planos para ela. Para ver algumas imagens do mockup, siga o seguinte link: <a href="http://pc.cd/Lpy7">http://pc.cd/Lpy7</a></p><p>Se tiver alguma dúvida sobre a aplicação, fique à vontade de enviar ao autor pelo <a href="https://twitter.com/_esausilva" rel="noopener">Twitter</a> por mensagem direta.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
