<?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[ Webpack - 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[ Webpack - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Mon, 06 Jul 2026 20:10:30 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/webpack/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <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>
