Full-Stack-Debugging: PHP und Node.js gleichzeitig in PhpStorm debuggen
AI generated
IDE
{ }
PhpStorm · PHP · Docker
PHP und Node.js gleichzeitig debuggen
Eine Session fuer Backend-Logik und Build-Pipeline

Bei Hyva-Theme-Projekten liegt der Fehler oft nicht klar auf einer Seite: Ist die Tailwind-Klasse falsch generiert oder wird sie vom Watcher gar nicht erst erkannt? PhpStorm kann Xdebug-Sitzung und Node-Prozess in einer einzigen Compound-Konfiguration buendeln, sodass beide Seiten synchron pausieren.

13 Min. Lesezeit Xdebug Node Inspector Compound Configs

1. Warum getrenntes Debugging bei Hyva-Projekten an seine Grenzen stoesst

Ein typisches Hyva-Setup besteht aus zwei parallel laufenden Prozessen: dem Magento-PHP-Backend, das ViewModels und phtml-Templates rendert, und einem Node-basierten Tailwind-Watcher, der bei jeder Aenderung die CSS-Klassen neu generiert. Taucht ein Layout-Fehler auf, ist oft unklar, welcher der beiden Prozesse verantwortlich ist: Erzeugt die PHP-Seite eine falsche Klasse, oder erkennt der Tailwind-Scanner das Pattern gar nicht erst und purged die Klasse weg.

Wer beide Seiten getrennt debuggt, wechselt staendig zwischen zwei Xdebug-Sessions und einer separaten Node-Inspector-Verbindung im Chrome DevTools Fenster. Der zeitliche Zusammenhang zwischen PHP-Ausgabe und Node-Verarbeitung geht dabei verloren, weil man nie beide Haltepunkte im gleichen Moment beobachten kann. Genau hier setzt eine gemeinsame Debug-Session in PhpStorm an, die beide Welten in einem Fenster zusammenfuehrt. Gerade bei Teams, die neu in ein bestehendes Hyva-Projekt einsteigen, spart dieser Ansatz erhebliche Einarbeitungszeit, weil der Zusammenhang zwischen Backend und Build-Pipeline direkt sichtbar wird, statt muehsam aus zwei getrennten Werkzeugen rekonstruiert werden zu muessen.

2. Das Grundprinzip: Compound-Konfigurationen buendeln Sessions

PhpStorm kennt neben einzelnen Run/Debug-Konfigurationen den Typ Compound. Eine Compound-Konfiguration startet mehrere hinterlegte Konfigurationen mit einem einzigen Klick und haelt sie waehrend der gesamten Sitzung aktiv. Fuer unseren Fall werden zwei Kind-Konfigurationen kombiniert: eine PHP Remote Debug Konfiguration fuer den Docker-Container und eine Attach to Node.js/Chrome Konfiguration fuer den laufenden Watcher-Prozess.

Jede Kind-Konfiguration behaelt ihre eigenen Breakpoints, Watches und Variablenansichten, wird aber im selben Debug-Tool-Fenster als eigener Tab angezeigt. Pausiert eine Seite an einem Breakpoint, laeuft die andere unbeeintraechtigt weiter, bis sie selbst auf einen Haltepunkt trifft. Dadurch entsteht eine gemeinsame Zeitleiste, ohne dass man Fenster wechseln oder Tools synchronisieren muss. Ein weiterer Vorteil zeigt sich beim Team-Onboarding: Die Compound-Konfiguration laesst sich als Projektdatei versionieren und mit ins Repository aufnehmen, sodass neue Kolleginnen und Kollegen dieselbe Debug-Umgebung mit einem Klick uebernehmen koennen, ohne jede Einzelkonfiguration selbst nachzubauen.


<!-- .idea/runConfigurations/Compound_PHP_Node.xml -->
<component name="ProjectRunConfigurationManager">
  <configuration name="PHP + Node Watcher" type="CompoundRunConfigurationType">
    <toRun name="Listen for PHP Debug Connections" type="PHP Remote Debug" />
    <toRun name="Attach Tailwind Watcher" type="NodeJSRemoteDebugRunConfigurationType" />
    <method v="2" />
  </configuration>
</component>

3. Xdebug-Startpunkt im Docker-Container korrekt setzen

