Skip to content
This page has been auto-translated and may contain errors.View in English

Configurando um projeto React

Uma aplicação React precisa de um pouco de ferramental antes de qualquer código executar. Algo precisa transformar JSX em JavaScript que o navegador consiga executar, e algo precisa servir o resultado enquanto você trabalha nele. Vite faz os dois, e monta um projeto funcional em cerca de trinta segundos. Este capítulo te leva de uma pasta vazia a uma aplicação rodando, e depois rastreia o caminho que mais importa: como um componente acaba na tela.

Criando um projeto

Vite é uma ferramenta de build com um gerador de projetos integrado. Execute com npm create, responda duas perguntas, e você tem um projeto:

bash
npm create vite@latest my-react-app
cd my-react-app
npm install
npm run dev

O primeiro comando pergunta qual framework você quer (escolha React) e qual variante (escolha JavaScript, ou TypeScript se estiver usando). Ele cria uma pasta chamada my-react-app com tudo que um projeto React precisa. npm install baixa as dependências listadas em package.json, de onde o próprio React vem. npm run dev inicia o servidor de desenvolvimento e imprime um endereço local, geralmente http://localhost:5173. Abra isso em um navegador e a aplicação inicial está rodando.

A pasta gerada tem um punhado de arquivos que importam cedo:

  • index.html: a página HTML única que o navegador carrega.
  • src/main.jsx: o ponto de entrada, onde React se prende a essa página.
  • src/App.jsx: seu componente de topo, e o arquivo que você vai editar primeiro.
  • src/assets/: imagens e outros arquivos estáticos que você importa em componentes.
  • package.json: dependências e os scripts dev, build e preview.
  • vite.config.js: configuração de build, que você pode deixar de lado por um bom tempo.

Como as peças se conectam

Três arquivos se passam um ao outro em linha reta. Comece em index.html, que é propositalmente quase vazio:

html
<body>
  <div id="root"></div>
  <!-- seguido por uma tag <script type="module" src="/src/main.jsx"> -->
</body>

Aquela <div id="root"> vazia é o lugar na página que React tem permissão de preencher. Tudo que sua app renderiza cai dentro dela. A tag <script> de módulo abaixo dela carrega main.jsx, que é onde React assume o controle:

jsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
)

Leia essa chamada de trás para frente. document.getElementById('root') encontra a div vazia. createRoot a envolve em uma raiz React, significando que React agora é dono do conteúdo daquele elemento e vai mantê-lo sincronizado com seus componentes. .render(...) diz a ela o que colocar lá: o componente App.

<StrictMode> é um envoltório apenas para desenvolvimento que executa verificações extras em tudo dentro dele e avisa sobre padrões que provavelmente causarão bugs. Não adiciona nada à página e desliga a si mesmo em um build de produção. Seu efeito mais visível aparece em Effects, onde propositalmente monta cada componente duas vezes durante o desenvolvimento.

App.jsx é um componente ordinário que se exporta:

jsx
export default function App() {
  return <h1>Hello from React</h1>
}

Essa é a cadeia toda. O navegador carrega index.html, o script carrega main.jsx, main.jsx chama createRoot na div root e renderiza <App />, e App retorna o JSX que vira o heading que você vê. Todo componente que você escrever daqui em diante fica em algum lugar dentro de App, então alcança a página através desse mesmo caminho. main.jsx é geralmente escrito uma vez e raramente tocado novamente; quase todo seu trabalho acontece em App.jsx e nos componentes que ela puxa.

Nota de versão

React 17 e anteriores usavam ReactDOM.render(<App />, document.getElementById('root')) como ponto de entrada. React 18 introduziu createRoot, que é o que liga rendering concorrente, e deixou a chamada antiga funcionando com um aviso de deprecação. React 19 removeu, então ReactDOM.render agora lança um erro. Em um tutorial que ainda usa, createRoot é a linha para escrever no seu lugar. Veja History and versions para o que mudou.

O servidor de desenvolvimento

npm run dev inicia o servidor de desenvolvimento do Vite, e ele fica rodando no terminal enquanto você trabalha. O trabalho dele é servir sua app e reagir às suas edições.

Salve uma mudança em App.jsx e o navegador atualiza quase imediatamente, sem um refresh manual. Isso é hot module replacement: Vite empurra o módulo alterado para a página e o troca no lugar, deixando o resto da app rodando. Um contador que você teria clicado até sete geralmente ainda lê sete depois da edição, então você mantém o estado que tinha configurado enquanto ajusta a marcação ao redor. Algumas mudanças ainda forçam um reload completo, e Vite decide isso para você.

Dois outros scripts vêm com o projeto. npm run build produz um bundle otimizado em uma pasta dist, que é o que você faz deploy. npm run preview serve esse output construído localmente para você verificar antes de lançar. Durante o desenvolvimento, npm run dev é o único que você precisa.

