Repository navigation
VisualEditor de
🌐 Diese Seite auf: English · Português · Español · Français · Deutsch
Eine Erstanbieter-Erweiterung für VS Code, die das SDK in eine visuelle Entwicklungsumgebung verwandelt: ein Bildschirm rendert neben der Datei, die ihn erzeugt, aus dem Puffer, in dem du tippst, jedes gerenderte Element weiß, welcher C#-Ausdruck es gebaut hat, und eines auszuwählen zeigt, und bearbeitet, diesen Ausdruck.
Die Vorschau ist der echte Web-Realisierer, der das echte kompilierte Modul ausführt. Sie ist keine Nachahmung, und genau darum geht es: eine Vorschau, die rendert, ist der Beweis, dass die Seite rendert. Nichts Neues zeichnet Pixel.
Stand. Die Vorschau, der Identitätsmechanismus, die Auswahl, der Eigenschafteninspektor und die strukturellen Gesten (einfügen, verschieben, duplizieren, entfernen und zwischen Containern ziehen) sind vorhanden und abgedeckt, von Unit-Tests gegen eine echte Projektkompilierung und von einer Integrationssuite, die in einem echten VS Code läuft. Es verpackt sich in ein installierbares
.vsix; im Marketplace ist es noch nicht. Spur E in der Roadmap hat die Meilensteine.
Seit 0.2.0-preview.30
eqdesign ist ein langlebiger Prozess, der die Roslyn-Kompilierung des Projekts hält und den
Puffer des Editors kompiliert, nicht die Datei auf der Platte. Dieser Unterschied ist der ganze
Grund, warum es ihn gibt: eqc liest Dateien und der Hot-Reload-Dienst beobachtet das Dateisystem,
also kann keiner von beiden dir den Text zeigen, den du gerade ansiehst, nur den Text, den du zuletzt
gespeichert hast.
Er spricht zeilenweise getrenntes JSON über stdio. Kein Port zu wählen, nichts zu autorisieren, nichts, das lauschend zurückbleibt, wenn das Fenster stirbt, und es funktioniert unverändert über Remote-SSH, weil der Erweiterungs-Host ohnehin auf der entfernten Maschine läuft.
Gemessen an samples/DefaultUIDashboard (16 Quelldateien, 316 Referenzen):
| Schritt | Zeit |
|---|---|
| Die Kompilierung bauen, einmal beim Aktivieren | 271 ms |
Eine Bearbeitung kompilieren (662-zeilige PaymentsPage, warm) |
p50 293 ms |
| Nur Diagnosen (binden, nicht transpilieren) | 36 ms |
Daher zwei Takte: Fehler werden nach einer Pause von 150 ms im Tippen erneut geprüft, die Vorschau kompiliert nach 400 ms neu. Ein C#-Fehler hält die Kompilierung an, bevor irgendetwas ausgegeben wird, Roslyn parst nachsichtig, also ergibt eine fehlende Klammer immer noch einen Baum, den der Transpiler durchlaufen würde, und erzeugt ein Modul, das montiert und wirft, was auf dem Bildschirm als leeres Bild ohne jede Erklärung ankommt.
Der Host weigert sich zu starten, wenn die Referenzliste leer ist, statt gegen ein unvollständiges Modell zu kompilieren. Dieser Fehlschlag ist sonst unsichtbar: ohne das semantische Modell werden benannte Argumente in syntaktischer Reihenfolge ausgegeben, und der Bildschirm rendert mit seinen Werten in den falschen Plätzen und nirgends einem Fehler.
Ein Bildschirm ist selten eine Datei. Eine Shell, eine Zeile, eine Datenhilfe, also schickt die Erweiterung jeden C#-Puffer, den der Editor gerade hält, nicht nur den aktiven, und der Host legt sie alle über die Kompilierung, bevor er kompiliert. Sonst würde die Vorschau dir die letzte gespeicherte Version von allem zeigen, außer von der Datei, in der du gerade tippst.
Seit 0.2.0-preview.30
VisualNode trägt ein Origin, die Quellspanne des Ausdrucks, der ihn konstruiert hat, oder null,
was jeder ausgelieferte Build ist. Eine Kompilierung im Design-Modus füllt es aus:
var compiler = new ComponentCompiler { DesignMode = true };
// Jede Knotenkonstruktion wird umhüllt ausgegeben, damit der gebaute Knoten sich erinnert, woher er kam:
// $eq.origin(UI.text(…), "…/PaymentsPage.cs|28:12|28:73")Beide Realisierer tragen es als data-eq-origin ins DOM, angehängt an ihrer einzigen Weiche:
<div data-eq-origin="/src/Screens/PaymentsPage.cs|27:8|34:10">
<span data-eq-origin="/src/Screens/PaymentsPage.cs|28:12|28:73">Count: 0</span>
</div>Das Format ist path|startLine:startColumn|endLine:endColumn, nullbasiert, die eigenen Koordinaten
des Editors.
Warum keine Source Maps. Die naheliegende Antwort funktioniert nicht. Der ganze Build-Körper
wird in eine flache Zeichenkette verwandelt und über einen einzigen Aufruf ausgegeben, also ist die
feinste Position, die eine V3-Map benennen kann, der Anfang der Methode: ein ausgeliefertes Modul
hat eine Zeile mit 942 Zeichen. Ein Origin ist stattdessen exakt, und weil es eine einfache
Zeichenkette am abstrakten Knoten ist, erbt die native Spur (Photon) denselben Mechanismus an dem Tag,
an dem sie ihn will.
Nur Konstruktionen werden gestempelt, niemals Referenzen. Eine Variable dort zu stempeln, wo sie
bloß erwähnt wird, würde das Origin der Konstruktion mit der Spanne einer Verwendung überschreiben und
die falsche Zeile auswählen. Ein Knoten, der in einem foreach gebaut wird, trägt die Spanne des
einen Ausdrucks, der ihn baut, was dort ohnehin das Einzige Bearbeitbare ist.
Der Design-Modus ist standardmäßig aus und in einem SDK-Build nie an: die Hülle ist echter
ausgegebener Code, und ihn auszuliefern würde das Anliegen eines Design-Werkzeugs in das Bundle jedes
Nutzers legen. Ein Produktionsrender enthält überhaupt kein data-eq-origin, und der
SSR-Hydration-Fingerabdruck-Test nagelt das fest.
Seit 0.2.0-preview.30
Ein Origin sagt, woher ein Knoten kam. Es sagt nicht, ob dieser Ort bearbeitet werden kann, und die
beiden als eine Frage zu behandeln ist, wie ein visueller Editor eine Datei beschädigt. Eine Zeile,
die fünfhundertmal in einem foreach gebaut wird, hat eine Quellstelle und keine eigene Existenz; ein
Knoten, den eine Hilfsmethode zurückgibt, ist ganz woanders geschrieben. „Lösche diese Zeile“ ist für
beide falsch.
Also wird jeder ausgewählte Knoten klassifiziert, indem von der Position des Origins aus Roslyns Vorfahren abgegangen werden:
| Stufe | Wo er geschrieben ist | Was die Leinwand anbietet |
|---|---|---|
literal |
Unbedingt, im Build, von dem die Vorschau ist |
alles, einschließlich struktureller Bearbeitungen |
derived |
In einer Schleife, einer Bedingung oder einem Callback | auswählen, inspizieren, Eigenschaften bearbeiten |
foreign |
Ein anderes Mitglied, eine lokale Funktion oder eine andere Datei | auswählen, inspizieren und dorthin springen, wo er geschrieben ist |
Eine lokale Funktion zählt hier als eigenes Mitglied, denn ein dort gebauter Knoten ist einmal geschrieben und wird über einen Aufruf erreicht, genau wie bei einer Hilfsmethode.
Jede Ablehnung erklärt sich, bevor die Handlungsmöglichkeit gezeichnet wird, nie nachdem geklickt wurde:
In einer Schleife gebaut: jede Wiederholung kommt aus diesem einen Ausdruck, es gibt also keine einzelne Zeile, die zu verschieben oder zu löschen wäre.
Von
PaymentRow()gebaut, nicht vonBuild().
Der Unterschied, der in der Praxis zählt: Verstehen ist nicht eingezäunt, nur Schreiben. Der Editor öffnet Code, der schon existiert, und echter Code verteilt sich über Hilfsmethoden und Dateien. Auswählen, inspizieren und eine Eigenschaft bearbeiten funktionieren überall dort, wo der Knoten geschrieben wurde, auch in einer anderen Datei, und darum wird dem Host jeder offene Puffer geschickt. Strukturelles Einfügen ist das, was innerhalb der deklarativen Form bleibt.
Seit 0.2.0-preview.30
Ein Element auszuwählen öffnet ein angedocktes Panel, im eigenen Chrom des Editors, das auflistet, was die Komponente nimmt: den Typ jeder Eigenschaft, den Doc-Kommentar, der am Quellsymbol gelesen wird, und wie sie gerade geschrieben ist, als Argument, in einem Objektinitialisierer oder gar nicht.
Bearbeitungen werden als C#-Quelle zurückgeschrieben, weil die Datei C# ist. Ein Enum bietet seine
Mitglieder als Liste statt als Textfeld an; alles andere ist ein Wert, den du tippst, und 12,
"Save" und Variant.Secondary sind alle einfach Ausdrücke.
Drei Dinge halten das ehrlich:
- Es wird kompiliert, bevor es angeboten wird. Eine Kandidatenbearbeitung wird geparst und gebunden, und eine Ablehnung zitiert den Compiler: Das würde nicht kompilieren: CS0117 ….
-
Es geht über
WorkspaceEdit, nie über ein Schreiben in die Datei. Die Änderung landet im eigenen Rückgängig-Stapel des Dokuments, also dreht ein Ctrl+Z die ganze Geste zurück und ein ungespeicherter Puffer bleibt ungespeichert. -
Es schreibt nie die Form um, in der die Datei geschrieben ist. Die init-only-Mitglieder einer
Komponente, das
LoadingvonButton, dasWidthvonFlexNode, sind nur über einen Objektinitialisierer erreichbar. Bei einem Fabrik-Aufruf ist die ehrliche Antwort „nicht von hier, und hier ist der Grund“: die Fabrikfläche existiert genau dafür, dass niemandnew Button("Save") { … }schreibt, und die eine hinter dem Rücken des Autors in die andere zu verwandeln ist keine Bearbeitung, um die er gebeten hat. Eine Konstruktion, die schon mitnewgeschrieben ist, hat diese Form gewählt, also werden ihre Klammern einfach hinzugefügt, wenn etwas hineingehört.
Eine geschlossene Menge wird als Liste angeboten, und der Typ ist nicht das Einzige, was
entscheidet, was geschlossen ist. Die Hälfte der Tokens des Frameworks sind keine Enums: Space ist
eine statische Klasse von const float, also liest sich ein float gap als Zahl. Was dort
geschrieben steht, sagt etwas anderes: Space.S3 benennt ein Mitglied einer statischen Klasse, und
jedes Geschwister desselben Typs gehört in diesen Platz, also öffnet sich die Zeile als die Skala, aus
der sie kam. Ein schlichtes gap: 7 bleibt eine Zahl, weil dort nichts eine Skala benennt.
Ein Wert ist keine Zeichenkette. Ein BoxStyle käme sonst als eine lange Zeile C# in einer
einzigen Zelle an, das, was ein Autor am meisten ändern will, an der einen Stelle, wo er es nicht
ändern kann. Ein Wert, der als new T { … } geschrieben ist, meldet seine Mitglieder als gewöhnliche
Eigenschaften, und das Panel rendert sie als kleines Blatt unter der Zeile, die sie trägt:
style BoxStyle 2 of 9 set
│ Padding EdgeInsets EdgeInsets.All(Space.S4) ×
│ Background ColorToken context.Theme.Surface ×
│ [ BorderWidth ▾ ] float + set
Schlüssel links, Werte in der eigenen Eingabe des Editors, und eine letzte Zeile, deren Schlüssel ein
Select von allem noch nicht Gesetzten ist. Ein Mitglied wieder herauszunehmen ist das × einer
Zeile: ein Blatt, dem man nur Zeilen hinzufügen kann, leckt. Alles hier ist dieselbe
Eigenschaftsmaschinerie eine Ebene tiefer, dieselben Enum-Listen, dieselbe Kompilier-Wache, dieselbe
Ablehnung, wenn der Wert ohne Initialisierer geschrieben ist, in dem er zu setzen wäre.
Das columns eines Grid ist ein Sammlungsausdruck, dessen Elemente echte Spannen haben, genau wie
ein children, und ebenso die items eines Menüs und die actions eines Dialogs. Alle bekommen,
was die Kinder bekamen: das Panel listet sie auf, und Einfügen oder Entfernen nimmt den Namen der
Liste.
Was sich unterscheidet, ist, was hinein geht. Ein GridTrack ist Daten: er rendert nie, also
trägt nichts auf der Leinwand seine Spanne und es gibt nichts zu klicken. Diese Listen werden daher
vom Panel aus über die Position angesprochen, und ihre Palette sind die eigenen Schreibweisen des
Elementtyps, GridTrack.Flex(), GridTrack.Auto und zielgetyptes new(…), da das Framework
Wert-Records absichtlich keine Fabrik gibt. Beide Tatsachen werden an der Signatur gelesen, statt als
Regel über Grids aufgeschrieben zu sein.
Seit 0.2.0-preview.30
Strukturelle Gesten sind auf die deklarative Form eingezäunt, einen Sammlungsausdruck
children: [ … ]:
Column(gap: Space.S4, children: [
Text("Total", TypeRole.LabelM, context.Theme.TextSecondary),
Text(total, TypeRole.TitleM, context.Theme.TextPrimary),
])Diese Liste ist die einzige Gestalt, in die ein Einfügen gefahrlos eingespleißt werden kann: ihre
Elemente haben echte Spannen, also geht ein neues zwischen zwei von ihnen, ohne irgendetwas anderes
zu berühren. Ein Container, der mit Anweisungen gebaut wird
(var column = new Column(); column.Add(…);), ist Datenfluss, keine Liste, und ihn umzuordnen ist ein
anderes Problem. Das Panel fragt zuerst und sagt es, statt ein Steuerelement anzubieten, das sich
weigert.
-
Einfügen kommt aus einer Palette, die aus den Fabrikflächen selbst abgeleitet ist, also
erscheint eine neue Komponente darin, ohne dass jemand eine Liste pflegt. Dazu gehören die eigenen
Komponenten der App: der Generator schreibt ihnen eine
AppUI-Fläche genau wie die des Frameworks, und sie werden zuerst angeboten, unter eigener Überschrift. Von jedem Eintrag ist bewiesen, dass er dort kompiliert, wo er landet: ein Test fügt jeden in eine echte Liste ein und scheitert an jedem, der es nicht täte. - Verschieben tauscht zwei Elemente und lässt alles zwischen ihnen genau dort, wo es ist: das Komma, den Zeilenumbruch, die Einrückung. Die Liste aus den Texten ihrer Elemente neu zu schreiben wäre einfacher und würde im Stillen einen Kommentar verwerfen, den jemand zwischen zwei Kindern gelassen hat. Eine Unvollkommenheit bleibt, und sie wird benannt statt verborgen: ein Kommentar, der über einem Kind geschrieben ist, bleibt bei der Position, nicht beim Kind.
- Entfernen nimmt das Element und genau einen Trenner. Das Element allein lässt ein verirrtes Komma; beide lassen ein Loch.
Weder Verschieben noch Entfernen wird dort angeboten, wo es nichts bedeutet: ein Knoten, der kein Element einer Liste ist, hat keine Ordnung, innerhalb derer er verschoben werden könnte, also werden die Steuerelemente verborgen statt deaktiviert, es gibt nichts über eine Anordnung zu erklären, die nicht existiert.
- Duplizieren kopiert den Text eines Knotens und setzt die Kopie unmittelbar danach, und die Kopie ist das, was ausgewählt bleibt, weil sie das ist, was du eben gemacht hast.
Jede Geste ist ein einziges WorkspaceEdit, also ist jede ein einziges Rückgängig.
Der ganze Bildschirm ist auch ein Baum, im Explorer neben der Gliederung. Jede Zeile sagt, wo sie
geschrieben ist, PaymentsPage.cs:28, was das Eine ist, das eine Liste sagen kann und ein Bild nicht,
und sie erreicht, was die Leinwand nicht kann: ein Container, der von seinen eigenen Kindern von Rand
zu Rand gefüllt ist, hat kein eigenes Pixel.
Eine Zeile zu wählen wählt sie auf der Leinwand aus, über denselben Weg, den ein Klick nimmt, also folgen die Gliederung, das Panel und der Cursor des Editors alle. Auf der Leinwand auszuwählen markiert die Zeile.
Jede Geste von oben ist auch eine Taste, und es ist dieselbe Geste statt einer zweiten Umsetzung von ihr:
| Pfeile | den Baum abgehen: hinauf zum Elternteil, hinab zum ersten Kind, links und rechts entlang der Geschwister |
| Alt+Pfeile | den Knoten verschieben statt die Auswahl |
| Delete | ihn entfernen |
| Cmd/Ctrl+D | ihn duplizieren |
| Esc | loslassen: zuerst die Auswahl, dann den Inspektionsmodus |
Sie beachten dieselben Wachen wie der Zeiger: nichts Strukturelles, während sich der Baum setzt, und überhaupt nichts, während der Zeiger über dem Panel ist, wo diese Tasten jemand sind, der tippt.
Dieselben drei Gesten sind am Zeiger, wo der Baum lesbar ist:
- Zieh ein Kind, um es umzuordnen. Ein Caret markiert die Lücke, in der es landen würde, und das Abzeichen sagt, wohin es geht, Text → 3 of 5. Wie weit es auch reist, es ist eine Bearbeitung und ein Rückgängig.
-
Fahre über ein Kind und ein
+erscheint an jedem seiner Enden, vor diesem, nach diesem, entlang der eigenen Achse des Containers. Welche Achse, wird am gerenderten Ergebnis gelesen statt am CSS: eineRowist flex, einGridist grid und einStackist absolut, und auf dem Bildschirm antworten alle drei auf „stehen diese nebeneinander?“ gleich. (Mit weniger als zwei Kindern gibt es kein Ergebnis zu lesen, und nur dort fragt die Leinwand das Layout selbst.) -
Fahre über den eigenen Raum eines Containers, auch einen leeren, und die Lücke, die dem Zeiger am
nächsten ist, wird mit einer gestrichelten Linie und einem einzelnen
+markiert. Diese Markierung ist die Antwort auf wo könnte etwas hin, was eine Frage ist, bei der eine Leinwand niemanden raten lassen sollte. Der Strich ist Absicht: das Caret markiert eine Festlegung, der Strich markiert eine Möglichkeit.
Ein Stapel ist keine Zeile. Die Kinder eines Stack überlappen sich, und die Malreihenfolge ist
die Kindreihenfolge, also ist seine Liste bedeutsam und seine Geometrie nicht. Die Leinwand kann es
nicht erkennen (zwei überlappende Kinder sehen genau wie zwei aus, die niemand gelayoutet hat), also
sagt der Host, welche Listen geschichtet sind. Dort wird die Abwurfmarke zu einer Decke über dem
Kind, vor dem der Knoten zu liegen kommen würde, das Abzeichen liest in front of Card statt
3 of 5, und die Pfeile des Panels behalten ihre Geste und lassen den falschen Namen dafür fallen:
Nach hinten senden und Nach vorn bringen.
Ein Ziehen ist nicht auf die Liste beschränkt, in der es begann: das Abwurfziel wird bei jeder
Bewegung aus dem Zeiger neu berechnet, also folgt das Caret in jeden Container, über dem es ist. Die
eigene Liste zu verlassen ist ein Entfernen und ein Einfügen, was der Host als eine einzige
Ersetzung schreibt, die beide umspannt, eine Bearbeitung, ein Ctrl+Z. Der verschobene Text wird auf
seine neue Tiefe neu eingerückt und ansonsten wortgetreu übernommen, und das macht den Compiler zum
Zaun: ein Knoten, der gegen eine lokale Variable der Methode geschrieben ist, aus der er kam,
kompiliert in seinem neuen Zuhause nicht, und die Ablehnung zitiert CS0103, statt eine Regel darüber
zu erfinden, was portabel ist.
Ablehnungen werden vor der Geste gezeichnet statt danach. Der Bildschirm und die C#-Liste müssen Kind für Kind zusammenpassen: ein Kind, das als mehrere Elemente rendert, oder als keines, bricht diese Entsprechung, und ein aus Pixeln berechneter Index würde dann ein anderes Element in der Datei benennen, also wird die Handlungsmöglichkeit zurückgehalten statt geraten. Ein Knoten kann nicht in seinen eigenen Teilbaum abgeworfen werden, nicht in einen Container, der keine Liste nimmt, und nicht in eine Liste in einer anderen Datei, das würde zwei Dokumente auf einmal bearbeiten.
Ein Verschieben macht die Spanne ungültig, die das Panel hielt, also antwortet der Host damit, wo der Knoten gelandet ist, und die Auswahl folgt ihm dorthin. Ohne das beschreibt eine Frage nach den alten Koordinaten das Geschwister, mit dem er eben getauscht wurde.
Der Vorschau ist es gleich, über welches SDK das Projekt ausgeliefert wird. Ein natives
(Photon)-Projekt, das kein wwwroot hat und eqc nie ausführt, bekommt genauso eine Vorschau: das
native SDK schreibt die Referenzliste für die Werkzeuge, die Erweiterung trägt die Browser-Laufzeit,
die dem Projekt zu Recht fehlt, und derselbe abstrakte Komponentenbaum rendert über den
Web-Realisierer. Die Werkzeugleiste sagt genau das, native project · web realizer, und öffnet in der
Telefon-Shell, denn das ist die Gestalt, in der die App ausgeliefert wird. Eine Vorgabe, kein Käfig:
sobald eine Hand den Formatwähler berührt, hört das Projekt auf, eine Meinung zu haben.
Ein Zähler, der auf 7 geklickt wurde, bleibt über den nächsten Tastenanschlag hinweg bei 7. Vor jedem
Neumontieren werden die eigenen Felder der Seite erfasst, von denen des Frameworks unterschieden,
indem die eigene Basisklasse der Seite abgefragt wird, nicht eine handgeschriebene Liste, und über
dieselbe __INITIAL_STATE__-Tür zurückgegeben, die die SSR-Übergabe nutzt. Durch den Klassennamen
abgesichert, also beginnt eine umbenannte Seite frisch, statt die Felder eines Fremden zu erben.
Der Würfel-Knopf in der Werkzeugleiste rendert den aktuellen Puffer durch die native Engine und zeigt das Bild, echte Glyphen, echtes Theme, im Format, das der Wähler gewählt hat. Das sind die Pixel, gegen die die GPU-Backends festgenagelt sind: das Bild kommt vom Referenz-Rasterisierer, der normativen Pixelquelle der Engine, und ein ständiger Paritätstest beweist, dass Metal dieselbe Displayliste zu denselben Pixeln zeichnet.
Es läuft in einem wegwerfbaren Kindprozess, denn das Build() einer Seite ist der Code des
Autors: eines, das nie zurückkehrt, wird nach zehn Sekunden getötet und kommt als Satz zurück, mit
der Vorschau noch lebendig dahinter. Dienste, um die der Konstruktor einer Seite bittet, werden so
erfüllt, wie der DI-Container es täte, minus den Container, eine Implementierung aus der eigenen
Assembly der App, wenn es eine gibt, sonst ein gutartiger Stub, und eine Seite, die dennoch wirft,
rendert die eigene Diagnosefläche des Frameworks und benennt die Komponente und die Ausnahme.
Ein Standbild, absichtlich, aber ein anklickbares. Bevor das Bild ausgegeben wird, wird jeder Ausdruck, der einen Knoten konstruiert, so umgeschrieben, dass er die C#-Spanne stempelt, die ihn gebaut hat (ein C#-zu-C#-Durchgang über die Design-Kompilierung, nie über etwas, das ein Nutzer ausliefert), und der Renderer gibt neben dem PNG eine Trefferkarte zurück: das Origin jedes Knotens und seine gelayouteten Grenzen, in Malreihenfolge. Ein Klick auf das Bild findet die oberste Komponente unter dem Cursor, den letzten Eintrag, der den Punkt enthält, markiert sie auf dem Bild, öffnet den Inspektor und zeigt die genaue Zeile. Es ist dieselbe Origin-Zeichenkette, mit der die Web-Leinwand auswählt, also antworten das Bild und die lebende Seite auf einen Klick gleich; Hilfsmethoden werden an ihrer Aufrufstelle gestempelt, und die eigene Spanne einer Konstruktion schlägt immer den Aufruf, der sie bloß zurückgab.
Interaktionen über die Auswahl hinaus bleiben auf der lebenden Vorschau, und eine Neukompilierung verwirft ein Bild der Seite, die sie ersetzt hat.
Verpacke es einmal und installiere das .vsix:
cd extensions/vscode && npm install && npm run packageDas kompiliert die Erweiterung, veröffentlicht den Design-Host hinein und schreibt
equantic-ui.vsix (10,7 MB), der Host reist mit der Erweiterung, eine Installation braucht also
keinen Checkout. Es ist framework-abhängig: eine eigenständige Veröffentlichung wären ~70 MB pro
Plattform und drei davon, und die eine Abhängigkeit, die das voraussetzt, ist die .NET-Laufzeit, gegen
die du ohnehin schon baust.
Wenn du stattdessen AN der Erweiterung arbeitest, genügt npm run compile: in der Entwicklung
gewinnt der eigene Build des Hosts aus dem Repository über einen verpackten, also kann ein gestern
gebautes .vsix nicht im Stillen für den Quellcode von heute antworten.
Dann öffne eine C#-Seite oder -Komponente und führe eQuantic UI: Open Preview aus. Das Projekt
muss einmal gebaut worden sein, die Vorschau steht auf der Ausgabe eines gewöhnlichen Builds (der
Referenzliste, die das SDK schreibt, und wwwroot/_equantic/runtime.js), also ist „baue das Projekt
einmal“ die ehrliche Anweisung, wenn ein Stück fehlt.
Die eigenen Steuerelemente der Vorschau leben in der Titelleiste des Editors, als gewöhnliche Befehle beigetragen, also erben sie das Theme und den Icon-Satz wie jede andere Editor-Aktion: der Zeiger startet und stoppt das Inspizieren, und ein Neustart ist da für den Fall, dass der Host zurückgebracht werden muss.
- Kein Ziehen zwischen Dateien. Ein Knoten kann in jede Liste der Datei gezogen werden, die bearbeitet wird, aber ein Container, der in einer anderen geschrieben ist, wird abgelehnt: diese Bearbeitung würde zwei Dokumente auf einmal berühren.
-
GridundStackbrauchen ihre eigene Geste. Die Spalten eines Grid sind Spuren, deren Hinzufügen jedes Kind neu fließen lässt, und die Listenreihenfolge eines Stack ist die Malreihenfolge, keines von beiden ist die Geste „ein Geschwister einfügen“, die die anderen Container teilen. -
Keine native Vorschau. Die Identität ist auf Photon schon gelöst (
LayoutNodeträgt den Knoten, absolute Grenzen und einen stabilen Pfad); es fehlt nur, Bilder in ein Webview zu bekommen. -
Keine
[ServerAction]-Aufrufe. Aktions-IDs kommen aus einem Assembly-Scan beim Start, also ist eine Ad-hoc-Vorschauklasse nie im Register. - Das Grundlinien-Theme. Eine App wählt ihr Theme beim Start, und das zurückzulesen heißt, die Kompositionswurzel der App auszuführen. Formen und Layout sind exakt; eine umgebrandete Palette wird noch nicht wiedergegeben.
- Debugging und Entwicklungswerkzeuge: der Logger und die Fehlerüberlagerung, die die Vorschau wiederverwendet.
- Compiler: wie C# zu dem Modul wird, das die Vorschau ausführt.
- Roadmap: Spur E und was vor ihr liegt.
🏁 Hier starten
🏗️ Architektur
- Architekturüberblick
- Write-once-Komponenten
- Deklarative Oberfläche
- Paketarchitektur
- Komponenten
- Styling
- Lokalisierung
- Analytics und GTM
📱 Write-once
- Photon-Engine
- Design System
- Fähigkeiten
- Speicher
- Formulare
- Code-Editor
- Markdown
- Mermaid
- E-Mail-Rendering
⚙️ Kompilierung
⚡ Runtime
🔌 Server
🎨 Ökosystem
🚀 Entwicklung