Damit PhpStorm ueberhaupt Breakpoints im PHP-Code treffen kann, muss Xdebug im Container aktiv sein und der richtige client_host konfiguriert werden. Im Mark-Shust-Setup aktiviert man Xdebug ueber den Wrapper bin/xdebug enable, der die passende ini-Datei einbindet und den Container neu startet. Wichtig ist die Path-Mapping-Konfiguration in PhpStorm, damit der Container-Pfad /var/www/html/app/code korrekt auf das lokale src/app/code Verzeichnis abgebildet wird.

Ein haeufiger Stolperstein ist ein falsch gesetzter xdebug.client_host, wenn der Container in einem eigenen Docker-Netzwerk laeuft. Auf Linux funktioniert meist die Docker-Bridge-IP, auf macOS und Windows ist host.docker.internal die zuverlaessigere Wahl. Ohne korrektes Mapping verbindet sich Xdebug zwar, aber PhpStorm zeigt die Breakpoints als nicht erreichbar an, was oft faelschlich als Xdebug-Fehler statt als Netzwerkproblem interpretiert wird. Ein schneller Test besteht darin, den Xdebug-Log-Modus temporaer auf einen hoeheren Detailgrad zu stellen und im Container-Log nachzuvollziehen, ob ueberhaupt ein Verbindungsversuch beim konfigurierten Host ankommt, bevor man an der PhpStorm-Konfiguration selbst weitersucht.


; docker/php/xdebug.ini
zend_extension=xdebug.so
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=host.docker.internal
xdebug.client_port=9003
xdebug.idekey=PHPSTORM

4. Node-Prozess des Watchers mit Inspector-Flag starten

Der Tailwind-Watcher laeuft normalerweise ueber ein npm-Skript, das den Build-Prozess im Watch-Modus haelt. Damit PhpStorm sich per Attach to Node.js/Chrome anhaengen kann, braucht der Node-Prozess das Flag --inspect oder --inspect-brk, das einen Debug-Port oeffnet. In einem docker-npm-Setup wird dieses Flag direkt im package.json-Skript hinterlegt, damit es bei jedem Start automatisch aktiv ist.

Laeuft der Node-Prozess ebenfalls im Container, gilt dieselbe Netzwerk-Ueberlegung wie bei Xdebug: Der Inspector-Port muss aus dem Container heraus exponiert und in PhpStorm unter der Node.js-Remote-Konfiguration mit der richtigen Host-Adresse hinterlegt werden. Ein haeufiger Fehler ist, den Port nur intern zu binden, sodass PhpStorm von aussen keine Verbindung aufbauen kann, obwohl der Prozess selbst fehlerfrei startet. In der docker-compose.yml des Projekts muss der gewaehlte Inspector-Port zusaetzlich explizit als Port-Mapping eingetragen werden, sonst bleibt er selbst bei korrekter Bindung innerhalb des Containers von aussen unerreichbar.


{
  "scripts": {
    "watch:tailwind": "node --inspect=0.0.0.0:9229 ./node_modules/.bin/tailwindcss -i ./web/tailwind/tailwind-source.css -o ./web/css/styles.css --watch"
  }
}

5. Compound-Konfiguration in der PhpStorm-Oberflaeche anlegen

In der Praxis geht man ueber Run, Edit Configurations und legt zunaechst die beiden Einzelkonfigurationen an: eine PHP Remote Debug fuer den Docker-Server und eine Attach to Node.js/Chrome mit Host und Port des Inspector-Sockets. Erst danach erstellt man ueber das Plus-Symbol eine neue Compound-Konfiguration und waehlt beide vorhandenen Eintraege als Kinder aus.

Ein sprechender Name wie PHP + Node Watcher und ein zugewiesenes Tastaturkuerzel machen die Konfiguration im Alltag praktikabel. Wichtig zu wissen: Beendet man die Compound-Session ueber den Stop-Button, werden beide Kind-Sessions sauber getrennt, der Docker-Container selbst laeuft aber unbeeinflusst weiter, sodass kein erneuter Neustart der Umgebung noetig ist.

6. Breakpoints ueber Sprachgrenzen hinweg koordinieren

Der eigentliche Mehrwert zeigt sich, wenn man in der ViewModel-Klasse einen PHP-Breakpoint setzt, der eine dynamische Klassenliste zusammenbaut, und gleichzeitig im Node-Watcher einen Breakpoint in der Transformationsfunktion, die die CSS-Ausgabe schreibt. Beim Laden der Seite greift zuerst der PHP-Breakpoint, weil das Rendering vor jedem CSS-Rebuild passiert.

