Feliz: Machen Sie Feliz zu einer abstrakten API

Erstellt am 19. Dez. 2020  ·  15Kommentare  ·  Quelle: Zaid-Ajaj/Feliz

Ich bin dabei, eine bahnbrechende Änderung vorzuschlagen, aber hoffentlich eine, die nur Endbenutzer und Bibliotheksautoren erfordert, Pakete zu aktualisieren, und keine tatsächlichen Codeänderungen.

  1. F# ist eine großartige Sprache zum Deklarieren von Benutzeroberflächen
  2. Jeder F#-Entwickler, der etwas mit dem Web zu tun hat, schreibt seine eigene DSL, um UIs zu deklarieren
  3. Feliz ist eine großartige API/DSL, um React-Web-UIs zu deklarieren

Was wäre, wenn wir "React" von 3 entfernen würden? Dies könnte viele Probleme lösen:

  • Feliz könnte ein Standard werden und 2 in der obigen Liste lösen. Die meisten mit Feliz geschriebenen Komponenten können also automatisch mit verschiedenen Rendering-Engines verwendet werden
  • Dies kann auch die Fable.React-Abhängigkeit vermeiden, wie in #285 beschrieben (Fable.React würde IViewElement implementieren, um die Kompatibilität zu wahren).
  • Dies könnte es auch einfacher machen, einen serverseitigen Feliz-Renderer zu schreiben, ohne wie bei Fable.React überall #if FABLE_COMPILER zu müssen
  • Es kann vorkommen, dass jemand irgendwo einen Frontend-Renderer direkt in Fable schreibt. Es wäre toll, wenn es nur Feliz verwenden könnte

Wenn der Elevator Pitch abgeschlossen ist, können wir die Umsetzung besprechen, wenn Sie der Meinung sind, dass dies ein guter Schritt ist. Ich habe noch nichts ausprobiert, bin mir also nicht sicher, wie es funktionieren könnte, aber was ich im Sinn habe, ist so etwas:

type IViewElement = interface end
type IViewProp = interface end

// Later renderers can inherit these interfaces
type ReactElement = inherit IViewElement

// The basic renderer interface contains few methods
type IHTML =
    abstract renderNative: tagName: string * props: IViewProp seq

// Most of the helpers would be extensions to the interface
type IHTML with
    member this.div(props: IViewProp seq) = this.renderNative("div", props)
    ...

// Then we have different implementations
module Feliz.React

type ReactHTML() =
    interface IHTML with
        member _.RenderNative(tag, props, children) = ...

let Html = Feliz.ReactHTML()

// Consumer code
open Feliz.React

Html.div [...]

Ich bin mir nicht sicher, wie Intellisense funktionieren würde, vielleicht müssen wir eine abstrakte Klasse anstelle einer Schnittstelle verwenden, aber ich hoffe, Sie verstehen die Idee. Was denken Sie?

Hilfreichster Kommentar

@alfonsogarciacaro Das sieht

Alle 15 Kommentare

Hallo @alfonsogarciacaro , um ehrlich zu sein, ich glaube nicht, dass dies eine gute Idee ist. Theoretisch macht es natürlich Sinn: Lassen Sie uns in Fable eine Standard-API für HTML bauen. In der Praxis lässt sich das nicht sehr gut übersetzen. Hier sind ein paar Gründe:

  • Die aktuelle API ist alles andere als Standard, sondern sehr eigensinnig. Viele Leute mögen immer noch nicht die ganze Single-Liste und prop.children Ding, was natürlich völlig in Ordnung ist.
  • Die aktuelle API ist "einfach" gemacht, weil davon ausgegangen wird, dass sie nur React ist: Sie zu abstrahieren würde VIEL Arbeit erfordern, wobei die Alternative des Schreibens / Duplizierens einer API im Feliz-Stil wahrscheinlich die einfachere Lösung wäre.
  • Ich würde mich eher auf die Verbesserung der Tools rund um React konzentrieren, als die Ressourcen dünn zu verteilen: Feliz ist noch lange nicht "fertig", es gibt noch viel zu tun in Bezug auf Dokumentation, Beispielanwendungen, bessere Testgeschichte usw.

