Aufbau, Zweck und eigene Einträge für den Compatibility Layer
Wer ein Drittanbieter-Modul in ein Hyvä-Theme einbindet, stößt früher oder später auf die module-config.json-Datei. Sie entscheidet pro Modul, ob native Hyvä-Templates greifen oder ob die Frontend-Ausgabe auf ein Fallback-Theme wie Magento/blank zurückfällt. Dieser Beitrag erklärt Aufbau, Laufzeitlogik, Merge-Verhalten und eigene Einträge Schritt für Schritt.
Inhaltsverzeichnis
- 1. Einordnung: Was module-config.json wirklich löst
- 2. Aufbau der Datei: Felder und Schema
- 3. Laufzeitauswertung: hyva-themes/module-fallback
- 4. Eigene Einträge hinzufügen: Schritt für Schritt
- 5. Zusammenspiel mit Layout-XML und ViewModel
- 6. Priorität und Merge-Verhalten über Theme-Vererbung
- 7. Typische Fehler
- 8. Best Practices
- 9. module-config.json im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Einordnung: Was module-config.json wirklich löst
Die module-config.json-Datei ist Hyvä's themenweite Kompatibilitäts-Registry. Sie liegt unter app/design/frontend/<Vendor>/<theme>/etc/module-config.json und wird von Hyvä's Theme-Fallback-Mechanismus, dem sogenannten Hyvä-Compatibility-Modules-System, gelesen, um pro Magento-Modul zu entscheiden, ob dieses Modul native Hyvä-Template-Overrides besitzt oder ob das Frontend-Rendering für die Seiten dieses Moduls auf einen Compatibility- beziehungsweise Blank-Rendering-Pfad zurückfallen muss. Genau dieses Problem löst module-config.json: die kontrollierte Steuerung eines Kompatibilitäts-Layers pro Modul, statt eines harten Theme-Forks für jedes Drittanbieter-Paket.
Ohne module-config.json müsste jedes Team, das ein noch nicht portiertes Luma-Modul einbindet, entweder das komplette Theme forken oder riskieren, dass ungestylte Luma-Fragmente im Hyvä-Frontend auftauchen. Mit einer gepflegten module-config.json-Datei bleibt die Entscheidung deklarativ: ein Eintrag pro Modul, ein klarer Fallback-Pfad, keine verstreuten Bedingungen im Template-Code. Das macht module-config.json zu einem zentralen Baustein jeder Hyvä-Theme-Architektur, gerade in Projekten mit vielen gewachsenen Drittanbieter-Erweiterungen aus der Luma-Welt.
2. Aufbau der Datei: Felder und Schema
Strukturell ist module-config.json ein flaches JSON-Objekt, dessen oberste Schlüssel die vollqualifizierten Magento-Modulnamen sind, etwa Vendor_Module. Jeder Schlüssel referenziert ein Konfigurationsobjekt mit einer festen Menge an Feldern. Das Feld hyva-compatible ist ein Boolean und markiert, ob das Modul native Hyvä-Templates mitbringt oder darauf ausgelegt ist, ohne Fallback zu rendern. Das Feld fallback-theme ist ein String, meist Magento/blank, und definiert, welches Theme als Rendering-Basis dient, wenn kein Hyvä-Override existiert. priority ist ein Integer und steuert die Reihenfolge, in der mehrere passende Compatibility-Einträge ausgewertet werden. requires ist ein Array und listet Modulabhängigkeiten auf, die erfüllt sein müssen, bevor der Eintrag greift.
Diese vier Felder bilden das Kernschema von module-config.json, wie es auch das offizielle hyva-themes/module-fallback-Paket erwartet. Zusätzliche, projektspezifische Felder werden vom Standard-Reader ignoriert, sind aber in eigenen ViewModels auswertbar, etwa um zusätzliche Metadaten für ein Compatibility-Dashboard zu transportieren. Die folgende JSON-Struktur zeigt das vollständige Schema an zwei Beispielmodulen, eines mit nativer Hyvä-Unterstützung, eines mit Fallback auf Magento/blank.
{
"// comment": "module-config.json - Hyvä theme-level compatibility registry",
"Magento_Catalog": {
"hyva-compatible": true,
"fallback-theme": null,
"priority": 100,
"requires": []
},
"Vendor_LegacyReviews": {
"hyva-compatible": false,
"fallback-theme": "Magento/blank",
"priority": 50,
"requires": ["Magento_Review"]
},
"Vendor_ThirdPartySlider": {
"hyva-compatible": false,
"fallback-theme": "Magento/blank",
"priority": 20,
"requires": []
}
}
3. Laufzeitauswertung: hyva-themes/module-fallback
Zur Laufzeit wird module-config.json nicht direkt vom Frontend-Controller gelesen, sondern über das Composer-Paket hyva-themes/module-fallback. Dieses Paket registriert einen Renderer-Selektor, der bei jeder Block-Auflösung prüft, welches Modul für den aktuellen Layout-Handle zuständig ist, und dann in der zusammengeführten module-config.json nachschlägt, ob hyva-compatible auf true steht. Ist das der Fall, greifen die regulären Hyvä-Templates aus dem aktiven Theme. Ist hyva-compatible auf false gesetzt, wechselt der Renderer auf das in fallback-theme hinterlegte Theme, meist Magento/blank, und liefert dort die klassischen Templates aus, allerdings ohne die Luma-spezifischen Assets vollständig zu laden.
Die Modul-Erkennung selbst basiert auf der Magento-Modulliste aus app/etc/config.php in Kombination mit den Layout-Handles, die ein Block auslöst. module-config.json liefert dabei ausschließlich die Entscheidungsgrundlage, nicht die Rendering-Logik selbst. Genau diese Trennung macht module-config.json austauschbar und testbar: Ein Modul kann ohne Codeänderung von Fallback auf nativ umgeschaltet werden, sobald ein Hyvä-Compatibility-Modul für dieses Drittanbieter-Paket existiert. Das ist der eigentliche Effizienzgewinn gegenüber hart verdrahteten Bedingungen im Template.
4. Eigene Einträge hinzufügen: Schritt für Schritt
Für ein noch nicht Hyvä-kompatibles Drittanbieter-Modul folgt das Vorgehen einem festen Muster. Zuerst wird geprüft, ob bereits ein Hyvä-Compatibility-Modul für das Paket existiert, meist über Composer suchbar. Existiert keines, wird ein eigener Eintrag in der theme-eigenen module-config.json angelegt, der das Modul explizit auf hyva-compatible: false setzt und ein fallback-theme definiert. Anschließend wird geprüft, ob das Fallback-Theme selbst installiert ist, da Magento/blank standardmäßig im Vendor-Verzeichnis vorhanden ist, ein individuelles Fallback-Theme aber gegebenenfalls per Composer nachgezogen werden muss.
Im dritten Schritt wird die priority so gesetzt, dass sie mit bestehenden Einträgen nicht kollidiert, insbesondere wenn mehrere Compatibility-Pakete dasselbe Modul referenzieren. Abschließend wird der Cache invalidiert und die Seite im Frontend geprüft. Das folgende Beispiel zeigt einen konkreten Eintrag für ein fiktives Bewertungs-Modul eines Drittanbieters, das noch keine Hyvä-Templates mitbringt, zusammen mit dem zugehörigen Composer-Befehl.
{
"// composer require": "composer require hyva-themes/magento2-magefan-blog-compatibility:^1.3",
"Fooman_ReviewBooster": {
"hyva-compatible": false,
"fallback-theme": "Magento/blank",
"priority": 30,
"requires": ["Magento_Review", "Magento_Catalog"]
}
}
5. Zusammenspiel mit Layout-XML und ViewModel
Der Fallback-Status aus module-config.json wirkt nicht nur auf die reine Template-Auswahl, sondern lässt sich gezielt in Layout-XML und ViewModel abfragen, um Blöcke bedingt zu rendern. Ein typisches Muster: Ein ViewModel liest den Fallback-Status eines Moduls aus module-config.json aus und stellt eine einfache Boolean-Methode bereit, etwa isHyvaCompatible(string $moduleName). Im Layout-XML wird der Block dann nur eingebunden, wenn dieser ViewModel-Wert im Template geprüft wird, wodurch verhindert wird, dass ein Fallback-Block zusätzlich eine Hyvä-spezifische Komponente ausliefert, die im Blank-Rendering-Pfad gar nicht existiert.
Diese Kombination aus module-config.json, Layout-XML und ViewModel ist besonders bei zusammengesetzten Seiten relevant, etwa Produktseiten, auf denen ein Kernblock nativ in Hyvä läuft, ein Drittanbieter-Block aber noch im Fallback-Modus verbleibt. Das folgende Layout-XML-Fragment zeigt, wie ein Block über einen ViewModel-Alias an den Fallback-Status von module-config.json gekoppelt wird, ohne dass im Container selbst Bedingungslogik verdrahtet werden muss.
<!-- catalog_product_view.xml - conditional block wiring based on module-config.json fallback status -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template"
name="review.booster.compat"
template="Fooman_ReviewBooster::review-booster.phtml">
<arguments>
<!-- ViewModel reads the merged module-config.json at render time -->
<argument name="module_config_view_model" xsi:type="object">
Mironsoft\HyvaCompat\ViewModel\ModuleFallback
</argument>
</arguments>
</block>
</referenceContainer>
</body>
</page>
6. Priorität und Merge-Verhalten über Theme-Vererbung
Hyvä-Themes erben typischerweise von einem Parent-Theme, etwa hyva-themes/magento2-default-theme-csp, und jedes Theme in dieser Kette kann eine eigene module-config.json mitbringen. Zur Laufzeit werden alle module-config.json-Dateien entlang der Theme-Vererbung zusammengeführt, wobei ein Eintrag im Child-Theme einen gleichnamigen Eintrag im Parent-Theme überschreibt. Die priority entscheidet zusätzlich, welcher Eintrag gewinnt, wenn mehrere Compatibility-Pakete unabhängig voneinander denselben Modulnamen registrieren, etwa weil zwei verschiedene Hyvä-Compatibility-Erweiterungen dasselbe Drittanbieter-Modul abdecken.
Für die eigene Theme-Entwicklung bedeutet das: Ein Child-Theme sollte nur die module-config.json-Einträge überschreiben, die tatsächlich abweichen, und den Rest der Vererbung überlassen. Ein Helper oder ViewModel, der den gemergten Zustand programmatisch auswertet, macht diese Vererbungslogik im Code sichtbar und testbar, statt sich auf implizites Verhalten zu verlassen. Die folgende PHP-Klasse liest die zusammengeführte module-config.json über das Hyvä-Compatibility-Paket aus und stellt das Ergebnis typisiert für Templates bereit.
<?php
declare(strict_types=1);
namespace Mironsoft\HyvaCompat\ViewModel;
use Magento\Framework\View\Element\Block\ArgumentInterface;
use Magento\Framework\Component\ComponentRegistrarInterface;
use Magento\Framework\Component\ComponentRegistrar;
use Magento\Framework\Filesystem\Driver\File;
/**
* ViewModel that reads the merged module-config.json across the active theme
* inheritance chain and exposes the fallback status per module to templates.
*/
final class ModuleFallback implements ArgumentInterface
{
/** @var array<string, array{hyva-compatible: bool, fallback-theme: ?string, priority: int, requires: string[]}> */
private array $mergedConfig = [];
/**
* @param ComponentRegistrarInterface $componentRegistrar Resolves theme paths for module-config.json lookups.
* @param File $fileDriver Filesystem driver used to read raw JSON files.
* @param string[] $themePaths Ordered list of theme directories, parent first, child last.
*/
public function __construct(
private readonly ComponentRegistrarInterface $componentRegistrar,
private readonly File $fileDriver,
private readonly array $themePaths,
) {
}
/**
* Checks whether a given Magento module has a native Hyva-compatible entry
* after merging module-config.json across all inherited themes.
*
* @param string $moduleName Fully qualified module name, e.g. "Vendor_Module".
* @return bool True if the merged entry marks the module as hyva-compatible.
*/
public function isHyvaCompatible(string $moduleName): bool
{
$config = $this->getMergedConfig();
return (bool) ($config[$moduleName]['hyva-compatible'] ?? false);
}
/**
* Returns the fallback theme configured for a module, or null if none applies.
*
* @param string $moduleName Fully qualified module name, e.g. "Vendor_Module".
* @return string|null Fallback theme path, e.g. "Magento/blank".
*/
public function getFallbackTheme(string $moduleName): ?string
{
$config = $this->getMergedConfig();
return $config[$moduleName]['fallback-theme'] ?? null;
}
/**
* Builds the merged module-config.json by reading each theme in the
* inheritance chain and letting later (child) entries win on conflicts.
*
* @return array<string, array{hyva-compatible: bool, fallback-theme: ?string, priority: int, requires: string[]}>
*/
private function getMergedConfig(): array
{
if ($this->mergedConfig !== []) {
return $this->mergedConfig;
}
$merged = [];
foreach ($this->themePaths as $themePath) {
$file = $themePath . '/etc/module-config.json';
if (!$this->fileDriver->isExists($file)) {
continue;
}
/** @var array<string, array{hyva-compatible: bool, fallback-theme: ?string, priority: int, requires: string[]}> $decoded */
$decoded = json_decode($this->fileDriver->fileGetContents($file), true) ?? [];
$merged = array_replace($merged, $decoded);
}
return $this->mergedConfig = $merged;
}
}
Ein wichtiger Nebeneffekt dieses Merge-Verhaltens: Wird ein Eintrag in einem Child-Theme versehentlich mit einer niedrigeren priority als im Parent-Theme angelegt, kann das dazu führen, dass module-config.json den Parent-Eintrag bevorzugt, obwohl der Child-Eintrag inhaltlich aktueller ist. Deshalb sollte priority immer bewusst und konsistent über die gesamte Theme-Kette vergeben werden, nicht zufällig pro Modul.
7. Typische Fehler
Der häufigste Fehler im Umgang mit module-config.json ist die vergessene Cache-Invalidierung nach einer Änderung. Da die zusammengeführte Konfiguration von Hyvä intern gecacht wird, führt eine reine Dateiänderung ohne bin/magento cache:flush dazu, dass die alte Fallback-Entscheidung weiter aktiv bleibt, obwohl die Datei bereits korrekt aussieht. Ein zweiter klassischer Fehler ist die falsche Schreibweise des Modulnamens: vendor_module in Kleinschreibung oder mit Bindestrich statt Unterstrich wird von module-config.json nicht erkannt, weil der Reader exakt den Magento-internen Modulnamen erwartet, wie er in app/etc/config.php registriert ist.
Ein dritter Fehlerbereich sind Prioritätskonflikte, wenn mehrere Compatibility-Pakete denselben Modulnamen mit unterschiedlicher priority registrieren. Ohne bewusste Priorisierung entscheidet die Ladereihenfolge der Composer-Pakete, welcher Eintrag in module-config.json am Ende gewinnt, was zu inkonsistentem Verhalten zwischen Entwicklungs- und Produktionsumgebung führen kann, wenn die Composer-Lock-Datei nicht identisch ist. Auch ein fehlendes oder falsch geschriebenes fallback-theme, etwa ein Tippfehler in Magento/blank, führt zu einem stillen Fehler: Hyvä fällt dann nicht auf das erwartete Theme zurück, sondern liefert im schlimmsten Fall eine leere Seite.
8. Best Practices
Für eine wartbare module-config.json empfiehlt sich eine konsequente Naming-Konvention: Modulnamen exakt wie in app/etc/config.php übernehmen, niemals abkürzen oder umschreiben. Jede Änderung an module-config.json gehört unter Versionskontrolle, idealerweise mit einer klaren Commit-Message, die das betroffene Drittanbieter-Modul benennt, damit spätere Priorisierungskonflikte im Git-Log nachvollziehbar bleiben. Nach jeder Änderung sollte ein vollständiger Cache-Flush und, bei Layout- oder ViewModel-Änderungen, ein erneutes Static-Content-Deployment erfolgen, bevor das Ergebnis im Frontend geprüft wird.
Ebenso wichtig ist ein manueller Funktionstest der betroffenen Seite nach jeder Änderung an module-config.json, da ein falsch gesetztes hyva-compatible nicht immer zu einem sichtbaren Fehler, sondern manchmal nur zu einem stillen Performance-Verlust durch doppelt geladene Assets führt. Die folgende Befehlsfolge zeigt die empfohlene Deploy-Sequenz nach einer Änderung an module-config.json.
#!/usr/bin/env bash
# Deploy sequence after editing module-config.json
set -euo pipefail
# 1. Rebuild Tailwind CSS if templates changed alongside module-config.json
bin/npm --prefix app/design/frontend/Mironsoft/default/web/tailwind run build
# 2. Remove stale preprocessed views and static assets (always first!)
cd src && rm -rf var/view_preprocessed/* pub/static/frontend/*
# 3. Redeploy static content for the affected theme
bin/magento setup:static-content:deploy de_DE -t Mironsoft/default -f
# 4. Flush the cache so the merged module-config.json is re-read
bin/magento cache:flush
# 5. Manually verify the affected module's frontend page
bin/magento cache:status
9. module-config.json im Vergleich
Ob module-config.json sauber gepflegt wird oder nicht, wirkt sich direkt auf Wartungsaufwand, Kompatibilität, Debugging-Zeit und Performance eines Hyvä-Projekts aus. Die folgende Tabelle stellt beide Szenarien gegenüber.
| Aspekt | Ohne gepflegte module-config.json | Mit sauber gepflegter module-config.json |
|---|---|---|
| Wartungsaufwand | Theme-Fork pro Drittanbieter-Modul, hoher manueller Aufwand | Ein deklarativer Eintrag pro Modul, zentral versioniert |
| Kompatibilität | Ungestylte Luma-Fragmente im Hyvä-Frontend möglich | Kontrollierter Fallback auf Magento/blank ohne Bruch |
| Debugging | Unklar, ob Modul nativ oder im Fallback rendert | Status pro Modul direkt aus der Datei ablesbar |
| Performance | Doppelt geladene Assets durch fehlerhafte Fallback-Erkennung | Nur benötigte Assets je nach Fallback-Status |
| Theme-Vererbung | Prioritätskonflikte zwischen Parent- und Child-Theme unklar | Merge-Verhalten dokumentiert und testbar über ViewModel |
In der Praxis zeigt sich: Projekte mit einer sauber gepflegten module-config.json benötigen deutlich weniger manuelle Nacharbeit bei Magento-Minor-Updates, weil neue Drittanbieter-Module direkt über einen zusätzlichen Eintrag statt über einen erneuten Theme-Fork eingebunden werden können.
10. Zusammenfassung
module-config.json ist Hyvä's zentrale Steuerungsdatei für den Compatibility Layer: Sie entscheidet pro Modul, ob native Hyvä-Templates oder ein Fallback-Theme wie Magento/blank greift, statt dass jedes Drittanbieter-Modul einen eigenen Theme-Fork erzwingt. Das Schema mit hyva-compatible, fallback-theme, priority und requires ist bewusst schlank gehalten und wird vom Composer-Paket hyva-themes/module-fallback zur Laufzeit ausgewertet. Eigene Einträge lassen sich schnell ergänzen, sobald ein Drittanbieter-Modul noch keine native Hyvä-Unterstützung mitbringt.
Über Layout-XML und ViewModel lässt sich der Fallback-Status aus module-config.json gezielt in bedingtes Block-Rendering übersetzen. Bei Theme-Vererbung werden alle module-config.json-Dateien der Kette zusammengeführt, wobei Child-Einträge gewinnen und priority Konflikte zwischen mehreren Compatibility-Paketen auflöst. Wer nach jeder Änderung konsequent Cache-Flush und Static-Content-Deployment durchführt und Modulnamen exakt schreibt, vermeidet die häufigsten Fehlerquellen rund um module-config.json.
module-config.json in Hyvä Themes, das Wichtigste auf einen Blick
Zweck
Kompatibilitäts-Registry pro Modul statt Theme-Fork. Entscheidet zwischen nativen Hyvä-Templates und Fallback-Theme.
Schema
hyva-compatible, fallback-theme, priority, requires pro Modulschlüssel.
Laufzeit
Ausgewertet durch hyva-themes/module-fallback bei jeder Block-Auflösung, unabhängig vom Template-Code.
Vererbung
Parent- und Child-Theme werden zusammengeführt, Child-Einträge und priority entscheiden bei Konflikten.
11. FAQ: hyva-themes/module-config.json erklärt
1Was ist module-config.json in Hyvä Themes?
2Wo genau liegt die module-config.json-Datei?
3Was bewirkt das Feld hyva-compatible?
4Welches Fallback-Theme wird typischerweise verwendet?
5Wie wird module-config.json zur Laufzeit ausgewertet?
6Wie füge ich einen eigenen Eintrag hinzu?
7Was passiert bei Theme-Vererbung mit mehreren Dateien?
8Warum greift meine Änderung nicht?
9Kann ich module-config.json in Layout-XML oder ViewModel auswerten?
10Häufigster Fehler bei der Modulnamen-Schreibweise?
Mironsoft
Hyvä-Theme-Entwicklung, Compatibility-Layer und Magento-2-Frontend-Architektur
Drittanbieter-Module sauber in Hyvä integrieren?
Wir pflegen module-config.json-Einträge, bauen native Hyvä-Templates für eure Luma-Module und sorgen für ein sauberes, getestetes Compatibility-Setup ohne Theme-Forks.
Compatibility-Audit
Bestehende module-config.json-Einträge prüfen und Prioritätskonflikte auflösen
Native Portierung
Luma-Module auf native Hyvä-Templates umstellen, statt dauerhaft im Fallback zu bleiben
CI-Integration
Deploy-Sequenzen für Cache-Flush und Static-Content-Deployment automatisieren