Skip to content

Frontend Development Guide

Matheus Vieira edited this page May 28, 2025 · 3 revisions

Symfony UX + React

📁 Estrutura Geral de assets/

assets/
├── app.ts
├── bootstrap.ts
├── controllers/                   ← Stimulus controllers (não-React)
│   ├── csrf_protection_controller.js
│   └── hello_controller.js
├── controllers.json               ← Configuração para @hotwired/stimulus
├── react/
│   ├── components/                ← Componentes funcionais reutilizáveis
│   │   ├── Home/                  ← Componentes da página Home
│   │   │   ├── CategoriesSection.tsx
│   │   │   ├── FeaturedMovies.tsx
│   │   │   └── MovieCard.tsx
│   │   └── shared/               ← Componentes reutilizados entre páginas
│   │       ├── DivineLines.tsx
│   │       ├── Footer.tsx
│   │       └── Header.tsx
│   ├── controllers/              ← "Root Controllers" React (integrados via Stimulus)
│   │   └── Home.tsx
│   └── types/                    ← Tipagens centralizadas
│       └── Movie.ts
└── styles/                       ← Estilos globais
    └── app.scss                  

🧩 Filosofia de Arquitetura

Este projeto segue uma abordagem modular e escalável, guiada pelas seguintes diretrizes:

1. Separação entre lógica de montagem e componentes

  • Diretório react/controllers/ contém componentes class-based integrados com o @symfony/ux-react. → Exemplo:

    // Home.tsx
    export default class extends Component<Movie, { movies: Movie[] }> {
        render(): ReactElement {
          return (
              <>
                  {/* Header */}
                  <Header/>
    
                  {/* Featured */}
                  <FeaturedMovies movies={this.state.movies}/>
    
                  {/* Divider */}
                  <DivineLines/>
    
                  {/* Categories */}
                  <CategoriesSection/>
    
                  {/* Footer */}
                  <Footer/>
    
              </>
          );
      }
    }
  • Diretório react/components/ contém componentes funcionais com TypeScript. → Totalmente puros e reutilizáveis:

    // MovieCard.tsx
    export const MovieCard: FC<Movie> = ({ title, imageUrl }): ReactElement => (
        <div className="movie-card">{title}</div>
    );

2. Tipagens sempre em react/types/

  • Tipos usados em múltiplos arquivos ou compartilhados entre componentes devem ser extraídos para esse diretório.
  • Isso reduz acoplamento, facilita refatoração e melhora a legibilidade global.
// types/Movie.ts
export interface Movie {
  id: string;
  title: string;
  imageUrl: string;
}

3. Twig + ReactController

A montagem dos componentes React ocorre de forma EXPLÍCITA no template, utilizando o helper react_component() provido por @symfony/ux-react. Esse helper injeta automaticamente os atributos data-* necessários para que o Stimulus inicialize o componente React correspondente.

Note

Não declaramos manualmente os atributos data-* no HTML.

Exemplo em Twig:
{# / or /home #}
{#
    Data available for consumption in the "Home" React controller:

    {{ playing }}   = now playing movies
    {{ popular }}   = popular movies
    {{ topRated }}  = top-rated movies
    {{ upcoming }}  = upcoming movie releases
#}
<main {{ react_component('Home', {upcoming: upcoming}) }} class="">
    <div class="loader">
        <div data-glitch="Loading..." class="glitch">Loading...</div>
    </div>
</main>

Isso resulta automaticamente em uma marcação como:

<div
  data-controller="react"
  data-react-component-name-value="Home"
  data-react-props-value="{...}">
</div>

Padrão dos componentes React

Embora o Symfony UX ofereça suporte a diferentes tipos de componentes React (incluindo function components com export const), neste projeto seguimos um padrão CLARO E BEM DEFINIDO:

  • Os arquivos em assets/react/controllers/ exportam componentes classe-based (class extends React.Component) com export default.

  • Já os arquivos em assets/react/components/ seguem o padrão function component com export const, usando a tipagem explícita com FC e ReactElement, favorecendo reutilização e legibilidade.

Essa separação foi adotada por clareza arquitetural: cada pasta e cada estilo de componente tem um propósito distinto e bem definido.


🛠 Convenções Gerais

Área Convenção
Componentes React Sempre funcionais e tipados com FC<Props>
Controllers React Sempre classes exportadas com default class extends Component
Estilos Globais Centralizados em styles/, com escopo atômico
Tipagem Centralizada em react/types/, nunca inline
Componentes Shared Tudo que for visual e reutilizável entre páginas vai em components/Shared/
Controllers JSON Gerenciado automaticamente (não editar diretamente)

🧪 Desenvolvimento e Boas Práticas

📦 Componentes e Tipagens

  • Todos os componentes devem ser escritos como Function Components (FC) com tipagem explícita.
  • Nenhum dado, propriedade ou estado deve ficar sem tipo declarado.
  • Tipos COMPLEXOS OU REUTILIZÁVEIS devem ser extraídos para arquivos dedicados em react/types/

Exemplo correto:

// types/Movie.ts
export interface Movie {
  title: string;
  description: string;
  poster: string;
  trailer: string;
}
// components/Home/MovieCard.tsx
import type { Movie } from '../../types/Movie';

export const MovieCard: FC<{ movie: Movie }> = ({ movie }): ReactElement => (
  <article>
    <img src={movie.poster} alt={movie.title} />
    <h2>{movie.title}</h2>
    <p>{movie.description}</p>
  </article>
);

Important

Nenhuma prop, variável de estado, retorno de função, evento ou elemento de UI deve permanecer sem tipo definido. Isso vale tanto para componentes quanto para lógica de controle e utilitários.


Criação de Novas Páginas (Controllers React)

Para cada nova página React que será montada por Twig, siga os passos:

  1. Crie um novo controller React dentro de react/controllers/ (por padrão, um arquivo .tsx que exporta um componente de classe estendendo Component).

  2. Crie os componentes funcionais puros em components/NomeDaPagina/. Mantenha esses componentes desacoplados e reutilizáveis.

  3. Declare a tipagem em arquivos separados dentro de react/types/ e utilize FC<Props> para tipar os componentes.

  4. Monte o controller no template Twig usando a função {{ react_component('NomeDoController') }}:

    <main {{ react_component('Home') }} class="">
        <div class="">Loading ...</div>
    </main>

Note

Apesar de o Symfony UX oferecer suporte à montagem via data-controller="react", aqui seguimos a abordagem {{ react_component(...) }} para manter a separação clara entre camadas e respeitar a responsabilidade de cada ferramenta.


📦 Build e Estilos

Como rodar o build do projeto

O projeto oferece duas formas de iniciar o ambiente com build de front-end já funcional:

  1. 🐳 Usando o Docker (forma recomendada e mais simples):

  2. 🛠 Configurando manualmente na máquina local:

    • Após clonar o repositório:

      npm install
      npm run dev
    • Essa etapa só é necessária caso você tenha optado por configurar o ambiente sem Docker, conforme explicado na mesma wiki acima.

Note

Ambas as abordagens levam ao mesmo resultado: aplicação rodando com build de front-end ativo e arquivos prontos para uso local.


📚 Recursos e Documentação


🧼 Manutenção

  • Tipos mudaram? Refatore no types/
  • Controller cresceu demais? Delegue a lógica para componentes filhos.
  • Componentes com mais de uma responsabilidade? Divida em subcomponentes.
  • Nunca adicione JSX diretamente em controllers/. Apenas controle de montagem.