Vielen Dank für die Antwort @Zaid! Ich verstehe Ihre Argumentation, es ist immer noch schade, dass wir so viele konkurrierende DSLs haben, aber vielleicht gibt es andere Lösungen, wie Sie sagen. Wenn ich Zeit finde, werde ich trotzdem versuchen, einen Prototypen zu schreiben, um zu sehen, wie es funktionieren würde.

Übrigens, ich habe hier mit der Arbeit begonnen: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/src/HtmlEngine.fs

Ich habe es nicht getestet, aber ich habe alle unbox und ähnliche Tricks entfernt, daher "sollte" es im Prinzip mit jedem Renderer funktionieren, der diese Schnittstelle implementiert. Es wäre zum Beispiel schön zu versuchen, einen React-Renderer mit @dbattli Feliz.ViewEngine zu kombinieren und zu sehen, ob es SSR mit Feliz einfacher macht.

Es gibt ein paar Dinge, die herausgefunden/berücksichtigt werden müssen:

Intellisense

Ich bin nicht sehr glücklich, dass mein Intellisense funky aussehen würde, da Html in Feliz wie folgt definiert wäre:

let Html = HtmlEngine(renderer)

Das ist aber eher ein kleines Problem.

Bündelgröße

Wir möchten natürlich, dass dies so ist, wie es derzeit ist (oder besser). Vielleicht ein Plugin in Feliz.HtmlEngine , das in Compiler-Direktiven eingeschlossen ist? Diese Lösung würde jedoch dazu führen, dass die Webserver von Fable abhängig sind.

Andere Bibliotheken

Eines der größten Probleme mit SSR, wie es derzeit gemacht wird, ist, dass andere Bibliotheken in den meisten Fällen einfach nicht funktionieren, und diejenigen, die dies tun (wie Feliz.Bulma / Feliz.Bulma.ViewEngine ) müssen immer noch angepasst werden, es sei denn, sie müssen ebenfalls angepasst werden Erstellen Sie eine abstrakte API für beide, um ähnlich wie diese zu referenzieren.

Alternativen

