Zum Inhalt springen

Frontend

Build-System, Asset-Pipeline, JavaScript-/SCSS-Architektur und Best Practices.

MP-Core Logo

Anforderungen

  • Node.js >= 22 (Node 24 empfohlen)
  • npm >= 10

Technologie-Stack

  • Vite 8 – Build-Tool mit HMR
  • Vue.js 3.5 – Interaktive Komponenten (TodoList, GallerySwiper, SwiperSlider)
  • Bootstrap 5.3 – UI-Framework
  • Sass 1.99 – CSS-Vorverarbeitung (Modern-Compiler-API)
  • PostCSS – preset-env, pxtorem
  • ESLint 10 / Stylelint 17 – Codequalität
  • Swiper 12 – Touch-Schieberegler (integriert über Vue-Komponenten)
  • Jarallax 3 – Parallax-Scrolling

Schnellstart

 
cd Build
npm ci
npm run watch   # Auto-rebuild on file changes
 

In einem mpc-Monorepo, in dem DDEV läuft, können Sie den Build auch aus dem Stammverzeichnis der Website starten: ddev mp-core-build (entspricht npm run build innerhalb libs/mp-core/Build/).

Die Ausgabe erfolgt in Resources/Public/ (JavaScripts, Stylesheets, Schriftarten, Icons, Bilder, Favicons, Backend-Layouts).

SkriptBeschreibung
buildLint + Produktions-Build (minimiert, optimiert) + Bundle-Größenprüfung
build:analyzeProduktionsbuild mit rollup-plugin-visualizer (schreibt reports/bundle-stats.html)
devLint + Entwicklungs-Build mit Source-Maps
watchEntwicklungs-Build mit Datei-Watcher
check-sizeFühren Sie das Bundle-Größen-Budget-Gate aus für Resources/Public/
lintESLint + Stylelint ausführen
eslint / eslint.fixJavaScript-Linting
stylelint / stylelint.fixCSS/SCSS-Linting

Sauberer Build: rm -rf node_modules Resources/Public && npm ci && npm run build

Projektstruktur

Build-Verzeichnis

 
Build/
├── Assets/
│   ├── Fonts/                  # Web fonts (WOFF2)
│   ├── Images/                 # Source images, Icons/
│   ├── Scripts/                # JavaScript/Vue
│   │   ├── code/               # Feature modules
│   │   │   ├── Utils/          # Shared utilities (domUtils.js, …)
│   │   │   ├── Vue/            # vue-initialisation.js (component registry)
│   │   │   └── Navigation/     # Primary / Secondary / Tertiary
│   │   └── components/         # Vue SFCs
│   ├── Scss/                   # SCSS (ITCSS layers)
│   │   ├── Base/               # Variables, fonts
│   │   ├── Elements/           # Base elements
│   │   ├── Mixins/             # SCSS mixins
│   │   ├── Modules/            # UI components
│   │   ├── Templates/          # Layout helpers
│   │   └── Extensions/         # TYPO3 extension overrides
│   └── Static/                 # Copied as-is (BackendLayouts, Favicons)
├── vite.config.js
├── eslint.config.js
├── stylelint.config.js
└── postcss.config.js
 

Ressourcenverzeichnis

 
Resources/
├── Private/                    # Fluid templates (not web-accessible)
│   ├── Backend/, Language/, Layouts/, Partials/, Templates/
├── Extensions/                 # Extension template overrides
│   ├── fluid_styled_content/, form/, indexed_search/, news/
└── Public/                     # Compiled assets (web-accessible)
    ├── Fonts/, Icons/, Images/, JavaScripts/, StyleSheets/, Favicons/
 

Bundle-Budgets

Jeder npm run build endet mit dem Aufruf von scripts/check-bundle-size.js. Das Skript liest jede kompilierte JS-/CSS-Datei aus Resources/Public/, berechnet die Größen nach gzip (Stufe 9) und Brotli (Qualität 11), vergleicht diese mit scripts/bundle-budgets.jsonund beendet die Ausführung mit einem Wert ungleich Null, wenn ein dateispezifisches oder kombiniertes Gesamtbudget überschritten wird. Eine WARN-Meldung (orangefarbene Warnung) wird ausgegeben, wenn ein Bundle innerhalb von 10 % seines Budgets liegt – das ist das Signal, eine Refaktorisierung durchzuführen, bevor die nächste Funktion uns über die Grenze treibt.

