enhancement
major
minor
major
minor
major
#29576
React-Controls-Bundle enthält eine zweite React-Instanz (createPortal-Import in TLDropdownSelect)
Problem
com.top_logic.layout.react/react-src/controls/TLDropdownSelect.tsx importiert createPortal direkt aus react-dom:
import { React, useTLState, useTLCommand, useI18N } from 'tl-react-bridge'; // korrekt
import { createPortal } from 'react-dom'; // Verstoß
vite.config.controls.ts externalisiert ausschließlich tl-react-bridge, nicht react/`react-dom`. Über die Abhängigkeitskette zieht dieser eine Import daher **React und react-dom vollständig in das Controls-Bundle**.
Nachgewiesen im eingecheckten Artefakt com.top_logic.layout.react/src/main/webapp/script/tl-react-controls.js:
| Zeile | Inhalt |
| 2227 | Banner react.production.js — vollständige zweite React-Instanz |
| 2599 | Banner react-dom.production.js |
| 2655 | __DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE |
Anteil: 14.608 Bytes = 9,0 % des 161.526-Byte-Bundles.
Das ist exakt der Fehlermodus, vor dem CLAUDE.md und der Kommentarblock in bridge-entry.ts warnen („A second React copy breaks all hooks at runtime — useState is null").
Ursache
bridge-entry.ts re-exportiert createPortal nicht. Es gab keine regelkonforme Alternative — die Komponente musste den direkten Import nehmen. TLDropdownSelect ist das einzige Control, das Portale verwendet.
Lösung
- createPortal und flushSync in react-src/bridge-entry.ts re-exportieren.
- TLDropdownSelect.tsx auf den Bridge-Import umstellen.
Änderungsumfang: 2 Dateien, +8/−2 Zeilen.
Verifikation (bereits durchgeführt)
mvn compile -pl com.top_logic.layout.react erfolgreich. Danach:
| vorher | nachher | Delta | |
| Controls-Bundle | 161.526 B | 144.826 B | **−16.700 B (−10,3 %)** |
| react.production.js | 1× | 0× | eliminiert |
| react-dom.production.js | 1× | 0× | eliminiert |
| __DOM_INTERNALS_DO_NOT_USE | 1× | 0× | eliminiert |
Bridge-Bundle wächst um 88 Bytes (die beiden Re-Exports).
Noch offen: Laufzeitverifikation des Dropdown-Portals in der Demo-App.
Nachhaltigkeit
Gefunden wurde der Fehler durch eine oxlint-Regel tl/no-react-import (30 Zeilen, 125 ms für 96 Dateien). Die Regel steht seit Jahren dreimal als Prosa in CLAUDE.md und wurde nie durchgesetzt. Vorschlag: Regel im Rahmen des Design-System-Vorhabens scharf schalten, mit Ausnahmepfad für react-src/bridge/**, bridge-entry.ts und die Shim-Dateien der Satellitenmodule.