Erst wenn man eine Template-Datei speichert, die der Tailwind-Scanner beobachtet, greift der Node-Breakpoint erneut. Wer diese Reihenfolge kennt, vermeidet falsche Schluesse, etwa die Annahme, eine Klasse fehle im CSS, obwohl sie schlicht noch nicht neu gebaut wurde, weil der Watcher den betroffenen Dateipfad gar nicht ueberwacht.


// app/code/Mironsoft/Theme/ViewModel/HeroBanner.php
public function getWrapperClasses(): string
{
    $classes = ['flex', 'items-center'];
    if ($this->isFullWidth()) {
        $classes[] = 'w-full'; // <- Breakpoint hier setzen
    }
    return implode(' ', $classes);
}

7. Praxisbeispiel: Verschwundene Tailwind-Klasse aufspueren

Ein konkreter Fall aus der Praxis: Eine bedingte Klasse wird per String-Konkatenation im phtml-Template gebaut, zum Beispiel 'bg-' . $color . '-500'. Der Tailwind-JIT-Scanner kann dieses Muster nicht statisch erkennen, weil er nur vollstaendige Klassennamen im Quelltext findet, keine zur Laufzeit zusammengesetzten Strings. Die Debug-Session zeigt im PHP-Teil, dass der korrekte Klassenname erzeugt wird. Ohne die kombinierte Session waere man vermutlich zunaechst davon ausgegangen, der Fehler liege im PHP-Code selbst, und haette wertvolle Zeit mit der Fehlersuche an der falschen Stelle verbracht.

Im Node-Teil bestaetigt ein Log-Statement im Watcher, dass die Klasse im finalen CSS fehlt, weil sie beim Scan-Vorgang nie als vollstaendiger String auftaucht. Die Loesung besteht darin, alle moeglichen Klassenkombinationen entweder explizit auszuschreiben oder sie in die Safelist der Tailwind-Konfiguration aufzunehmen, damit der Purge-Vorgang sie nicht entfernt.


// tailwind.config.js
module.exports = {
  content: ['../**/*.phtml'],
  safelist: [
    'bg-red-500', 'bg-green-500', 'bg-blue-500',
  ],
};

8. Performance-Fallstricke bei parallelem Debugging

Zwei aktive Debug-Engines gegen einen Docker-Container erhoehen spuerbar die Latenz jeder Step-Aktion, besonders wenn viele Watch-Ausdruecke gleichzeitig ausgewertet werden. Jede Watch, die ein komplexes Objekt oder ein grosses Array beobachtet, wird bei jedem Breakpoint neu berechnet, was die Reaktionszeit der IDE merklich verlangsamt.

In der Praxis hilft es, Watches auf das Noetigste zu beschraenken und die maximale Anzahl angezeigter Array-Elemente in den Debugger-Einstellungen zu reduzieren. Auch die Option Force step into sollte global deaktiviert bleiben, da sie bei aktiver Compound-Session sonst versucht, in Framework- und node_modules-Code hineinzuspringen, was die Sitzung spuerbar traege macht. Wer regelmaessig mit grossen Produktdatenmengen arbeitet, sollte zusaetzlich die Anzeige von Objektreferenzen im PHP-Debugger auf eine geringere Tiefe begrenzen, da tief verschachtelte ViewModel-Objekte sonst bei jedem Halt vollstaendig aufgeloest werden und die Reaktionszeit weiter verschlechtern.

9. Wann sich der Aufwand nicht lohnt und welche Alternativen es gibt

Fuer einfache, klar lokalisierte Bugs ist eine einzelne Debug-Session weiterhin schneller aufgesetzt als eine Compound-Konfiguration. Der Mehraufwand lohnt sich vor allem bei schwer reproduzierbaren Problemen, die genau an der Schnittstelle zwischen serverseitigem Rendering und clientseitigem Build entstehen, etwa bei Timing-Problemen zwischen Cache-Invalidierung und Watcher-Trigger.

Als leichtgewichtige Alternative bieten sich korrelierte Log-Ausgaben an: Beide Prozesse schreiben Zeitstempel in ein gemeinsames Log-Format, sodass man den Ablauf nachtraeglich rekonstruieren kann, ohne live debuggen zu muessen. Fuer wiederkehrende Analysen ist das oft praktikabler als jedes Mal eine vollstaendige Compound-Session neu zu starten.

