Kochbuch für TYPO3 Fluid Component: Rezepte für moderne Frontend Entwicklung

Kochbuch für TYPO3 Fluid Component: Rezepte für moderne Frontend Entwicklung

Das TYPO3 Ökosystem hat mit der Einführung der komponentenbasierten Frontend Entwicklung in Fluid 4.3 einen bedeutenden Sprung nach vorne gemacht. Dieses bahnbrechende Feature bringt moderne Frontend-Entwicklungsmuster direkt in die TYPO3-Welt und bietet Entwicklern einen besser wartbaren, wiederverwendbaren und kollaborativen Ansatz zur Erstellung von Web-Oberflächen.

Wenn Sie bisher mit dem traditionellen Templating-System von TYPO3 gearbeitet haben oder mit den Einschränkungen von Partials zu kämpfen hatten, erfahren Sie in diesem Handbuch alles, was Sie über Fluid Components wissen müssen - von grundlegenden Konzepten bis hin zu fortgeschrittenen Implementierungsstrategien.

Dieses leistungsstarke Feature ist Simon Praetorius (@s2b) zu verdanken, der drei Monate damit verbracht hat, moderne, komponentenbasierte Muster in TYPO3 einzuführen. Seine Vision, seine Entwicklungsarbeit und seine klare Dokumentation haben es für Entwickler einfacher gemacht, diesen modernen Ansatz zu übernehmen. Wir sind dankbar für seinen Beitrag zur Weiterentwicklung der TYPO3 Frontend Entwicklung.

Fluid-Komponenten sind benutzerdefinierte HTML-ähnliche Tags, die auf Fluid Templates basieren und die Sie in Ihrem gesamten Projekt wiederverwenden können. Das Konzept ähnelt beliebten Frontend-Frameworks wie React und Vue oder nativen Webkomponenten, wird jedoch von PHP serverseitig gerendert.

Stellen Sie sich Komponenten als in sich geschlossene, wiederverwendbare Teile der Benutzeroberfläche vor, die sowohl Struktur als auch Verhalten kapseln. Im Gegensatz zu herkömmlichen Fluid-Partials bieten Komponenten:

  • Strenge Typisierung: Komponenten haben explizite Argumentdefinitionen unter Verwendung des <f:argument> ViewHelper
  • Globale Verfügbarkeit: Keine manuelle Konfiguration von partiellen Wurzelpfaden in Rendering-Kontexten notwendig
  • Klare APIs: Gut definierte Schnittstellen, die Komponenten weniger fehleranfällig und besser wartbar machen
  • Bessere Organisation: Komponenten fördern eine modulare Architektur mit gruppierten, verwandten Assets

Komponenten vs. Partials: Die Hauptunterschiede

Obwohl Partials und Komponenten auf den ersten Blick ähnlich erscheinen mögen, dienen sie unterschiedlichen Zwecken:

Traditionelle Teilkomponenten:

<f:render partial="Button" arguments="{
    variant: 'primary',
    label: 'Click me'
}" />

Moderne Komponenten:

<my:atom.button variant="primary">
    Click me
</my:atom.button>

Der Komponentenansatz ist intuitiver, bietet bessere IDE-Unterstützung (geplant) und bietet eine strengere Typüberprüfung.

Moderne Frontend-Muster übernehmen

Die Webentwicklungslandschaft hat sich dramatisch in Richtung komponentenbasierte Architekturen verschoben. Von React und Vue.js bis hin zu nativen Web Components erwarten Entwickler modulare, wiederverwendbare UI-Bausteine. Komponenten führen einen modernen, komponentenbasierten Workflow ein, der Ihre Frontend- und Integrationsarbeit modularer, konsistenter und wartbarer macht.

Verbesserte Entwicklererfahrung

Komponenten verändern die Art und Weise, wie Teams an TYPO3 Projekten zusammenarbeiten:

  • Frontend-Entwickler können unabhängig voneinander an UI-Komponenten arbeiten
  • Backend-Entwickler erhalten klare, dokumentierte APIs für die Integration
  • Projektmanager profitieren von besser vorhersehbaren Entwicklungszeitplänen
  • Designer können sehen, dass ihre Designsysteme konsistent umgesetzt werden