Ich denke, das Grundproblem hier ist, dass der Versuch, SSR selbst zu machen, nicht sehr machbar ist, wenn wir die beabsichtigte erste Farbe vollständig emulieren möchten. Was wir wirklich brauchen, ist so etwas wie ReactDOMServer für .NET. Ich habe mich nicht wirklich damit befasst, aber wäre React.NET (vielleicht mit einem F#

Vielen Dank für die Kommentare @Shmew und sorry für die späte Antwort:

  • Intellisense : Hmm, ich habe nur ein einfaches Beispiel mit der abstrakten API geschrieben, aber kein Problem mit der Autovervollständigung festgestellt. Ich werde versuchen, es noch einmal zu überprüfen. Anstatt auf einen statischen Typ zuzugreifen, greifen Benutzer auf einen Wert zu. Ich denke, es sollte in Ordnung sein und in vielen Fällen muss der Code nicht geändert werden. Der Hauptnachteil wäre wahrscheinlich, dass open type nicht verwendet werden kann.
  • Bundle-Größe : Das muss ich auch überprüfen. Meine Hoffnung ist, dass sich nicht viel ändert, da die Klassenmitglieder von Fable als getrennte Funktionen kompiliert werden, die sich baumschütteln lassen und auch gut verkleinern können. Obwohl der generierte Code leider nicht mehr so ​​schön aussieht wie jetzt nach #284
  • Andere Bibliotheken : Ja, andere Bibliotheken müssten angepasst werden, um die Vorteile einer abstrakten API zu nutzen. Hoffentlich mit minimalen Änderungen.
  • Alternativen : TBH, ich weiß nicht wirklich, wie SSR mit React funktioniert, obwohl der (beigetragene) Code in Fable.React nicht sehr kompliziert aussieht (im Grunde nur einige Metadaten zu den generierten HTML-Tags hinzufügen), also nicht sicher ob es einfacher ist, so etwas wie React.NET zu verwenden oder nicht. Ich vermute, dass dieses ootb auch mit Feliz nicht verwendbar sein wird, da Feliz Fable-Tricks (hauptsächlich unsichere Casts) enthält, die .NET einwerfen.

Eigentlich denke ich dabei nicht nur an SSR, sondern auch _beyond React_ :wink:, zum Beispiel für HTML-Generatoren in F#-Servern, die nicht unbedingt mit React kompatibel sein müssen und für den Fall, dass wir andere Renderer verwenden möchten als Reagieren Sie für das Frontend.

Vielen Dank für die Kommentare @Shmew und sorry für die späte Antwort

Gern geschehen und keine Sorge!

Intellisense: Hmm, ich habe nur ein einfaches Beispiel mit der abstrakten API geschrieben, aber kein Problem mit der Autovervollständigung gesehen. Ich werde versuchen, es noch einmal zu überprüfen. Anstatt auf einen statischen Typ zuzugreifen, greifen Benutzer auf einen Wert zu. Ich denke, es sollte in Ordnung sein und in vielen Fällen muss der Code nicht geändert werden. Der Hauptnachteil wäre wahrscheinlich, dass offene Typen nicht verwendet werden können.

Entschuldigung, ich war nicht ganz klar. Intellisense ist in Ordnung, aber eher die Tatsache, dass Html eine andere Farbe hätte. Wie gesagt, ganz klein . Die Tatsache, dass wir open type verlieren, ist eigentlich eine etwas größere Sache. Ich weiß, dass einige das wirklich bevorzugen, als alles zu namespace.

Bundle-Größe: Das muss ich auch überprüfen. Meine Hoffnung ist, dass sich nicht viel ändert, da die Klassenmitglieder von Fable als getrennte Funktionen kompiliert werden, die sich baumschütteln lassen und auch gut verkleinern können. Obwohl der generierte Code leider nicht mehr so ​​schön aussieht wie jetzt nach #284

Ich wusste nicht einmal, dass die Interop-Funktionen nicht bereits inlined sind, ich habe sie bereits in meine Bibliotheken integriert. Ich habe eher über die Tatsache gesprochen, dass das gesamte Html Modul im Vergleich zu einer nativen Ausführung in JS keine Paketgröße erhöht, da es sich nur um einen Inline-Wrapper handelt. Bei einer konkreten Klasse ist das nicht mehr der Fall.

Andere Bibliotheken: Ja, andere Bibliotheken müssten angepasst werden, um die Vorteile einer abstrakten API zu nutzen. Hoffentlich mit minimalen Änderungen.

Das Problem dabei ist, dass Bibliotheken, die nativen Reaktionscode verwenden, nicht richtig funktionieren können, da alle Interna nur JS sind.

Alternativen: TBH, ich weiß nicht wirklich, wie SSR mit React funktioniert, obwohl der (beigetragene) Code in Fable.React nicht sehr kompliziert aussieht (im Grunde nur einige Metadaten zu den generierten HTML-Tags hinzufügen), also nicht sicher ob es einfacher ist, so etwas wie React.NET zu verwenden oder nicht. Ich vermute, dass dieses ootb auch mit Feliz nicht verwendbar sein wird, da Feliz Fable-Tricks (hauptsächlich unsichere Casts) enthält, die .NET einwerfen.

Ja, das funktioniert für einfache Fälle, aber wenn Sie versuchen, komplexere Dinge zu verwenden, wie einige der Komponenten in Feliz.MaterialUI es einfach nicht funktionieren. Soweit ich weiß, ist React SSR ziemlich einfach, wenn es auf node.js ausgeführt wird, da sie einfach ReactDOMServer ausführen können, um tatsächlich einen vollständigen String auszuspucken, der die erste Farbe der Seite ist. Mein Verständnis ist, dass React.NET nur einen node.js-Prozess umschließt, um genau das zu tun.

Ich vermute, dass dies mit Feliz-Code eigentlich ziemlich einfach wäre, da er solche Dinge bereits unterstützt. Der Ablauf wäre ungefähr so:

Fable compiles F# React 
-> node.js process imports and returns html string 
-> web server caches output 
-> web server serves page

jenseits von React

Das ist ein großartiger Punkt und definitiv etwas, was ich mir wünschen würde, wenn ich reines HTML ohne React oder so rendern wollte.

Ich habe mit dieser Idee experimentiert, Sie können meine Fortschritte hier sehen: https://github.com/alfonsogarciacaro/Feliz.Engine

Es gibt noch viel zu tun und ich habe einige Zweifel an einigen Dingen, aber es funktioniert bereits und deckt den größten Teil der Feliz-API ab. Allerdings musste ich ein paar Änderungen vornehmen, also ist es wahr, dass es schwierig wird, Feliz durch so etwas zu ersetzen. Aber eine abstrakte Version von Feliz ist immer noch wertvoll, da sie viele Möglichkeiten eröffnet. Einige Beispiele:

  1. Verwenden Sie es mit anderen Frontend-Frameworks wie Sutil: https://github.com/davedawkins/Sutil/pull/15
  2. Verwenden Sie es, um CSS anstelle von SASS zu generieren: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Css/Feliz.Css.fs
  3. Verwenden Sie es zum Generieren von statischem HTML: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.StaticHtml/Feliz.StaticHtml.fs
  4. Verwenden Sie es mit einer anderen Virtual-Dom-Implementierung wie Snabbdom: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Snabbdom/Feliz.Snabbdom.fs

Dies sind alles Entwürfe, aber sie funktionieren und Sie können sehen, dass sie sehr wenig Code benötigen. Noch wichtiger ist, dass sie alle Benutzern eine dokumentierte und vertraute API bieten, die auch erweiterbar ist: Sie können beispielsweise einfach eine BulmaEngine erstellen, die mit all diesen (und zukünftigen) Apps kompatibel ist. Im Fall von 2. und 3. verwende ich Fable, weil die inkrementelle Kompilierung viel schneller ist als mit .NET, aber Feliz.Engine ist mit .NET kompatibel (ich habe alle unbox ), also sollte es trivial sein um sie mit F# .NET-Servern kompatibel zu machen, und hoffentlich sollte es nicht viel Arbeit erfordern, auch den HTML-Generator React-kompatibel zu machen.

Was denkst du @Zaid-Ajaj? Den Gedanken, die aktuelle Feliz React API abzulösen, habe ich schon aufgegeben 😅 Ist der Name ok oder würdest du lieber einen anderen verwenden?

Hallo @alfonsogarciacaro , ich werde irgendwann diese Woche tief in diese Samples eintauchen und auf jeden Fall darauf zurückkommen 😄

Hallo,

Ich habe mir den Code wirklich kurz angeschaut und es scheint, als würde diese abstrakte Version einige Auswirkungen auf die Bundle-Größe haben. Wollte nur darauf hinweisen, da es eines der Merkmale von Feliz in seiner aktuellen Form war.

Ja, es wird ein Impact erwartet, die Frage ist, wie groß es ist :) Ich hoffe, dass es bei mittelgroßen Apps nicht sehr auffällt, aber es wäre natürlich schön, so etwas wie Fulma-Demo in beiden Stilen zu haben, also wir Optimierungsmöglichkeiten vergleichen und testen können. Es wäre auch interessant, nur zu überprüfen, wie sich das Inlining oder nicht Feliz-Helfer auf die Bundle-Größe auswirkt. Im Moment ist der von Feliz generierte Code ziemlich nett und sieht sehr nach kompiliertem JSX aus, aber Funktionen können minimiert werden, so dass es eine Möglichkeit sein könnte, die Duplizierung vieler Aufrufe wie .createElement("div") zu reduzieren (nicht sicher, ob gzip komprimieren kann diese Anrufe aber).