Importando ativos estáticos

Imagens vivem sob src/assets e entram em um componente através de um import:

jsx
import logo from './assets/logo.png'

export default function Header() {
  return <img src={logo} alt="Company logo" />
}

O import te dá uma variável segurando a URL final daquela imagem, que você então passa para src entre chaves. Escrever src="./assets/logo.png" como uma string simples tende a quebrar, porque os caminhos na sua pasta source raramente são os caminhos no output construído.

Importar o arquivo em vez disso coloca a ferramenta de build no loop. Ela vê que seu código depende de logo.png, copia para o output, e te devolve de volta qualquer URL que aquele arquivo acaba sendo. Mova seu componente para uma pasta diferente e o import relativo ainda resolve. Misepe o nome do arquivo e você descobre imediatamente, porque o import falha, em vez de descobrir uma imagem quebrada em produção. O mesmo padrão funciona para SVGs, fontes e qualquer outro arquivo que a ferramenta de build saiba como lidar.

Um navegador não tem ideia do que é um arquivo .jsx. Não há parser de JSX em nenhuma engine de JavaScript, e <App /> é um erro de sintaxe em JavaScript puro. O que o navegador recebe já foi transformado. Vite executa cada arquivo .jsx através do esbuild, que reescreve o JSX em chamadas de função: sob o automatic runtime do React 19, <App /> vira uma chamada tipo _jsx(App, {}). Qual helper você recebe depende do modo. A transformação de produção importa jsx de react/jsx-runtime, enquanto a transformação de desenvolvimento importa jsxDEV de react/jsx-dev-runtime e passa argumentos extras carregando o arquivo source e número de linha, que é como um aviso do React no seu console consegue apontar para o lugar exato no seu código. A extensão .jsx é principalmente um sinal para ferramental de que esse arquivo contém sintaxe precisando daquela transformação. No momento em que algo alcança a página, são módulos JavaScript ordinários chamando funções ordinários.

O servidor de desenvolvimento e o build de produção pegam rotas diferentes para aquele resultado. Em desenvolvimento, Vite serve módulos ES nativos e transforma cada arquivo sob demanda, então o tempo de startup mal cresce com o tamanho do projeto e uma única edição só invalida aquele módulo. npm run build muda para Rollup, que agrupa o grafo todo, tree-shakes exportações não usadas, minifica, e divide código em chunks. O comportamento pode diferir ligeiramente entre os dois, que é por que npm run preview existe.

O import de imagem funciona porque o bundler trata arquivos não-JavaScript como parte do grafo de módulos também. import logo from './assets/logo.png' não é um import de módulo JavaScript real. Vite o intercepta, emite o arquivo para dist/assets com um hash de conteúdo no nome, e substitui o import com uma string literal daquele caminho final, algo tipo /assets/logo-4f2a1c8b.png. O hash é o que torna caching agressivo seguro: mude a imagem e o nome do arquivo muda com ela, então nenhuma cópia obsoleta sobrevive em um CDN. Arquivos abaixo de um threshold de tamanho (4KB por padrão) pulam o request separado completamente e ficam inlineados como uma URL de dados base64. Em desenvolvimento o mesmo import resolve para um caminho simples servido pelo servidor de desenvolvimento, que é por que a URL que você vê em devtools difere entre npm run dev e um build real.

JunoUm caminho da página ao seu componente Setup são quatro comandos, e depois você pode esquecer disso. O que vale a pena guardar é a cadeia: index.html tem uma div vazia com o id root, main.jsx agarra aquela div com createRoot e renderiza <App /> dentro dela, e App.jsx é o componente que diz o que aparece. Uma vez que você consegue seguir aquele caminho, você sabe exatamente onde seu próprio código se encaixa.
JunoUm caminho da página ao seu componentenpm create vite@latest, escolha React, instale, npm run dev. Dali é index.html para main.jsx para App.jsx: o arquivo de entrada chama createRoot na div root uma vez e renderiza seu componente topo, e você gasta o resto do seu tempo abaixo daquela linha. Importe imagens em vez de codificar paths para que a ferramenta de build as resolva e lhes dê fingerprint para você.
JunoUm caminho da página ao seu componente O setup existe porque JSX não tem runtime: esbuild reescreve <App /> em chamadas de runtime, jsx de react/jsx-runtime em um build e jsxDEV de react/jsx-dev-runtime em desenvolvimento, antes de algo alcançar o navegador, e imports de assets resolvem para URLs com hash que o bundler emite. Dev roda módulos ES não-bundled através de esbuild, produção roda Rollup, então trate npm run preview como a verificação de que os dois concordam. createRoot é o ponto de entrada do React 18, e é o que liga sua árvore em rendering concorrente.

Próximo: Components, os blocos de construção que você preencherá aquele App.jsx com.