Bessere Wartbarkeit

Durch die Kapselung der Funktionalität in einzelnen Komponenten erhalten Sie:

  • Leichteres Debugging und Testen
  • Weniger Code-Duplizierung
  • Klarere Trennung von Belangen
  • Vereinfachte Refactoring-Prozesse

React vs. Fluid Components: Ein praktischer Vergleich

Das Verständnis der Unterschiede zwischen Fluid Components und React kann Entwicklern helfen, fundierte Architekturentscheidungen zu treffen.

Ähnlichkeiten

AspektReactFluid-Komponenten
Definition von KomponentenJSX-basierte KomponentenFluid-Komponenten auf Basis von Vorlagen
Requisiten/ArgumenteTypisierte Requisiten mit PropTypes/TypeScriptTypisierte Argumente mit <f:argument>
ZusammenstellungKomponentenverschachtelung und KompositionKomponentenverschachtelung mit <f:slot>
WiederverwendbarkeitImportieren und überall verwendenGlobale Verfügbarkeit mit Namespaces

Hauptunterschiede

Rendering-Modell:

  • React: Client-seitiges Rendering (oder SSR mit zusätzlichen Einstellungen)
  • Fluid-Komponenten: Server-seitiges Rendering als Standard

Datenfluss:

  • React: Unidirektionaler Datenfluss mit Zustandsverwaltung
  • Fluid-Komponenten: Template-Variablen und kontextbasierte Daten

Lernkurve:

  • React: Erfordert JavaScript/TypeScript-Kenntnisse
  • Fluid-Komponenten: Verwendet die vertraute Fluid-Syntax für Vorlagen

Wann sollte man was wählen?

Wählen Sie Fluid Components, wenn:

  • Erstellung traditioneller TYPO3 Websites mit serverseitigem Rendering
  • Arbeiten mit TYPO3 Content Management Workflows
  • das Team über fundierte Fluid/TYPO3 Kenntnisse verfügt
  • SEO und Leistung sind wichtige Anforderungen

React in Betracht ziehen, wenn:

  • hochgradig interaktive Anwendungen erstellen
  • eine komplexe clientseitige Zustandsverwaltung benötigen
  • Entwicklung von TYPO3 Implementierungen ohne Kopfhörer
  • das Team über fundierte JavaScript-Kenntnisse verfügt

Voraussetzungen

Sie können bereits heute Komponenten in Ihren Composer-basierten TYPO3 v13 Projekten verwenden, indem Sie auf die neueste Fluid Version aktualisieren. Stellen Sie sicher, dass Sie über:

  • TYPO3 v13+ mit Composer
  • Fluid 4.3+ installiert
  • Grundlegendes Verständnis von Fluid Templating

Schritt 1: Komponentensammlung einrichten

Erstellen Sie zunächst eine Komponentensammlungsklasse, die definiert, wo sich Ihre Komponenten befinden:

<?php
namespace Vendor\MyPackage\Components;

use TYPO3Fluid\Fluid\Core\Component\AbstractComponentCollection;
use TYPO3Fluid\Fluid\View\TemplatePaths;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;

final class ComponentCollection extends AbstractComponentCollection
{
    public function getTemplatePaths(): TemplatePaths
    {
        $templatePaths = new TemplatePaths();
        $templatePaths->setTemplateRootPaths([
            ExtensionManagementUtility::extPath(
                'my_sitepackage', 
                'Resources/Private/Components/'
            ),
        ]);
        return $templatePaths;
    }
}

Schritt 2: Erstellen Sie Ihre erste Komponente

Erstellen Sie eine Ordnerstruktur für Ihre Komponenten. Folgen Sie dabei den Prinzipien des atomaren Designs:

Resources/Private/Components/
├── Atom/
│   └── Button/
│       └── Button.html
├── Molecule/
│   └── Card/
│       └── Card.html
└── Organism/
    └── Header/
        └── Header.html

Erstellen Sie Ihre erste Schaltflächenkomponente(Button/Button.html):