Ja, ich kann mir nicht vorstellen, dass jemand dagegen wäre, diese wunderbare API / diesen wunderbaren Stil in anderen Projekten zu verwenden. Meine einzigen wirklichen Bedenken waren, ob dies die Qualität dieser Bibliothek beeinträchtigen würde, und einige der oben beschriebenen ergonomischen Probleme.

Hallo @alfonsogarciacaro , ich habe mir den Beispielcode gut

  • Die CssEngine generiert CSS, was der Vorteil davon ist, nur CSS/SASS-Toolchains oder CSS-in-JS wie die in Feliz eingebaute zu verwenden oder andere CSS-in-JS-Bibliotheken wie FSS oder Emotion zu verwenden. Das Generieren von CSS aus F # würde alleine funktionieren, aber ich würde es nicht mit Feliz verwenden, da es eine bessere Wahl wäre, sich auf vorhandene Toolchains zu verlassen (auch schnellere Kompilierungszeiten, wenn Sie nicht möchten, dass der Fable / F #-Compiler verlangsamt wird) um riesige Stylesheets zu kompilieren) Momentan bin ich eher dafür, CSS-Module für Feliz/React-Komponenten zu verwenden
  • Die statische HTML-Engine: Feliz generiert bereits statisches HTML mit ReactDOM im Node und im Browser. Feliz.ViewEngine macht dasselbe für die Generierung von statischem HTML in Dotnet. Ich weiß, dass die Idee darin besteht, die API zu teilen, aber das wird durch andere Herausforderungen erschwert, wie @Shmew erwähnt hat: 3. Bibliotheken, die beides implementieren müssen, wirken sich auf den generierten Code aus, der jetzt wirklich sauber ist. Es mischt auch Attribute, Stile und Kinder in eine Liste, die die aktuelle API von Feliz bricht.
  • Snabbdom-Engine: interessantes Beispiel, hat aber nicht das Ökosystem von Bibliotheken wie React.

