-
Notifications
You must be signed in to change notification settings - Fork 2
Frontend Development Guide
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
Este projeto segue uma abordagem modular e escalável, guiada pelas seguintes diretrizes:
-
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> );
- 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;
}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.
{# / 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>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) comexport default. -
Já os arquivos em
assets/react/components/seguem o padrão function component comexport const, usando a tipagem explícita comFCeReactElement, 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.
| Á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) |
- 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.
Para cada nova página React que será montada por Twig, siga os passos:
-
Crie um novo controller React dentro de
react/controllers/(por padrão, um arquivo.tsxque exporta um componente de classe estendendoComponent). -
Crie os componentes funcionais puros em
components/NomeDaPagina/. Mantenha esses componentes desacoplados e reutilizáveis. -
Declare a tipagem em arquivos separados dentro de
react/types/e utilizeFC<Props>para tipar os componentes. -
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.
O projeto oferece duas formas de iniciar o ambiente com build de front-end já funcional:
-
🐳 Usando o Docker (forma recomendada e mais simples):
- Basta seguir o passo a passo descrito em: 👉 https://github.com/BAD-WOLF/StreamVibe/wiki/Symfony-Project-Setup-Guide
- O build já acontece automaticamente ao iniciar os containers com o projeto.
-
🛠 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.
- Symfony UX React: ux.symfony.com/react
- Symfony UX: ux.symfony.com
- React + TypeScript: react-typescript-cheatsheet.netlify.app
- 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.