Wenn ein Bundle aus legitimen Gründen gewachsen ist (neue Komponente, beabsichtigtes Upgrade einer Abhängigkeit), aktualisiere scripts/bundle-budgets.json im selben Commit wie die Größenänderung vor. Erhöhen Sie niemals ein Budget, nur um den Gate zu umgehen.

Baseline (03.06.2026)

Erfasst mit Vite 8, Bootstrap 5.3.8, Vue 3.5, Swiper 12.

BundleRohGzipBrotli
bootstrap.js65,9 KiB20,1 KiB17,9 KiB
screen.js33,0 KiB9,6 KiB8,6 KiB
vue.js239,8 KiB72,5 KiB63,8 KiB
navigationPrimary.js1,7 KiB662 B560 B
navigationSecondary.js5,6 KiB1,3 KiB1,2 KiB
navigationTertiary.js4,4 KiB1,3 KiB1,1 KiB
paginationTruncate.js1,7 KiB733 B579 B
theme-init.js222 B183 B129 B
bootstrap.css174,1 KiB24,2 KiB17,5 KiB
screen.css67,4 KiB10,6 KiB9,1 KiB
vue.css24,2 KiB3,9 KiB3,4 KiB
navigationPrimary.css7,8 KiB1,8 KiB1,6 KiB
navigationSecondary.css25,2 KiB3,6 KiB3,2 KiB
navigationTertiary.css17,3 KiB3,2 KiB2,8 KiB
ckeditor.css18,3 KiB2,7 KiB2,3 KiB
print.css1,3 KiB559 B432 B
insgesamt--158,7 KiB135,8 KiB

Nach der Refaktorisierung von „manual-chunk“ und „dynamic-import“ (siehe „Vendor-Aufteilung“ unten) ist zu erwarten, vue.js erheblich schrumpfen, da die Vue-Laufzeitumgebung, Swiper und die drei Vue-SFCs in langlebige vendor-* / pro-SFC- Chunks verschoben werden. Führen Sie den Vorgang npm run check-size einmal nach dem nächsten Build und senken Sie die betroffenen Budgets in scripts/bundle-budgets.json.

„Vendor Splitting“

vite.config.js definiert eine manualChunks Map, die diese node_modules Pfade in benannte Anbieter-Chunks zusammenfasst:

BlockInhalt
vendor-vuevue, @vue/*
vendor-swiperswiper
vendor-bootstrapbootstrap
vendor-popper@popperjs/core
vendor-jarallaxjarallax

Anbieter-Blöcke ändern sich nur, wenn sich die festgepinntes Abhängigkeit ändert; daher bleiben sie über mehrere Bereitstellungen hinweg im HTTP-Cache erhalten, während sich unser eigener Anwendungscode ändert.

Code-Splitting bei Vue-Komponenten

code/Vue/vue-initialisation.js verwendet dynamische import() pro Komponente, sodass jeder .vue SFC zu einem eigenen Chunk kompiliert. Eine Seite, die nur SwiperSlider nie heruntergeladen TodoList oder GallerySwiper. Fügen Sie neue Komponenten hinzu, indem Sie die componentLoaders Map in vue-initialisation.js.

On-Demand-Anbieter: Jarallax

code/jarallax.js lädt das Jarallax-Anbieter-Bundle verzögert über dynamische import('jarallax'), abhängig von einer document.querySelectorAll('.grid-parallax') Präsenzprüfung. Der .grid-parallax Wrapper wird nur ausgegeben, fluid_styled_content/Layouts/Container.html , wenn ein Editor das Parallax-Kontrollkästchen (grid_parallax = 1) bei einem ce_container-Stil- Inhaltselement aktiviert.

Auswirkung: Seiten ohne Parallax-Container fordern den vendor-jarallax-*.js Chunk (~26 KiB im Rohformat / ~7 KiB gzip / ~6 KiB brotli) an. Dank der manualChunks Map; lediglich die Netzwerkanfrage wechselt von „eager“ zu „deferred“.

Visualisierung des Bundles

 
npm run build:analyze
 

Schreibt Build/reports/bundle-stats.html (Treemap, gzip- und Brotli-fähig, git-ignoriert). Direkt im Browser öffnen; kein Server erforderlich.

Vite-Einstiegspunkte

Definiert in Build/vite.config.js:

BundleZweck
bootstrap.jsInitialisierung des Bootstrap-Frameworks
screen.jsHaupt-Frontend (sticky Header, Theme usw.)
vue.jsVue.js 3-Komponenten (einschließlich Swiper-Integration)
navigationPrimary/Secondary/Tertiary.jsNavigationsebenen
print.jsDruckspezifische Stile
backend.jsTYPO3-Backend-Stile
ckeditor.jsCKEditor-RTE-Stile
 

Hinweis: Swiper ist in das vue.js Bundle integriert – es gibt keinen separaten swiper.js Einstiegspunkt.

 

Neuen Eintrag hinzufügen

  1. Erstellen Sie eine JS-Datei in Build/Assets/Scripts/
  2. Registrieren unter vite.config.js
  3. Ausführen npm run watch
  4. In Fluid einbinden:
<f:asset.script identifier="myfeature" src="EXT:mp_core/Resources/Public/JavaScripts/myfeature.js" />
<f:asset.css identifier="myfeature" href="EXT:mp_core/Resources/Public/StyleSheets/myfeature.css" />
 

JavaScript-Architektur

Funktionsmodule (Build/Assets/Scripts/code/)

Kern: main.js, i18n.js, i18nLinkHelper.js

UI: jarallax.js, modalGallery.js, openAccordionAndTabs.js, pagination.js, sticky.js, totop.js

Navigation: nav-toggle.js, Navigation/Primary/navigation.js, Navigation/Secondary/navigation.js, Navigation/Tertiary/navigation.js

Layout: moveHeaderDate.js, moveMeta.js, theme.js

Suche: searchAutosuggest.js — Type-Ahead für indexed_search (Kopfzeile und /suche Formular)

Gemeinsam genutzte Funktionen (code/Utils/domUtils.js)

  • debounce(func, wait) -- Leistungsoptimierte Handhabung von Größenanpassung und Bildlauf
  • toggleNavState(...) -- geöffneter/geschlossener Zustand der Navigation
  • handleDropdownVisibility(element, showCb, hideCb) -- Bootstrap-Dropdown-Ereignisse
  • toggleAriaLabelAndTitle(element, openLabel, closeLabel) -- Barrierefreies Umschalten von Beschriftungen

Vue.js-Komponenten

Befindet sich in Build/Assets/Scripts/components/:

KomponenteBeschreibung
TodoList.vueInteraktive Aufgabenliste mit localStorage, registriert als CType mpcore_todolist
GallerySwiper.vueSwiper-basiertes Galerie-Karussell für das Galerie-Inhaltselement
SwiperSlider.vueGenerischer Swiper-Slider für Container-Slider-Elemente

Die Registrierung der Komponenten erfolgt in code/Vue/vue-initialisation.js.

Vue-Mounts auf Elementen mit data-container="vue" und data-component="ComponentName" (siehe VueComponents.typoscript und Vorlagen für Inhaltselemente). Optionale data-* Attribute übergeben Props (z. B. data-card-title bei „TodoList“).

Eine neue Komponente erstellen

  1. Erstellen Sie .vue Datei in Build/Assets/Scripts/components/
  2. Registrieren in code/Vue/vue-initialisation.js
  3. Erstellen und über <f:asset.script> in Fluid (der vue.js Einstiegspunkt bindet registrierte Komponenten automatisch ein).

SCSS-Architektur (ITCSS)

Ebenen von geringer bis hoher Spezifität:

  1. Einstellungen (Base/) – Variablen, Schriftarten, Farbtabellen
  2. Tools (Mixins/) – Funktionen, Mixins (keine CSS-Ausgabe)
  3. Allgemein – Zurücksetzen, Normalisieren (aus Bootstrap)
  4. Elemente (Elements/) – Basis-HTML-Elemente
  5. Objekte – Layoutmuster
  6. Komponenten (Modules/) – Gestaltete UI-Komponenten
  7. Hilfsfunktionen – Hilfsklassen

Bootstrap-Anpassung

  • Helles Design: Build/Assets/Scss/Base/Bootstrap/_custom-variables.scss
  • Dunkles Design: Build/Assets/Scss/Base/Bootstrap/_custom-variables-dark.scss

Verwaltung von Assets

Asset-TypMuster
Bilder in SCSSurl('../../Images/Icons/icon.png') (relativer Pfad)
Schriftarten@include font-face('Name', '../../Fonts/file', 400, normal, woff2)
Inline-SVGsvg-load('../Images/Icons/arrow.svg')
Statische DateienBuild/Assets/Static/ -> kopiert nach Resources/Public/

Vorlagenintegration

Fluid

 
<f:asset.css identifier="screen" href="EXT:mp_core/Resources/Public/StyleSheets/screen.css" />
<f:asset.script identifier="screen" src="EXT:mp_core/Resources/Public/JavaScripts/screen.js" />
 

TypoScript

 
page {
  includeCSS.screen = EXT:mp_core/Resources/Public/StyleSheets/screen.css
  includeJSFooter.screen = EXT:mp_core/Resources/Public/JavaScripts/screen.js
}
 

Priorität der Vorlagenpfade: Höhere Zahlen haben Vorrang vor niedrigeren (0 = Kern, 10 = Erweiterung, 20+ = Projekt).

Überschreibungen durch Erweiterungen

ErweiterungPfadAnmerkungen
fluid_styled_contentResources/Extensions/fluid_styled_content/Private/Im Bootstrap-5-Stil
FormularResources/Extensions/form/Bootstrap-Formulare + YAML-Konfiguration
NachrichtenResources/Extensions/news/Listen-, Detail- und Kategorieansichten
Indexierte SucheResources/Extensions/indexed_search/Bootstrap-Suchergebnisse + Combobox mit Autovervollständigung

mp-core ersetzt die standardmäßigen „indexed_search“-Vorlagen und fügt eine barrierefreie Combobox mit Autovorschlägen für das Suchfeld in der Kopfzeile und die spezielle Suchseite hinzu (/suche).

Website-Einstellungen

Konfigurieren unter „Website-Verwaltung“ → „Websites“ → „Einstellungen“ → „Suche“ (oder config/sites/<id>/settings.yaml):

EinstellungStandardWirkung
search.headerSearchtrueSuchfeld in der Kopfzeile anzeigen (alle Navigationsvarianten)
search.autosuggesttrueVorschläge während der Eingabe für Kopfzeile und /suche Formularen

Wenn die automatische Vorschlagsfunktion deaktiviert ist, wird in beiden Formularen ein einfaches Suchfeld angezeigt.

Verhalten

  • Vorschläge werden als JSON abgerufen aus SearchSuggestMiddleware / SearchSuggestService — indizierte Basiswörter sowie passende Seitentitel, eingeschränkt auf die aktuelle Website, Sprache und den Zugriff des Frontend-Benutzers (kein Solr erforderlich).
  • Die Combobox folgt dem WAI-ARIA-Listbox-Muster mit Tastaturnavigation und höflichen Statusmeldungen.
  • Die obersten Ergebnisse verweisen auf dieselben Detail-URLs wie die vollständigen Suchergebnisse (einschließlich Mediathek-Einträge, die über Indexer-Routenargumente aufgelöst werden).
  • Die Suche in der Kopfzeile wird per POST an die „indexed_search“ search (cHash-sicher). Bei den Desktop-navType-Werten 1/2/3 erscheint das Feld je nach Breakpoint im Flyout der Meta-Leiste oder inline im mobilen Hamburger-Menü.

Frontend-Modul: Build/Assets/Scripts/code/searchAutosuggest.js (enthalten in screen.js).

Best Practices

JavaScript: Modularer Code in code/, gemeinsame Muster in Utils/, Debounce bei Größenänderung/Scrollen, Event-Delegation, ARIA-Labels, Lint vor dem Commit.

SCSS: ITCSS-Ebenen beachten, CSS-Variablen für das Theming, logische Eigenschaften für RTL, maximal 3 Verschachtelungsebenen, Mobile-First- min-width Abfragen.

Vue.js: Single-File-Komponenten, bereichsbezogene Stile, Prop-Validierung, Composition-API für komplexe Logik.

Fehlerbehebung

ProblemLösung
404-Fehler bei SchriftartenÜberprüfen Sie ../ Segmente aus SCSS auf Fonts/
Fehlende Bilder im CSSPfad im Assets/Images/
Bundle zu großNur benötigte Bootstrap-Komponenten importieren
Änderungen werden nicht angezeigtBrowser- und TYPO3-Cache leeren

Wichtig: Niemals Resources/Public/ direkt. Bearbeiten Sie immer in Build/Assets/ und führen Sie npm run build.

Weiterführende Literatur

Seite teilen