<f:argument name="variant" type="string" optional="true" default="primary" />
<f:argument name="size" type="string" optional="true" default="medium" />
<f:argument name="disabled" type="bool" optional="true" default="false" />

<button 
    class="btn btn--{variant} btn--{size}"
    {f:if(condition: disabled, then: 'disabled="disabled"')}
>
    <f:slot />
</button>

Schritt 3: Verwenden Sie Ihre Komponente

Importieren Sie in einer beliebigen Fluid-Vorlage den Namespace und verwenden Sie Ihre Komponente:

<html
    xmlns:my="http://typo3.org/ns/Vendor/MyPackage/Components/ComponentCollection"
    data-namespace-typo3-fluid="true"
>
    
<my:atom.button variant="secondary" size="large">
    Get Started Now
</my:atom.button>

</html>

This renders as:
<button class="btn btn--secondary btn--large">
    Get Started Now
</button>

Erstellen einer Teaser Card-Komponente

Lassen Sie uns eine komplexere Komponente erstellen, die Komposition und mehrere Argumente demonstriert:

<!-- Components/Molecule/Card/Card.html -->
<f:argument name="title" type="string" />
<f:argument name="subtitle" type="string" optional="true" />
<f:argument name="image" type="string" optional="true" />
<f:argument name="link" type="string" optional="true" />
<f:argument name="variant" type="string" optional="true" default="default" />

<article class="card card--{variant}">
    <f:if condition="{image}">
        <div class="card__image">
            <img src="{image}" alt="{title}" />
        </div>
    </f:if>
    
    <div class="card__content">
        <h3 class="card__title">{title}</h3>
        <f:if condition="{subtitle}">
            <p class="card__subtitle">{subtitle}</p>
        </f:if>
        
        <div class="card__body">
            <f:slot />
        </div>
        
        <f:if condition="{link}">
            <div class="card__footer">
                <my:atom.button variant="outline">
                    <a href="{link}">Read More</a>
                </my:atom.button>
            </div>
        </f:if>
    </div>
</article>

Verwendung:

<my:molecule.card 
    title="TYPO3 Components" 
    subtitle="Modern Frontend Development"
    image="/images/typo3-logo.svg"
    link="/learn-more"
    variant="featured"
>
    Discover how Fluid Components revolutionize TYPO3 frontend development 
    with reusable, maintainable UI building blocks.
</my:molecule.card>

Formularkomponenten mit Validierung

Erstellen Sie eine wiederverwendbare Formulareingabekomponente:

<!-- Components/Atom/Input/Input.html -->
<f:argument name="name" type="string" />
<f:argument name="type" type="string" optional="true" default="text" />
<f:argument name="label" type="string" optional="true" />
<f:argument name="placeholder" type="string" optional="true" />
<f:argument name="required" type="bool" optional="true" default="false" />
<f:argument name="value" type="string" optional="true" />
<f:argument name="error" type="string" optional="true" />

<div class="form-field {f:if(condition: error, then: 'form-field--error')}">
    <f:if condition="{label}">
        <label for="{name}" class="form-field__label">
            {label}
            <f:if condition="{required}">
                <span class="form-field__required">*</span>
            </f:if>
        </label>
    </f:if>
    
    <input 
        type="{type}"
        id="{name}"
        name="{name}"
        placeholder="{placeholder}"
        value="{value}"
        class="form-field__input"
        {f:if(condition: required, then: 'required="required"')}
    />
    
    <f:if condition="{error}">
        <span class="form-field__error">{error}</span>
    </f:if>
</div>

Navigationskomponente mit aktiven Zuständen

<!-- Components/Organism/Navigation/Navigation.html -->
<f:argument name="items" type="array" />
<f:argument name="currentPage" type="string" optional="true" />

<nav class="main-navigation">
    <ul class="nav-list">
        <f:for each="{items}" as="item">
            <li class="nav-item {f:if(condition: '{item.url} == {currentPage}', then: 'nav-item--active')}">
                <a href="{item.url}" class="nav-link">
                    {item.title}
                </a>
                <f:if condition="{item.children}">
                    <ul class="nav-submenu">
                        <f:for each="{item.children}" as="child">
                            <li class="nav-subitem">
                                <a href="{child.url}" class="nav-sublink">
                                    {child.title}
                                </a>
                            </li>
                        </f:for>
                    </ul>
                </f:if>
            </li>
        </f:for>
    </ul>
</nav>

Empfehlungen zur Ordnerstruktur

Organisieren Sie die Komponenten nach den Prinzipien des atomaren Designs:

Resources/Private/Components/
├── Atom/                    # Basic building blocks
│   ├── Button/
│   ├── Input/
│   ├── Icon/
│   └── Link/
├── Molecule/                # Component combinations
│   ├── Card/
│   ├── SearchBox/
│   └── Breadcrumb/
├── Organism/                # Complex UI sections
│   ├── Header/
│   ├── Footer/
│   └── ProductList/
└── Template/                # Page-level layouts
    ├── Default/
    └── Landing/

Benennungskonventionen

Befolgen Sie konsistente Benennungsmuster:

  • PascalCase für Komponentenordnernamen(Button, SearchBox)
  • kebab-case für CSS-Klassen(btn-primary, search-box)
  • camelCase für Argumente(isActive, showIcon)

Komponenten-API-Design

Entwerfen Sie klare, intuitive Komponenten-APIs:

<!-- Good: Clear, predictable arguments -->
<f:argument name="variant" type="string" optional="true" default="primary" />
<f:argument name="size" type="string" optional="true" default="medium" />
<f:argument name="disabled" type="bool" optional="true" default="false" />

<!-- Avoid: Too many optional arguments without good defaults -->
<f:argument name="buttonStyle" type="string" optional="true" />
<f:argument name="buttonColor" type="string" optional="true" />
<f:argument name="buttonBorder" type="string" optional="true" />

Überlegungen zur Leistung

  • Konzentrieren Sie sich auf die Komponenten und halten Sie sie klein
  • Vermeiden Sie nach Möglichkeit eine tiefe Verschachtelung von Komponenten
  • Verwenden Sie Caching-Strategien für teure Operationen
  • Erwägen Sie die Verwendung von ViewHelper-Caching für statische Komponenten

Fallstrick 1: Überkomponentisierung

Problem: Erstellen Sie Komponenten für jedes kleine UI-Element, auch wenn diese nur einmal verwendet werden.
Lösung: Befolgen Sie die „Dreierregel“ – erstellen Sie eine Komponente, wenn Sie sie an drei verschiedenen Stellen benötigen oder wenn sie eine komplexe Logik aufweist, die es wert ist, gekapselt zu werden.

<!-- Avoid: Over-componentizing -->
<my:atom.paragraph text="Simple text" />

<!-- Better: Use direct HTML for simple cases -->
<p>Simple text</p>

Fallstrick 2: Unzureichend definierte Komponenten-APIs

Problem: Komponenten mit unklarer oder inkonsistenter Argumentbenennung.
Lösung: Legen Sie klare Konventionen fest und dokumentieren Sie Ihre Komponenten-APIs:

<!-- Poor: Unclear naming -->
<f:argument name="btn_type" type="string" />
<f:argument name="isDisable" type="bool" />

<!-- Better: Consistent, clear naming -->
<f:argument name="variant" type="string" />
<f:argument name="disabled" type="bool" />

Fallstrick 3: Ignorieren der Komponentenzusammensetzung

Problem: Monolithische Komponenten erstellen, die versuchen, alles zu tun.
Lösung: Setzen Sie auf Komposition – bauen Sie komplexe Komponenten aus einfacheren auf:

<!-- Complex card component composed of simpler parts -->
<my:molecule.card>
    <f:slot name="header">
        <my:atom.badge variant="new">New</my:atom.badge>
        <my:atom.heading level="3">{title}</my:atom.heading>
    </f:slot>
    
    <f:slot name="content">
        <!-- Content here -->
    </f:slot>
    
    <f:slot name="footer">
        <my:atom.button variant="primary">Action</my:atom.button>
    </f:slot>
</my:molecule.card>

Fallstrick 4: Vermischung von Belangen

Problem: Einbeziehung von Geschäftslogik oder Datenabruf in Präsentationskomponenten.
Lösung: Konzentrieren Sie die Komponenten auf die Präsentation. Behandeln Sie die Datenaufbereitung in Controllern oder ViewHelpers:

<!-- Avoid: Data fetching in components -->
<f:argument name="productId" type="int" />
<!-- Complex data fetching logic here -->

<!-- Better: Pass prepared data -->
<f:argument name="product" type="array" />

Fallstrick 5: Unzureichende Fehlerbehandlung

Problem: Komponenten brechen ab, wenn die erforderlichen Argumente fehlen.
Lösung: Verwenden Sie geeignete Argumentdefinitionen mit sinnvollen Standardwerten:

<f:argument name="title" type="string" />
<f:argument name="variant" type="string" optional="true" default="default" />

<f:if condition="{title}">
    <h2 class="component-title component-title--{variant}">
        {title}
    </h2>
<f:else>
    <f:debug title="Missing required argument: title" />
</f:if>

Kontextbereitstellung für Design Tokens

Manchmal kann es hilfreich sein, einige globale Einstellungen für alle Komponenten innerhalb einer Komponentensammlung bereitzustellen. Ein gängiger Anwendungsfall könnte die Bereitstellung von Design-Tokens aus einer JSON-Datei für Ihre Komponenten sein.

<?php
namespace Vendor\MyPackage\Components;

use TYPO3Fluid\Fluid\Core\Component\AbstractComponentCollection;

final class ComponentCollection extends AbstractComponentCollection
{
    private ?array $designTokens = null;

    public function getAdditionalVariables(string $viewHelperName): array
    {
        $this->designTokens ??= json_decode(
            file_get_contents('path/to/designTokens.json'), 
            true
        );
        
        return [
            'designTokens' => $this->designTokens,
        ];
    }
}

Verwenden Sie Design-Token in Komponenten:

<f:argument name="color" type="string" optional="true" default="brand" />

<div class="alert" style="
    background-color: {designTokens.colors.{color}};
    border-radius: {designTokens.borderRadius.medium};
    padding: {designTokens.spacing.medium};
">
    <f:slot />
</div>

Dynamisches Laden von Komponenten

Für komplexere Szenarien können Sie das dynamische Laden von Komponenten implementieren:

<!-- Dynamic component based on content type -->
<f:switch expression="{content.type}">
    <f:case value="text">
        <my:molecule.textBlock content="{content}" />
    </f:case>
    <f:case value="image">
        <my:molecule.imageBlock content="{content}" />
    </f:case>
    <f:case value="video">
        <my:molecule.videoBlock content="{content}" />
    </f:case>
    <f:defaultCase>
        <my:molecule.genericBlock content="{content}" />
    </f:defaultCase>
</f:switch>

Strategien für Komponententests

Obwohl Fluid Components noch keine eingebauten Test-Frameworks haben, können Sie Teststrategien implementieren:

  • Unit-Tests: Testen der Komponentenlogik in PHP

  • Integrationstests: Testen der gerenderten HTML-Ausgabe
  • Visuelle Regressionstests: Verwenden Sie Tools wie BackstopJS oder Percy
  • Testen der Zugänglichkeit: Sicherstellen, dass Komponenten die WCAG-Richtlinien erfüllen

Alternative Ordner-Strukturen

Wenn Sie eine alternative Ordnerstruktur zum Standard definieren möchten, können Sie dies tun, indem Sie eine benutzerdefinierte Implementierung von resolveTemplateName in Ihrer ComponentCollection bereitstellen.

<?php
public function resolveTemplateName(string $viewHelperName): string
{
    $fragments = array_map('ucfirst', explode('.', $viewHelperName));
    return implode('/', $fragments);
}

Dies ermöglicht flachere Strukturen:

Components/
├── Atom/
│   └── Button.html      # Instead of Button/Button.html
├── Molecule/
│   └── Card.html
└── Organism/
    └── Header.html

Von Partials zu Komponenten

Die Migration bestehender Partials zu Komponenten ist einfach:

Vorher (Partial):

<!-- Partials/Button.html -->
<button class="btn btn--{variant}">
    {label}
</button>

<!-- Usage -->
<f:render partial="Button" arguments="{variant: 'primary', label: 'Click me'}" />

Nach (Komponente):

<!-- Components/Atom/Button/Button.html -->
<f:argument name="variant" type="string" optional="true" default="primary" />

<button class="btn btn--{variant}">
    <f:slot />
</button>

<!-- Usage -->
<my:atom.button variant="primary">Click me</my:atom.button>

Schrittweiser Migrationsansatz

  • Beginnen Sie mit neuen Komponenten: Beginnen Sie mit der Verwendung von Komponenten für neue Funktionen
  • Konvertieren Sie Teilkomponenten mit hoher Auswirkung: Migrieren Sie zuerst häufig genutzte Teilkomponenten
  • Aktualisieren Sie die Vorlagen schrittweise: Ersetzen Sie partielle Aufrufe durch die Verwendung von Komponenten
  • Entfernen Sie veraltete Teilfunktionen: Aufräumen, sobald die Migration abgeschlossen ist

Zukünftige Entwicklungen

Die TYPO3 Community hat spannende Pläne für Fluid Components:

  • IDE-Unterstützung: XSD-Dateigenerierung für Autovervollständigung und Validierung
  • Verbessertes Tooling: Bessere Debugging- und Entwicklungstools
  • Leistungsoptimierungen: Caching Verbesserungen und Optimierungen
  • Erweiterungen der Integration: Bessere TYPO3 Backend Integration

Beteiligung der Community

Beteiligen Sie sich an der Diskussion in #typo3-fluid auf Slack, oder öffnen Sie einen Eintrag auf GitHub, wenn Sie einen Fehler finden.

Wie Sie sich einbringen können:

  • Teilen Sie Feedback und Anwendungsfälle im TYPO3 Slack
  • Tragen Sie zur Verbesserung der Dokumentation bei
  • Melden Sie Bugs und schlagen Sie Funktionen auf GitHub vor
  • Teilen Sie Ihre Komponentenbibliotheken mit der Community

Ressourcen zum Lernen

Aufbau eines Komponenten-Ökosystems

Erwägen Sie die Erstellung und gemeinsame Nutzung von Komponentenbibliotheken:

  • Design-System-Komponenten: Implementieren Sie das Designsystem Ihrer Organisation
  • Branchenspezifische Komponenten: Erstellen Sie Komponenten für bestimmte Bereiche
  • Integrationskomponenten: Erstellen von Komponenten für Dienste von Drittanbietern
  • Open-Source-Bibliotheken: Teilen Sie wiederverwendbare Komponenten mit der Community

Fluid Components stellen einen Paradigmenwechsel in der TYPO3 Frontend-Entwicklung dar und bringen moderne komponentenbasierte Muster auf die von uns geliebte Plattform. Mit diesem neuen Ansatz können Entwickler besser wartbare, wiederverwendbare und kollaborative Frontend-Architekturen erstellen.

Beim Übergang vom traditionellen Templating zur komponentenbasierten Entwicklung geht es nicht nur um eine neue Syntax, sondern um eine Denkweise, die Modularität, Wiederverwendbarkeit und klare Schnittstellen in den Vordergrund stellt. Ganz gleich, ob Sie einfache Websites oder komplexe Anwendungen erstellen, Fluid Components bieten die Werkzeuge und Muster, die Sie für die moderne Frontend-Entwicklung benötigen.

Fangen Sie klein an, experimentieren Sie mit grundlegenden Komponenten und bauen Sie Ihre Komponentenbibliothek nach und nach auf. Die TYPO3-Community ist gespannt darauf, was Sie mit dieser neuen Funktion schaffen werden. Willkommen in der Zukunft der TYPO3-Frontend-Entwicklung!

Möchten Sie tiefer eintauchen? Schauen Sie sich die offizielle Fluid Components-Dokumentation und beteiligen Sie sich an der Diskussion in den TYPO3-Gemeinschaftsforen.

Your One-Stop Solutions for Custom TYPO3 Development

  • A Decade of TYPO3 Industry Experience
  • 350+ Successful TYPO3 Projects
  • 87% Repeat TYPO3 Customers
TYPO3 Service
service

Post a Comment

×