Ansatz Setup-Aufwand Staerke Grenze
Getrennte Sessions Gering Schnell fuer isolierte Bugs Kein zeitlicher Zusammenhang sichtbar
Compound-Konfiguration Mittel, einmalig Synchrone Zeitleiste beider Prozesse Hoeherer IDE-Overhead
Korrelierte Logs Gering, dauerhaft Nachtraegliche Analyse ohne Live-Session Kein interaktives Stepping
Manueller Fensterwechsel Keins Kein zusaetzliches Setup Zeitfenster leicht verpasst

Mironsoft

PhpStorm-Setup, Docker-Integration und Team-Produktivität

PhpStorm, das für Magento- und PHP-Projekte wirklich optimal läuft?

Wir prüfen bestehende PhpStorm-Setups auf langsame Indizierung, ungenutzte Docker-Integration und fehlende Team-Konventionen und richten eine Konfiguration ein, die von der ersten Sekunde an produktiv ist.

Setup-Review

Indexing, Interpreter und Speicher-Einstellungen für große Magento-Projekte optimieren.

Docker-Integration

Xdebug, PHPUnit und Datenbank-Tools sauber mit dem Docker-Setup verbinden.

Team-Konventionen

Inspection-Profile, Code-Style und Live-Templates projektweit vereinheitlichen.

10. Zusammenfassung

Full-Stack-Debugging in PhpStorm: Das Wichtigste auf einen Blick

Kernwerkzeug

Compound Run/Debug Configuration verbindet PHP Remote Debug und Attach to Node.js/Chrome.

Voraussetzung

Xdebug mit korrektem client_host und Node-Prozess mit --inspect-Flag.

Typischer Fall

Bugs an der Schnittstelle zwischen PHP-Rendering und Tailwind-Watcher-Build.

Grenze

Fuer einfache Bugs bleibt eine einzelne Session schneller aufgesetzt.

11. FAQ: Full-Stack-Debugging in PhpStorm: Das Wichtigste auf einen Blick

1Was ist eine Compound Run Configuration in PhpStorm?
Ein Konfigurationstyp, der mehrere bestehende Run- oder Debug-Konfigurationen mit einem einzigen Start-Klick gemeinsam ausfuehrt und im selben Debug-Fenster als separate Tabs anzeigt.
2Muss der Node-Prozess im selben Container laufen wie PHP?
Nein, er kann in einem eigenen Container oder direkt auf dem Host laufen. Wichtig ist nur, dass der Inspector-Port von PhpStorm aus erreichbar ist.
3Welches Flag braucht Node.js fuer den Inspector-Zugriff?
Das Flag --inspect oeffnet einen Debug-Port, --inspect-brk pausiert den Prozess zusaetzlich sofort beim Start, bis sich ein Debugger verbindet.
4Warum werden meine PHP-Breakpoints als nicht erreichbar angezeigt?
Meist liegt es an einem falschen xdebug.client_host oder an einem fehlerhaften Path-Mapping zwischen Container-Pfad und lokalem Projektverzeichnis.
5Kann man mehr als zwei Konfigurationen in einer Compound-Session buendeln?
Ja, eine Compound-Konfiguration kann beliebig viele Kind-Konfigurationen enthalten, etwa zusaetzlich einen Datenbank-Konsolen-Start oder einen weiteren Node-Prozess.
6Wirkt sich die Compound-Session auf die Performance des Docker-Containers aus?
Der Container selbst wird kaum belastet, die spuerbare Verlangsamung entsteht meist in der IDE durch viele gleichzeitig ausgewertete Watch-Ausdruecke.
7Wie findet man den richtigen Inspector-Port fuer einen laufenden Node-Prozess?
Der Port wird beim Start im Terminal-Log ausgegeben, Standardwert ist 9229, sofern er nicht explizit ueber das --inspect-Flag geaendert wurde.
8Ist Full-Stack-Debugging auch ohne Docker sinnvoll?
Ja, das Prinzip funktioniert genauso bei lokal installiertem PHP und Node, die Netzwerkkonfiguration ist dabei sogar einfacher, weil kein Container-Mapping noetig ist.
9Was passiert, wenn nur eine der beiden Kind-Konfigurationen startet?
PhpStorm zeigt im Debug-Fenster nur den erfolgreichen Tab an und meldet einen Verbindungsfehler fuer die andere Konfiguration, die Session laeuft aber teilweise weiter.
10Lohnt sich dieser Aufwand fuer kleine Projekte?
Bei kleinen Projekten mit seltenen Cross-Layer-Bugs meist nicht, dort reicht getrenntes Debuggen. Bei komplexen Hyva-Themes mit vielen dynamischen Klassen zahlt sich der einmalige Setup-Aufwand aus.