Alles in allem eine interessante Übung. Um ehrlich zu sein, bin ich kein großer Fan der neuen API und würde persönlich lieber Zeit damit verbringen, die aktuelle Erfahrung mit mehr Dokumenten, Beispielen und Bindungen in React zu verbessern, anstatt zu versuchen, die Bibliotheken zu standardisieren. Tut mir leid, wenn ich etwas negativ rüberkomme, du hast wahrscheinlich viel daran gearbeitet. Es macht mir nichts aus, denselben Namen wie Feliz zu haben, da er von der Bibliothek inspiriert wurde.

Vielen Dank für die Überprüfung der Beispiele @Zaid-Ajaj! Ich schätze deine Ehrlichkeit. Der CSS- und HTML-Drucker waren nur schnelle Beispiele, um zu überprüfen, wie einfach/schwierig die Anpassung der Feliz.Engine an potenzielle Anwendungen war (der Code zum Drucken beträgt nur 50 Zeilen). Ich habe Fable & Node verwendet, weil die inkrementelle Kompilierung viel schneller ist, aber "im Prinzip" sollte es einfach sein, es an .net anzupassen. Der Snabbdom-Adapter sollte auch ein weiteres schnelles Beispiel sein, aber ich beginne tatsächlich zu mögen, obwohl das eine andere Sache ist :)

Wie auch immer, mir ist endlich klar geworden, dass es nicht möglich sein wird, aktuelle Feliz React-Apps zu abstrahieren, ohne Änderungen vorzunehmen (wie du es von Anfang an gesagt hast 😅), also belassen wir es als paralleles Projekt für Benutzer, die andere Renderer mit ausprobieren möchten eine Feliz-ähnliche API

@alfonsogarciacaro Das sieht

Jawohl. das wäre ein toller Anwendungsfall. Es ist jedoch schwierig, da Feliz.Engine am Ende einige Unterschiede zu Feliz hat, was bedeutet, dass wir eine Feliz.Engine React-Implementierung schreiben müssten, die mit Feliz selbst konkurrieren würde, was ich vermeiden möchte ;) Aber hoffentlich finden wir eine Lösung.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen