Hallo,
In dieser Ausgabe möchte ich meine Erfahrungen mit Feliz und Feliz.Bulma teilen.
Dieses Feedback basiert auf der Konvertierung von Fable Repl von Fable.React + Fulma in Feliz + Feliz.Bulma .
Im ersten Abschnitt werde ich alle Dinge auflisten, die mir bei der Verwendung von Feliz gefallen haben oder mit denen ich Probleme hatte. Ich werde etwas Ähnliches für Fable.React und Fulma tun, weil sie nicht von guten und weniger guten Teilen ausgenommen sind.
Dann werde ich ein zweites Mal versuchen zu erklären, wie meine Erfahrungen mit Feliz und Feliz.Bulma verlaufen sind. Das Ziel ist es, mit Ihnen zu teilen, wie sich mein Standpunkt im Laufe der Zeit verändert hat und warum.
Wichtig
Ich weiß, dass das Thema, das ich analysiere, sensibel ist und dass ich Angst habe. Aber denken Sie bitte daran, den Kommentarbereich positiv zu halten.
Ich habe versucht, eine Möglichkeit zu finden, meine Rückmeldungen zu organisieren, das klassische "Pro und Contra" fühlte sich für mich zu begrenzt und zu aggressiv an.
Stattdessen verwende ich Symbole:
Der gleiche Eintrag kann mehrere Symbole haben :)
✔️ Feliz und Fable.React können gemischt werden, da Feliz eine Schicht über Fable.React ist
✔️ Der Code lässt sich im Vergleich zu Fable.React bequemer einrücken, da wir nur eine einzige Liste haben. Es ist einfacher, der Tabelle zu folgen.
Hier klicken für Details
**Fable.React + Fulma**
div [ ]
[ Hero.hero [ Hero.IsFullHeight ]
[ Hero.body [ ]
[ Container.container [ ]
[ img [ Src "img/fable-ionide.png"
Style [ Display DisplayOptions.Block
Width "auto"
Margin "auto" ] ]
br [ ]
Heading.h3 [ Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "Fable REPL" ]
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "is only available on desktop" ] ] ] ] ]
**Feliz + Feliz.Bulma**Html.div [
Bulma.hero [
hero.isFullHeight
prop.children [
Bulma.heroBody [
Bulma.container [
Html.img [
prop.src "img/fable-ionide.png"
prop.style [
style.display.block
style.width length.auto
style.margin length.auto
]
]
Html.br [ ]
Bulma.title3 [
text.hasTextCentered
prop.text "Fable REPL"
]
Bulma.subtitle5 [
text.hasTextCentered
prop.text "is only available on desktop"
]
]
]
]
]
]
✔️ Dank des vorherigen Punktes ist es auch einfach, Code zu verschieben
✔️ Stark typisierte API für die DOM-Eigenschaften
✔️ Stark typisierte API für CSS und CSS-Einheiten über ICSSUnits
style.marginLeft (length.em 0.5)
style.width (length.percent (model.PanelSplitRatio * 100.))
✔️ Verschmutzt den Kontext nicht, die meisten Dinge sind unter Html.*
oder Prop.*
✔️ ⚠️ Feliz bietet die Möglichkeit Rauschen im Code zu vermeiden
Hier klicken für Details
Html.span "Fable REPL"
// instead of
// Feliz verbose version
span [
str "Fable REPL"
]
// Fable.React
span [ ]
[ str "Fable REPL" ]
// --------------------
Bulma.title4 "Fable REPL"
// instead of
// Feliz.Bulma verbose version
Bulma.title4 [
prop.text "Fable REPL"
]
// Fable.React
Headings.h4 [ ]
[ str "Fable REPL" ]
Da es mehrere Möglichkeiten gibt, denselben Code zu schreiben, können wir den Code nicht einfach "lesen". Manchmal müssen wir einen Schritt zurücktreten, um den äußeren Kontext zu verstehen. Dadurch wird der Code auch weniger "konsistent", da nicht alles gleich geschrieben ist.Html.tr [
Html.th "Steps"
Html.th [
prop.className "has-text-right"
prop.text "ms"
]
]
⚠️ Es unterstützt (noch) kein SSR
⚠️ Es ist nicht einfach, die Überladung der Methoden/Eigenschaften zu entdecken (dies ist vielleicht eine Einschränkung von Ionid, die ich nicht kenne)
Ich musste:
prop.text 2.0
unterstützt wird oder nicht, wenn ich einen Float hatte.⚠️ Erschweren Sie die Verwendung von Rückrufen, die mehr als einen Parameter benötigen. In Fable.REPL musste ich das Uncurry mit System.Func<_,_,_>
erzwingen.
Hier klicken für Details
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>) = Interop.mkAttr "editorDidMount" f
Was auf der aufrufenden Seite diesen Code ergibt:let private registerCompileCommand dispatch =
System.Func<_,_,_>(
fun (editor : Monaco.Editor.IStandaloneCodeEditor) (monacoModule : Monaco.IExports) ->
let triggerCompile () = StartCompile None |> dispatch
editor.addCommand(monacoModule.KeyMod.Alt ||| int Monaco.KeyCode.Enter, triggerCompile, "") |> ignore
editor.addCommand(monacoModule.KeyMod.CtrlCmd ||| int Monaco.KeyCode.KEY_S, triggerCompile, "") |> ignore
)
✔️ ⚠️ Feliz bietet Überladungen, um dem Benutzer das Leben etwas zu erleichtern, aber das hat seinen Preis.
Für prop.onChange
, etwa 6 Überladungen, je nachdem, was Sie hören möchten:
static member inline onChange (handler: bool -> unit)
static member inline onChange (handler: Event -> unit)
static member inline onChange (handler: File -> unit)
static member inline onChange (handler: File list -> unit)
static member inline onChange (handler: string -> unit)
static member inline onCheckedChange (handler: bool -> unit)
Das ist schön, weil dadurch vermieden wird, dass die Leute "kein" lustigen Code schreiben, aber das Gegenstück ist, dass Sie explizit sagen müssen, welchen Ereignistyp Sie möchten.
// Feliz
prop.onChange (fun (e : Types.Event) -> e.Value |> ChangeGistToken |> dispatch)
// Fable.React
prop.onChange (fun e -> e.Value |> ChangeGistToken |> dispatch)
✔️ ⚠️ Das Feliz-Ökosystem ist größtenteils typsicher, verhindert jedoch nicht das Schreiben von ungültigem Code. Wenn Sie Feliz und eine ihrer Erweiterungen wie Feliz.Bulma verwenden, können Sie Eigenschaften leicht mischen, aber Sie müssen dabei vorsichtig sein.
Hier klicken für Details
Dieser Code scheint aus Sicht von Feliz und dem F#-Compiler in Ordnung zu sein, aber er wird Ihnen nicht das erwartete Ergebnis liefern.
Html.p [
text.isUppercase
text.isItalic
color.hasTextSuccess
prop.text "Hello Feliz"
]
`text.isUppsercase`, `text.isItalic` und `color.hasTextSuccess` geben alle etwas wie `ClassName "my-css-class` aus. Aber in React hat nur das letzte eine Auswirkung, also in unserem Fall der Code generieren:<p class="has-text-success">Hello Feliz<\p>
Anstatt von<p class="is-uppercase is-italic has-text-success>Hello Feliz</p>
Die Lösung dafür ist das von Feliz.Bulma angebotene `++`:open Feliz.Bulma.Operators
Html.p [
text.isUppercase
++ text.isItalic
++ color.hasTextSuccess
prop.text "Hello Feliz"
]
Dies ist immer noch eine nette Möglichkeit, denn das bedeutet, dass Sie Verhalten aus einer anderen Feliz-Bibliothek zu einem "Feliz-Element" hinzufügen können, wenn sie kompatibel sind. Die Leute müssen nur vorsichtig sein.ℹ Zuerst dachte ich, Feliz biete nicht den Syntaxzucker ev.Value
, den wir mit Fable.React bekommen, aber das ist nicht der Fall.
Fable.React.Extension
hostet die Syntax Sugar, also können wir sie einfach öffnen, um den Kontext nicht mit all den Fable.React-Funktionen zu verschmutzen.
open Feliz
open Fable.React.Extensions
ℹ Die Syntax reproduziert nicht die Denkweise von HTML. Feliz ist eher ein Syntax-Zucker auf der React-API als HTML. Feliz denkt in Eigenschaften, denn selbst children
ist eine Eigenschaft.
✔️ Integriert sich gut in Feliz
✔️ Leichter einzurücken im Vergleich zu Fulma
Hier klicken für Details
// Fulma
Card.card [ ]
[ Card.header [ Common.Props [ OnClick (fun _ -> ToggleWidget title |> dispatch ) ] ]
[ Card.Header.title [ ]
[ Icon.icon [ Icon.Props [ Style [ MarginRight ".5em" ] ] ]
[ Fa.i [ icon; Fa.Size Fa.FaLarge ] [] ]
str title ]
Card.Header.icon [ ]
[ Icon.icon [ ] [ Fa.i [ headerIcon ; Fa.Size Fa.FaLarge ] [] ] ] ]
ofOption content ]
// Feliz.Bulma
Bulma.card [
Bulma.cardHeader [
prop.onClick (fun _ -> ToggleWidget title |> dispatch )
prop.children [
Bulma.cardHeaderTitle [
Bulma.icon [
prop.style [
style.marginRight (length.em 0.5)
]
prop.children [
Fa.i [ icon; Fa.Size Fa.FaLarge ] []
]
]
Html.text title
]
Bulma.cardHeaderIcon [
Bulma.icon [
Fa.i [ headerIcon ; Fa.Size Fa.FaLarge ] []
]
]
]
]
Html.ofOption content
]
✔️ Dank des Präfixes Bulma
ist es einfach, Bulma
Komponenten zu identifizieren
✔️ ⚠️ Die Eigenschaften sind zugänglich, verschmutzen aber den Kontext button.*
, help.*
, columns.*
.
Theoretisch sollten die Leute nur ein CSS-Framework verwenden, daher glaube ich nicht, dass es bei generischen Eigenschaften wie button.*
, columns.*
usw.
✔️ Die Komponentenhierarchie scheint leicht zu greifen
Bulma.card
> Bulma.cardHeader
> Bulma.cardHeaderTitle
Klicken Sie hier zum Beispiel
Bulma.card [
Bulma.cardHeader [
prop.onClick (fun _ -> ToggleWidget title |> dispatch )
prop.children [
Bulma.cardHeaderTitle [
// ...
]
Bulma.cardHeaderIcon [
// ...
]
]
]
]
⚠️ Aber einige der Komponenten folgen nicht der gleichen Konvention
Bulma.passwordInput
statt Bulma.inputPassword
In diesem Fall können Sie die verschiedenen Eingabetypen nicht einfach untersuchen, da sie nicht mit demselben "Präfix" beginnen.
✔️ ⚠️ Feliz.Bulma macht es einfach, das Verhalten von Komponenten zu mischen.
Hier klicken für Details
Bulma.button [
// Properties specific to a button coming from Feliz.Bulma
button.isOutlined
// Properties specific to a tooltip coming from Feliz.Bulma
tooltip.hasTooltipRight
tooltip.text tooltipText
// General properties coming from Feliz
prop.disabled isCompiling
prop.onClick (fun _ -> dispatch msg)
prop.children [
Bulma.icon [
icon.isLarge
prop.children faIcon
]
]
]
Das ist schön, denn wie Sie sehen, ist es einfach, einer vorhandenen Komponente ein neues Verhalten hinzuzufügen. Hier haben wir den Verhaltens-Tooltip zu einer Schaltfläche hinzugefügt. Das bedeutet aber auch, dass Sie ungültigen Code schreiben können wie:Html.select [
select.isFullwidth
]
Anstatt vonBulma.select [
select.isFullwidth
]
Fulma ist bei der Komponententrennung strenger und erlaubt Ihnen nicht, das Verhalten zu mischen, es sei denn, Sie übergeben die CSS-Klassen über `CustomClass`-Eigenschaften.✔️ ⚠️ Feliz.Bulma bietet keine Möglichkeit zu steuern, welches HTML-Element wir ausgeben möchten.
Zum Beispiel haben wir nur Bulma.field
was ein div
generiert. Manchmal möchten Sie jedoch ein p
Element als Ausgabe.
✔️ ⚠️ Feliz.Bulma ist ein exaktes Mapping über Bulma
Das ist schön, weil es schlank ist.
Es bedeutet aber auch:
Wenn Sie beispielsweise eine Bulma.tabs
Komponente schreiben, werden Sie nicht angeleitet und müssen wissen, dass tabs
ul
gefolgt von li
mit einem a
darin.
Klicken Sie hier, um den Code zu sehen
// Feliz + Feliz.Bulma
Bulma.tabs [
tabs.isCentered
tabs.isMedium
tabs.isToggle
prop.children [
Html.ul [
Html.li [
if (activeTab = CodeTab.FSharp) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.FSharp |> dispatch)
prop.children [
Html.a [
prop.text "F#"
]
]
]
Html.li [
if (activeTab = CodeTab.Html) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.Html |> dispatch)
prop.children [
Html.a [
prop.text "HTML"
]
]
]
Html.li [
if (activeTab = CodeTab.Css) then
prop.className "is-active"
prop.onClick (fun _ -> SetCodeTab CodeTab.Css |> dispatch)
prop.children [
Html.a [
prop.text "CSS"
]
]
]
]
]
]
Fulma ermöglicht es dem Benutzer, mehr in "Bulma-Komponenten" zu denken.// Fable.React + Fulma
Tabs.tabs [ Tabs.IsCentered
Tabs.Size Size.IsMedium
Tabs.IsToggle ]
[ Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.FSharp)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.FSharp |> dispatch)
] ]
[ a [ ] [ str "F#" ] ]
Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.Html)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.Html |> dispatch)
] ]
[ a [ ] [ str "HTML" ] ]
Tabs.tab [ Tabs.Tab.IsActive (activeTab = CodeTab.Css)
Tabs.Tab.Props [
OnClick (fun _ -> SetCodeTab CodeTab.Css |> dispatch)
] ]
[ a [ ] [ str "CSS" ] ] ]
Notiz:
Fulma betrachtet tab
als eine Komponente und bietet Tabs.Tab.*
spezifischen Wrapper an.
Bei Fulma müssen Sie immer noch wissen, dass ein a
Element erforderlich ist, aber wir könnten es standardmäßig hinzufügen (das ist bei einigen Komponenten der Fall).
✔️ ⚠️ Feliz.Bulma hat bei einem kleinen Projekt einen geringeren Einfluss auf die Bundle-Größe, hat jedoch einen größeren Einfluss, wenn die Projektgröße ansteigt.
Hier klicken für Details
Fulma verwendet viele DUs, um Bulma-Klassen zu modellieren. Sie können einen Blick auf [Common.fs] werfen (https://github.com/Fulma/Fulma/blob/2f99474cd6c793776001d07da009f7211be2f30c/src/Fulma/Common.fs); außerdem hat jede Komponente ihre eigenen DUs. Dies erfordert, dass Fulma einen Funktionsaufruf `parseOptions` implementiert, der die DUs in einfachen Worten in Klassen umwandelt. Feliz.Bulma verfolgt einen direkteren Ansatz, indem sie keine DSL zusätzlich zu Bulma-Klassen erstellt, sondern die Klassen stattdessen direkt ausgibt.
// Fulma
Column.column
[
Column.Width (Screen.Desktop, Column.IsHalf)
Column.Width (Screen.Mobile, Column.IsFull)
]
[
// ...
]
// Feliz
Bulma.column [
column.isHalfDesktop
column.isFullMobile
prop.children [
// ...
]
]
Dank der direkten Klassenverwendung und der Manipulation der Eigenschaftsliste hat Feliz.Bulma nicht die großen Kosten für alle in Fulma hinzugefügten DUs und Codes. Es braucht jedoch immer noch einen zusätzlichen Pass, um allen Klassen "beizutreten". Dieser Teil erfolgt über [Feliz.Bulma.ElementBuilders.Helpers module](https://github.com/Dzoukr/Feliz.Bulma/blob/3ecbba1579d2a26281f24e6a6664b5d9c5222603/src/Feliz.Bulma/ElementBuilders.fs) aber #L6-L23 diese Funktionen sind inline. Deshalb ist die Auswirkung auf Ihren Code umso größer, je größer Ihr Projekt ist.⚠️ Es ist nicht einfach, neue Farbunterstützung hinzuzufügen.
In Feliz.Bulma enthält jede Komponente ihre eigene Farbimplementierung wie button.isWarning
, help.isWarning
usw.
Wenn Sie also Ihre Farbe hinzufügen möchten, müssen Sie alle button.isMyNewColor
, help.isMyNewColor
implementieren
In Fulma, teilen sie alle die gleiche Farbe Art . Siehe die Dokumentation
✔️ Folgt der HTML-Struktur, wenn Sie es sich als Liste von Eigenschaften und einer Liste von Kindern vorstellen
⚠️Einrückungsregeln sind schwer festzulegen, weil wir eine Doppelliste organisieren müssen und im Allgemeinen viele Ausnahmefälle machen.
Klicken Sie hier für eine detaillierte Erklärung
Beispiel:
// When I want to put an empty div
div [ ] [ ]
// When I want to put a div with a single property
div [ ClassName "button" ] [ ]
// or
div [ ClassName "button" ]
[ ]
// When I want to put a div with several property
div [ ClassName "button"; Id "my-button" ]
[ ]
// yes but what if one of my property is not that simple?
div
[
ClassName "button"
OnClick (fun _ ->
// do something
)
]
[ ]
// It's also possible to have consistent indentation if you do something like that
div [ ] [
// Children 1
// Children 2
]
// But if you have non simple property you still have problems, I don't personally don't find it easy to read
// I am not sure if that's how people would write it because I don't use this format personally
div [
ClassName "button"
OnClick (fun _ ->
// do something
)
] [
div [ ] [
str "Children 1"
]
]
// and so on
Wie Sie nur bei einigen wenigen Fällen in der Eigenschaftsliste sehen können, haben wir mehrere mögliche Syntaxen. Wenn ich in meinem Projekt eine konsistente Syntax etablieren müsste, wäre das ungefähr so:div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
// Children 1 ...
// Children 2 ...
// Children 3 ...
]
div
[
// Property 1 ...
// Property 2 ...
// Property 3 ...
]
[
// Children 1 ...
// Children 2 ...
// Children 3 ...
]
]
// So for an empty element
div
[
]
[
]
// Awesome... 🙄
Zum Vergleich in Feliz mache ich:// Empty div
Html.div [ ]
// Non empty div
Htmldiv [
// Property 1
// Property 2
// Property 3
prop.children [
Html.div [
// Property 1
// Property 2
// Property 3
]
Html.div [
// Property 1
// Property 2
// Property 3
// Complexe property
OnClick (fun _ ->
// Do something
)
]
]
]
Ich habe jetzt also nur 2 Fälle, und ich könnte sogar die leere Version auf mehreren Zeilen ohne zu viel Rauschen schreiben, wenn ich wirklich einen einzigen Weg zur Strukturierung von Feliz-Code möchte.⚠️ Der größte Teil der API ist nicht typisiert
type HTMLAttr =
| DefaultChecked of bool
| DefaultValue of obj
| Accept of string
| AcceptCharset of string
| AccessKey of string
| Action of string
| AllowFullScreen of bool
| AllowTransparency of bool
✔️ ⚠️ Einige der APIs sind typisiert, aber nicht alle, was bedeutet, dass der Code nicht konsistent ist.
✔️ Es unterstützt SSR
✔️ Typsichere API
Modifier.TextAlignment (Screen.All, TextAlignment.Centered)
Button.button [ Button.Color IsWhite ]
[ str "White" ]
✔️ Die Fulma-API ist über Intellisense leicht zu erkunden, wenn Sie verstehen, wie sie strukturiert ist
✔️ Fulma zwingt dich, bei Komponenten in Begriffen zu denken
✔️ Machen Sie es einfach, die unterstützte Farbe zu erweitern, dank IsCustomColor
// All you need to add `custom-purple` support to all your components is this line
let isCustomPurple = IsCustomColor "custom-purple"
✔️ ⚠️ Ich denke, es hat eine gute Dokumentation mit Beispielen für alle Komponenten, aber nicht jede Komponente enthält den gleichen Informationsstand
✔️ ⚠️ Der Einfluss von Fulma auf deine Bundle-Größe ist "stabil". Dieser Punkt wurde im Abschnitt Feliz.Bulma beschrieben
⚠️ „Besondere Helfer“ findet man nicht so leicht.
⚠️ Fulma-Code fügt Ihrem Code aufgrund des stark typisierten DSL Rauschen hinzu
Klicken Sie hier für ein Beispiel
// Fulma
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ]
[ str "is only available on desktop" ]
// Feliz.Bulma
Bulma.subtitle5 [
text.hasTextCentered
prop.text "is only available on desktop"
]
⚠️ Fulma-Code ist nicht so einfach richtig zu formatieren, da er viele verschachtelte Listen enthält, wenn Sie Props
, Modifiers
kombinieren
An dieser Analyse habe ich über einen Zeitraum von 2-3 Wochen gearbeitet und könnte noch weitermachen. Aber ich muss es beenden, weil es viel Zeit in Anspruch nimmt und ich denke, dass ich die Situation jetzt besser im Blick habe.
All das, um zu sagen, dass es noch mehr gute Punkte oder Probleme geben könnte, insbesondere zu Fable.React und Fulma, aber das ist auch das Schwierigste für mich. Ich benutze sie und entwerfe sie seit mehr als 3 Jahren, daher ist es schwierig, eine objektive Sicht auf sie zu haben.
Die Konvertierung von Fable.React zu Feliz war einfach zu bewerkstelligen. Da Feliz mit Fable.React kompatibel ist, können Sie die Konvertierung auf progressive Weise Datei pro Datei, Komponente pro Komponente usw. durchführen.
Um sicher zu gehen, dass ich alles konvertiert habe, habe ich alle Anweisungen für open Fable.React
und open Fable.React.Props
. Ich habe auch Fulma als Abhängigkeit entfernt.
Natürlich hatte ich einige Dateien vergessen, also habe ich die Compilerfehler behoben und dann hat es funktioniert.
Sie können die Zusammenführungsanfrage, die die Konvertierung hostet, hier sehen .
Als ich Feliz entdeckte, war ich zunächst in der Defensive, weil es nicht dem "HTML/JSX-Weg" folgte und es ein alternatives Projekt für Dinge ist, in die ich viel Mühe investiert habe.
Dann erinnerte ich mich daran, dass Innovation so funktioniert und uns wachsen lässt. Zum Beispiel dank dessen, dass wir heute Elmish haben.
Eine andere Sache, an die ich mich erinnerte, ist, dass JSX nicht die "echte React-API" ist, tatsächlich ist die React-API React.createElement
. JSX ist obendrein ein Syntaxzucker, das gleiche gilt für Fable.React und Feliz. Ich bestehe darauf, weil es mir geholfen hat, vorwärts zu kommen und neugierig darauf zu sein.
Um Feliz zu testen, habe ich mich für ein mittelgroßes Projekt entschieden, das Fable REPL. Fable REPL ist keine komplexe Anwendung, verwendet jedoch viele Funktionen von Fable und React.
Eine nicht erschöpfende Liste von Dingen, die ich dank dieser Entscheidung getestet habe:
Als ich mit der Konvertierung begann, war ich sehr zufrieden mit der einfachen Formatierung des Codes. Ich denke, die Konvention zum Schreiben von Feliz-basierten Ansichten könnte wirklich einfach zu befolgen sein. Je größer meine Anwendungen werden, desto wichtiger finde ich die Codeformatierung.
Dann in der Mitte fing ich an, mich über etwas zu ärgern, konnte aber nicht finden, was.
Ich habe die Konvertierung von Fable REPL in Feliz abgeschlossen und war mir nicht sicher, ob mir meine Erfahrung damit gefallen hat oder nicht.
Erst jetzt, wenn ich versuche, meine Analyse abzuschließen, verstehe ich, was mich zurückhält. Es hat nicht viel mit Feliz zu tun, sondern eher mit Feliz.Bulma.
Es ist wichtig, sich daran zu erinnern, dass ich seit mehr als 2,5 Jahren an Fulma arbeite und es verbessere. Fulma ist eines meiner größten Projekte. Code damit zu schreiben ist großartig, vor allem, weil alles getippt ist und Sie gezwungen sind, in Komponenten zu denken.
Feliz.Bulma verfolgt einen anderen Ansatz und ist jünger als Fulma; es ist erst 5 Monate alt.
Nach alledem denke ich, ist es jetzt an der Zeit, zu meinem Fazit zu kommen :)
Ich denke, der größte Vorteil von Feliz ist der Single-List-Stil. Das habe ich oft erwähnt, aber für mich ist es ein großes Plus, meinen Code einfach formatieren zu können und nicht darüber nachdenken zu müssen, wo ich die nächste Zeile beginnen soll.
Zweitens ist die typsichere API ein Muss. Es ist ausführlicher als das CSS-Äquivalent, aber ich denke, es ist eine gute Funktion. Ich habe keine ausgefallenen Sachen damit gemacht, daher kann ich nicht sagen, ob alles unterstützt wird, aber wenn das nicht der Fall ist, können wir immer eine PR machen, um das zu beheben :).
Feliz.Bulma zeigt einen vielversprechenden Weg, um Feliz zu erweitern, ist aber noch nicht reif genug, um ein direktes Äquivalent zu Fulma zu sein. Dies ist etwas, was ich mit @Dzoukr mehr erforschen
Vor 3 Jahren, dem 8. März 2017 , haben Tomas, Eugene und ich beschlossen, Fable.Arch mit Elmish zu fusionieren. Dies ermöglichte es uns als Gemeinschaft, das erstaunliche Ökosystem aufzubauen, das wir heute haben.
Ich glaube, wir erleben derzeit mit Feliz und Fable.React eine ähnliche Zeit. Ich denke, Feliz wird mehr Zugkraft gewinnen als Fable.React
aber beides wird zusammen existieren. Am Ende arbeiten beide gut zusammen, was bedeutet, dass die Leute diejenige auswählen können, die sie bevorzugen.
Vielen Dank, dass Sie meine Analyse gelesen haben und ich werde sie gerne im Kommentarbereich mit Ihnen besprechen :)
Tolle Analyse.
Für mich persönlich, obwohl die doppelte Listenformatierung manchmal mühsam ist, habe ich das Gefühl, dass ich beim Betrachten des Fable.React-Codes die Struktur des zugrunde liegenden HTML besser sehen kann. Es ist div [.. , nicht Html.div [.... (usw.). Es ist keine große Sache, aber mein Gehirn scheint Fable.React einfacher zu analysieren.
Tolles Schreiben @MangelMaxime , du hast viele gute Punkte gemacht.
Nach allem, was ich mitbekommen habe, sind die wichtigsten Erkenntnisse hauptsächlich Probleme mit der Erweiterung der Bibliothek und die Probleme, die auftreten, wenn sie nicht optimal ausgeführt werden.
Ich kann definitiv zustimmen, dass das Schreiben von Bibliotheken für Feliz
dem Entwickler viel mehr Arbeit abverlangt, aber meiner Meinung nach ist es die Mühe wert, wenn die resultierende API so angenehm zu verwenden ist.
Ich habe eine ganze Reihe von Erweiterungen für Feliz
daher denke ich, dass ich einen Einblick geben kann, wie viele dieser Probleme behoben werden können:
Ich verwende Visual Studio und habe keine Probleme herauszufinden, welche Überladungen mir zur Verfügung stehen. Vielleicht kann dies auf der Seite von Ionid verbessert werden?
Wir könnten prop.text
einfach zu einer einzelnen Inline-Funktion machen, die das Element toString
erfordert und jeden Typ akzeptiert?
Anstatt von:
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>) = Interop.mkAttr "editorDidMount" f
Schreiben:
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : Monaco.Editor.IStandaloneCodeEditor -> Monaco.IExports -> unit) = Interop.mkAttr "editorDidMount" (Func<_,_,_> f)
Sie können dann die Immobilie so aufrufen, wie Sie es auf der Clientseite erwarten würden.
Ich habe noch niemanden gesehen, der dies in dem Umfang angewendet hat, den ich in einigen meiner Bibliotheken habe, und möglicherweise nicht vollständig anwendbar, wenn Html
. Sie können dies verhindern, indem Sie den von Ihnen definierten Eigenschaften zusätzliche Schnittstellentypen hinzufügen. In meiner größten Feliz
Bibliothek Feliz.Plotly
ich sie so eingerichtet, dass Sie einen Compilerfehler erhalten, wenn Sie Versuchen Sie, eine ungültige Eigenschaft zu verwenden. Der einzige Nachteil ist, dass es für den Bibliotheksentwickler ziemlich viel Arbeit bedeutet.
Zum erweitern klicken
[<AutoOpen;EditorBrowsable(EditorBrowsableState.Never)>]
module Types =
type IPlotProperty = interface end
type IModeBarButtonsProperty = interface end
type IAaxisProperty = interface end
type IAggregateProperty = interface end
type IAggregationProperty = interface end
type IAggregationsProperty = interface end
type IAngularaxisProperty = interface end
type IAnimationProperty = interface end
type IAnnotationProperty = interface end
type IAnnotationsProperty = interface end
type IAreaProperty = interface end
type IAspectratioProperty = interface end
type IAxisProperty = interface end
type IBarProperty = interface end
type IBarpolarProperty = interface end
type IBaxisProperty = interface end
type IBorderProperty = interface end
type IBoxProperty = interface end
type IButtonProperty = interface end
type ICameraProperty = interface end
type ICandlestickProperty = interface end
type ICapsProperty = interface end
type ICarpetProperty = interface end
type ICaxisProperty = interface end
type ICellsProperty = interface end
type ICenterProperty = interface end
type IChoroplethProperty = interface end
type IChoroplethmapboxProperty = interface end
type ICircleProperty = interface end
type IColoraxisProperty = interface end
type IColorbarProperty = interface end
type IColorscaleProperty = interface end
type IColorscalesProperty = interface end
type IConcentrationscalesProperty = interface end
type IConeProperty = interface end
type IConfigProperty = interface end
type IConnectorProperty = interface end
type IContourProperty = interface end
type IContourcarpetProperty = interface end
type IContoursProperty = interface end
type ICumulativeProperty = interface end
type ICurrentvalueProperty = interface end
type IDecreasingProperty = interface end
type IDeltaProperty = interface end
type IDensitymapboxProperty = interface end
type IDiagonalProperty = interface end
type IDimensionProperty = interface end
type IDimensionsProperty = interface end
type IDomainProperty = interface end
type IEditsProperty = interface end
type IErrorXProperty = interface end
type IErrorYProperty = interface end
type IErrorZProperty = interface end
type IEyeProperty = interface end
type IFillProperty = interface end
type IFilterProperty = interface end
type IFontProperty = interface end
type IFrameProperty = interface end
type IFramesEntryProperty = interface end
type IFramesProperty = interface end
type IFunnelProperty = interface end
type IFunnelareaProperty = interface end
type IGaugeProperty = interface end
type IGeoProperty = interface end
type IGradientProperty = interface end
type IGridProperty = interface end
type IGroupbyProperty = interface end
type IHeaderProperty = interface end
type IHeatmapProperty = interface end
type IHeatmapglProperty = interface end
type IHistogram2dProperty = interface end
type IHistogram2dcontourProperty = interface end
type IHistogramProperty = interface end
type IHoverlabelProperty = interface end
type IImageProperty = interface end
type IImagesProperty = interface end
type IIncreasingProperty = interface end
type IIndicatorProperty = interface end
type IInsidetextfontProperty = interface end
type IIsosurfaceProperty = interface end
type ILabelfontProperty = interface end
type ILataxisProperty = interface end
type ILayerProperty = interface end
type ILayersProperty = interface end
type ILayoutProperty = interface end
type ILeafProperty = interface end
type ILegendProperty = interface end
type ILightingProperty = interface end
type ILightpositionProperty = interface end
type ILineProperty = interface end
type ILinkProperty = interface end
type ILonaxisProperty = interface end
type IMapboxProperty = interface end
type IMarginProperty = interface end
type IMarkerProperty = interface end
type IMeanlineProperty = interface end
type IMesh3dProperty = interface end
type IModebarProperty = interface end
type INodeProperty = interface end
type INumberProperty = interface end
type IOhlcProperty = interface end
type IOutsidetextfontProperty = interface end
type IPadProperty = interface end
type IParcatsProperty = interface end
type IParcoordsProperty = interface end
type IPathbarProperty = interface end
type IPieProperty = interface end
type IPointcloudProperty = interface end
type IPolarProperty = interface end
type IProjectProperty = interface end
type IProjectionProperty = interface end
type IRadialaxisProperty = interface end
type IRangebreakProperty = interface end
type IRangebreaksProperty = interface end
type IRangefontProperty = interface end
type IRangeselectorProperty = interface end
type IRangesliderProperty = interface end
type IRotationProperty = interface end
type ISankeyProperty = interface end
type IScatter3dProperty = interface end
type IScatterProperty = interface end
type IScattercarpetProperty = interface end
type IScattergeoProperty = interface end
type IScatterglProperty = interface end
type IScattermapboxProperty = interface end
type IScatterpolarProperty = interface end
type IScatterpolarglProperty = interface end
type IScatterternaryProperty = interface end
type ISceneProperty = interface end
type ISelectedProperty = interface end
type IShapeProperty = interface end
type IShapesProperty = interface end
type ISlicesProperty = interface end
type ISliderProperty = interface end
type ISlidersProperty = interface end
type ISortProperty = interface end
type ISpaceframeProperty = interface end
type ISplomProperty = interface end
type IStartsProperty = interface end
type IStepProperty = interface end
type IStepsProperty = interface end
type IStreamProperty = interface end
type IStreamtubeProperty = interface end
type IStyleProperty = interface end
type IStylesProperty = interface end
type ISunburstProperty = interface end
type ISurfaceProperty = interface end
type ISymbolProperty = interface end
type ITableProperty = interface end
type ITernaryProperty = interface end
type ITextfontProperty = interface end
type IThresholdProperty = interface end
type ITickfontProperty = interface end
type ITickformatstopProperty = interface end
type ITickformatstopsProperty = interface end
type ITilingProperty = interface end
type ITitleProperty = interface end
type ITotalsProperty = interface end
type ITracesProperty = interface end
type ITransformsProperty = interface end
type ITransitionProperty = interface end
type ITreemapProperty = interface end
type IUniformtextProperty = interface end
type IUnselectedProperty = interface end
type IUpProperty = interface end
type IUpdatemenuProperty = interface end
type IUpdatemenusProperty = interface end
type IViolinProperty = interface end
type IVolumeProperty = interface end
type IWaterfallProperty = interface end
type IXProperty = interface end
type IXaxisProperty = interface end
type IXbinsProperty = interface end
type IYProperty = interface end
type IYaxisProperty = interface end
type IYbinsProperty = interface end
type IZProperty = interface end
type IZaxisProperty = interface end
type IButtonsProperty = inherit IModeBarButtonsProperty
type IMeasureProperty = interface end
type ITemplateProperty = interface end
In ähnlicher Weise können Sie auch Dinge im Bibliothekscode implementieren, um die Eigenschaften "automatisch" zu kombinieren, wenn Sie möchten. Ich bin mir jedoch nicht sicher, wie das funktioniert, wenn Sie Dinge außerhalb Ihrer eigenen Bibliothek verwenden. Der Trick dabei ist, diese Elemente zu einem anderen Typ zu machen als nur IReactProperty
. Zum Beispiel mache ich in Feliz.Plotly
viele Dinge, bei denen ich abhängig von den gegebenen Konfigurationen die Benutzereingaben modifiziere/sammele/ändere, um sie richtig in den tatsächlichen Code zu übersetzen. Es ist in gewisser Hinsicht wirklich schön, Dinge zu entfernen, die immer vorhanden sind.
Ich denke, viele der Probleme, die Sie hatten, könnten mit einer besseren Dokumentation darüber gelöst werden, wie Sie beim Schreiben Ihrer eigenen Bibliotheken auf die "Feliz" -Art navigieren. Vielleicht können @Zaid-Ajaj und ich in Zukunft daran arbeiten.
Danke @l3m
Für mich persönlich, obwohl die doppelte Listenformatierung manchmal mühsam ist, habe ich das Gefühl, dass ich beim Betrachten des Fable.React-Codes die Struktur des zugrunde liegenden HTML besser sehen kann. Es ist div [.. , nicht Html.div [.... (usw.). Es ist keine große Sache, aber mein Gehirn scheint Fable.React einfacher zu analysieren.
Tatsächlich ist es nicht einfach, die Art und Weise zu ändern, wie der Code gelesen wird, und deshalb habe ich erwähnt, dass wir ihn in meinem Fall nicht als HTML sehen sollten, es hat mir bei der Umstellung geholfen.
Ich nehme an, dass Feliz mit F# 5 und der Möglichkeit, statische Klassen zu öffnen, sowohl die Html.div
als auch die div
Syntax unterstützen kann, je nachdem, ob Sie die Html-Klasse öffnen oder nicht.
Danke @Shmew für den Kommentar und tatsächlich habe ich vergessen, dass es für Feliz mehrere Arten von "Bibliotheken" gibt.
Über das "Schreiben von ungültigem Code" ja, aber in einigen Bibliotheken möchten wir den Typ IReactProperty
"erweitern", um die Fulma-Situation zu vermeiden, in der Sie Standardeigenschaften über einen speziellen Helfer wie Props
. Der Grund dafür ist, dass Bulma "Komponenten" nur eine Spezialisierung auf die DOM-Elemente sind.
Sie sind nur Code, der standardmäßig eine Klasse in das HTML-Element einfügt.
Bulma.button
erzeugt <div class="button">
Im Fall einer Bibliothek, die auf "echten" Komponenten funktioniert (sorry, ich weiß nicht, wie ich sie anders benennen soll) ist Ihre Lösung in der Tat die richtige. Dies ist beispielsweise der Ansatz von Fable.ReactLeaflet, bei dem ich die spezifischen Eigenschaften für jede Komponente definiere. Daher müssen Komponenten nicht alle Standard-HTML-Eigenschaften unterstützen.
Über deine Lösung für "Rückrufe" hat es bei mir nicht funktioniert. Aber die von Fable übergebene Funktion hatte Curry-Argumente und wenn ich nicht etwas wie myFunction(arg1)(arg2)
schreiben wollte, musste ich die uncurry-Version über System.Func
erzwingen.
Wenn Sie wissen, wie es funktioniert, würde ich mich freuen, wenn Sie eine PR senden, um das Problem in https://github.com/fable-compiler/repl/pull/108/files zu beheben
Hallo @MangelMaxime ,
Zunächst möchte ich mich bei Ihnen dafür bedanken, dass Sie sich die Zeit und Mühe genommen haben, Feliz nicht nur in einem Projekt auszuprobieren, sondern auch eine so umfangreiche Analyse zu schreiben. Ich bin sicher, dass viele Fable-Benutzer es sehr hilfreich und informativ finden werden.
Ich schätze diese Art von Feedback und Offenheit sehr und glaube, dass es entscheidend ist, diese Bibliothek zusammen mit ihrem Ökosystem so gut wie möglich zu machen :pray:
Ich werde gleich über Feliz.Bulma sprechen, weil ich denke, dass es etwas Besonderes im Ökosystem ist. Zuerst werde ich auf einige Probleme antworten, die Sie bereits haben, ohne dass Änderungen in der Bibliothek vorgenommen werden können.
onChange
Sie müssen explizit angeben, welchen Ereignistyp Sie möchten.
Eigentlich nicht. Der Typ sollte wie folgt aus Ihrem Nachrichtentyp abgeleitet werden:
prop.onChange (ChangeGistToken >> dispatch)
Abhängig vom Typ von ChangeGistToken
wird die richtige Überladung abgeleitet. Wenn der DU-Fall ChangeGistToken of string
ist, wird die Überladung von string -> unit
gewählt. Es kann aber auch FileSelected of File
wenn der Eingabetyp file
In diesem Fall wird die Überladung File -> unit
abgeleitet und so weiter und so weiter. Sie brauchen nicht den Syntaxzucker von ev.Value
von Fable.React
prop.onCheckedChange wird entfernt, da
onChange
den booleschen Fall behandelt
@Shmew hat das Problem bereits angesprochen und tatsächlich können diese Arten von Eigenschaften so gelöst werden. Es ist wichtig zu verstehen, dass Sie bei der Implementierung von Feliz-Erweiterungen Transformationen durchführen können, bevor Sie die Eigenschaft festlegen:
type myExtension =
static member inline extenstionProperty value =
// transform value here
let transformedValue = doWeirdStuffWith value
Interop.mkAttr "extenstionProperty" transformedValue
Nach dieser Logik könnten Sie 'A -> 'B -> unit
Func<'A, 'B, unit>
intern in
[<Erase>]
type editor =
/// <summary>Triggered when the Editor has been mounted</summary>
static member inline editorDidMount (f : Monaco.Editor.IStandaloneCodeEditor -> Monaco.IExports -> unit) =
let transformedFunction = System.Func<Monaco.Editor.IStandaloneCodeEditor, Monaco.IExports, unit>(fun editor exported -> f editor exported)
Interop.mkAttr "editorDidMount" transformedFunction
Dies ist eine explizitere Version als die von @Shmew (Wie Sie bei Bindungen wissen, müssen Sie immer ein bisschen damit spielen, um sie richtig zu machen). Ein funktionierendes Beispiel dafür ist hier
Wie @Shmew oben erwähnt: Eine richtige Feliz-Erweiterung ermöglicht es Ihnen nicht, Code zu schreiben, der sich falsch verhält, und die Einschränkung der Eigenschaftstypen ermöglicht es Ihnen, dies zu implementieren. Sie können entweder Eigenschaften erstellen, die IReactProperty
wie es Feliz.Recharts tut, was die Abwärtskompatibilität mit vorhandenen Eigenschaften in prop
oder Sie könnten einen spezialisierteren Typ implementieren, der ISpecialiedProperty
unterstützt nur eine Teilmenge der Eigenschaften, während die Namen einiger Eigenschaften von IReactProperty
dupliziert werden, um die Abwärtskompatibilität zu gewährleisten:
type felizExtension =
static member inline specializedProp (value: string) : ISpecializedProperty = unbox (prop.text value)
Das habe ich mit Feliz.AntDesign gemacht, zum Beispiel hier, wo ich einige Eigenschaften dupliziere, um sie vom Einstiegspunkt button
verfügbar zu machen (später könnte ich die Eigenschaften mit strikten Typen spezialisieren, aber zuerst , rückwärtskompatiert ist, wo Sie zuerst beginnen). Ich glaube, Feliz.MaterialUI tut ähnliche Dinge, um IReactProperty
anstatt Eigenschaften zu spezialisieren. Dies bringt den Fall von Feliz.Bulma.
Bevor Feliz.Bulma implementiert wurde, hatte ich die Idee, dass es keine Notwendigkeit gibt , Feliz-Erweiterungen für CSS-only-Frameworks zu bauen. Feliz macht es bereits sehr einfach, mehrere Klassennamen zusammenzustellen und bedingt damit zu arbeiten. Mit implizitem yield
in F# ist es jetzt noch einfacher. Kombinieren Sie dies mit TypedCssClasses und Sie müssen kein
Nachdem ich jedoch die Implementierung von Feliz.Bulma von @Dzoukr gesehen habe, machte es Sinn: Sie könnten den Code stark vereinfachen, indem Sie bestimmte "Einstiegspunkte" in die CSS-Komponenten aus einem Modul von Bulma einführen, so dass Sie Bulma.button
, Bulma.card
usw. Diese sind wirklich nett zu benutzen. Was die Modifikatoren angeht, denke ich, dass Romans Ansatz leicht zu verfolgen und zu handhaben ist, aber wie Sie sagten, kann er manchmal interessante Ergebnisse liefern. Sicherlich gibt es in dieser Abteilung noch mehr zu verbessern und auf jeden Fall denke ich, dass Roman großartige Arbeit geleistet hat, um der Vision von Feliz zu folgen, etwas leicht zu erlernen und zu verwenden.
Ich möchte nur auf einen großen Unterschied zwischen den aktuellen Fable.React
und Feliz
hinweisen: die Paketversionierung und -verwaltung. Feliz-Versionen sind alle seine Ökosystembibliotheken Femto- kompatibel, was den Benutzern die Last nimmt, die erforderlichen npm-Pakete manuell installieren zu müssen oder zu wissen, mit welcher Version sie kompatibel sind. Dies ist anders als bei vielen, wenn nicht sogar allen, abgeleiteten Fable.React
Bibliotheken und sogar Fable.React
selbst, bei denen dies nicht der Fall ist.
Eigentlich nicht. Der Typ sollte wie folgt aus Ihrem Nachrichtentyp abgeleitet werden:
prop.onChange (ChangeGistToken >> dispatch)
Über diese Verwendung habe ich mir tatsächlich keine Gedanken gemacht.
Rückrufe mit mehreren Argumenten
@Shmew hat das Problem bereits angesprochen und tatsächlich können diese Arten von Eigenschaften so gelöst werden.
Entschuldigung, ich habe das Ende des Snippets von @Shmew nicht gesehen. Ich habe gerade die Unterschriftserklärung gesehen und war wie nein, funktioniert nicht.
Sie haben beide Recht, wir können die Transformation durchführen, bevor wir den Wert an die Eigenschaft übergeben.
Ja, TypedCssClasses ist in Ordnung, aber im Vergleich zu Fulma oder Feliz.Bulma kann es nicht die gleichen Funktionen bieten. Denn nicht alles ist in der CSS-Datei enthalten.
Eine andere Sache ist, dass wir im Dev-Modus die Datei nicht immer auf der Festplatte generiert haben und ich nicht sicher bin, ob TypedCssClasses dieses Szenario unterstützt.
Ich denke, Roman hat großartige Arbeit geleistet, um der Vision von Feliz zu folgen, etwas leicht zu erlernen und zu verwenden.
Ich stimme zu, ich denke nur, wir müssen ein wenig von der in Fulma geleisteten Arbeit hinzufügen, um es ähnlich zu machen. Wie gesagt, wir müssen den richtigen Mittelweg zwischen beiden finden.
Die fehlenden Funktionen, die mir im Moment ins Auge fallen, ermöglichen die Steuerung des Ausgabeelements und erleichtern die Erweiterung des Satzes der unterstützten Farben. Ich glaube nicht, dass es viel Komplexität hinzufügt.
@Zaid-Ajaj danke für das Feedback und vor allem dafür, dass du mir die richtige Richtung aufgezeigt hast, wie ich das Feliz-Potenzial nutzen kann.
Ich gebe zu, dass ich die Feliz-Dokumentation nicht wirklich gelesen habe (das ist schlecht, ich weiß), also sind sie vielleicht darin dokumentiert. Wenn nicht, wissen wir wohl, dass wir noch ein paar Dinge hinzufügen müssen :)
Danke @MangelMaxime - das ist ein toller Vergleich. Sie haben Fantomas nirgendwo für die automatische Formatierung des Codes erwähnt - hatten Sie die Möglichkeit, mit Fantomas mit Fable.React oder Feliz zu arbeiten?
In einem meiner Fable-Projekte, in denen ich Fantomas verwende, habe ich die automatische Formatierung beim Speichern von Dateien in Ionide aktiviert und muss sagen, dass dies wirklich ein Produktivitätsschub ist - Sie müssen sich überhaupt keine Gedanken über die manuelle Formatierung machen!
Ich denke wirklich, dass Fantomas jetzt an Fahrt gewinnt und würde gerne eine breitere Akzeptanz sehen, auch in Verbindung mit Fable und React / Feliz.
@theimowski Ich habe Fantomas seit einiger Zeit nicht mehr verwendet.
Vor allem, weil es meinen Code durcheinander brachte und es wirklich schwer zu lesen machte. Aus meiner Erfahrung war es nicht gut mit Fable.React und Feliz zu spielen.
Ich mag auch die Standardeinstellung von Fantomas nicht. Ich muss es in Zukunft erneut überprüfen, wenn ich weiß, wie mein Code eingerückt werden soll. Aber nach dem, was ich mir das Repo angesehen habe, glaube ich nicht, dass es meinen Anforderungen entspricht, hauptsächlich weil Fantomas den Code je nach Größe des Kontexts formatiert.
Wenn ich zum Beispiel so etwas schreibe:
type Test =
{
Prop1 : string
}
Ich möchte, dass es so bleibt und nicht zu type Test = { Prop1 : string }
nur weil es in eine einzelne Zeile passt.
Vielleicht ist eine Platte kein gutes Beispiel, aber ich hoffe ihr versteht was ich meine :)
@theimowski das ist toll zu hören, ich verwende Fantomas für meine Nicht-Fable-Projekte. Ich muss es noch einmal versuchen und sehen, wie es damit umgeht.
@MangelMaxime danke für deine Arbeit. Irgendwie hat mich Ihr Fulma-Projekt in der Fabelwelt angegriffen. Und ich genieße die Reise sehr.
Ich mag auch die Einzelliste, aber ich mag auch DU als Klassenmitgliedsüberschreibungen. Manchmal frage ich mich, ob DU Override unterstützt, dann wäre es super toll.
Da ich Fable.React bereits viel verwende, aber immer noch eine einzelne Liste möchte, habe ich einen Operator erstellt > und ich kann ihn wie folgt verwenden:
let myView =
div </> [
Classes [ ""; ""; "" ]
Children [
...
]
]
Der Operator ist ziemlich einfach und nutzt auch DU, meine grobe Implementierung könnt ihr hier überprüfen: https://github.com/albertwoo/Fun.LightForm/blob/master/src/Fun.LightForm.Fable/Fable.React. Extra.fs
@Zaid-Ajaj Danke auch für deine tolle Arbeit, ich habe auch angefangen, einige meiner Projekte in Feliz und Feliz.Material zu konvertieren.
Vielen Dank!
Hallo @MangelMaxime ,
erstmal danke! Ehrlich gesagt hätte ich nicht erwartet, dass sich jemand so intensiv mit der Bibliothek auseinandersetzen würde, die ich hauptsächlich für eigene Dogfooding-Projekte erstellt und als Nebeneffekt veröffentlicht habe. Komisch, wie der anfängliche Gedanke an "Hey, wie @Zaid-Ajaj Feliz entworfen hat, ist großartig - lasst uns dasselbe für Bulma tun" angeschwollen.
Ich habe bereits eine neue Ausgabe im Feliz.Bulma
Repo erstellt und liebe es zu diskutieren, wie man v2 noch besser machen kann. Es scheint, dass wir uns in den meisten Fragen einig sind, daher sollte es kein Problem sein, den version2
Zweig zu starten. Auch ein Blick auf den Plan von Zaid für die nächste Hauptversion könnte nützlich sein, um die API zwischen den neuesten Hauptversionen zu 100% kompatibel zu halten.
Trotzdem vielen Dank - tolle Analyse!
Auf die Gefahr hin wird die Wiedereröffnung alter Diskussionen (sorry!) Ich wollte nur meine zwei Cent auf die Vertiefung Debatte hinzufügen - das ist (mehr oder weniger) das Styling wir folgen , die für schöne, konsistente identation erlaubt und im Anschluss für die Fable.React Stil.
Der einzige Ort, auf den dies jedoch nicht ganz zutrifft, ist das nicht triviale Styling. Dies macht jedoch unserer Erfahrung nach nur eine Minderheit der Elemente aus (vielleicht 10-20%).
div [ ] [
Hero.hero [ Hero.IsFullHeight ] [
Hero.body [ ] [
Container.container [ ] [
img [ Src "img/fable-ionide.png"
Style [ Display DisplayOptions.Block
Width "auto"
Margin "auto" ]
]
br [ ]
Heading.h3 [ Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ] [
str "Fable REPL"
]
Heading.p [ Heading.IsSubtitle
Heading.Is5
Heading.Modifiers [ Modifier.TextAlignment (Screen.All, TextAlignment.Centered) ] ] [
str "is only available on desktop"
]
]
]
]
]
Auch wenn Sie VS Code und etwas wie Rainbow Brackets verwenden, kann dies wirklich helfen, die Überlastung der Klammern zu vermeiden.
Etwas anderes zu beachten (vielleicht habe ich das oben übersehen) ist, dass GiraffeViewEngine den Fable.React-Stil verwendet, dh das Element attr-list children-list, also nur etwas zum Nachdenken in Bezug auf die Leute, die zwischen den beiden wechseln.
@Zaid-Ajaj macht einen guten Punkt über Femto; Gibt es einen Grund, warum dies nicht von Komponenten im Fable.React-Stil implementiert werden konnte, oder ist dem Feliz-Stil etwas inhärent, an das Femto gekoppelt ist?
Gibt es einen Grund, warum dies nicht von Komponenten im Fable.React-Stil implementiert werden konnte, oder ist dem Feliz-Stil etwas inhärent, an das Femto gekoppelt ist?
@isaacabraham
Von Fable.React abgeleitete Bibliotheken könnten (und sollten) Femto-Metadaten hinzufügen, aber Fable.React selbst konnte dies nicht, da es eine inkompatible Mischung aus react
, react-dom
und react-native
. @MangelMaxime hat mit der Aufteilung von Paketen begonnen, aber es war viel mehr Arbeit als erwartet und wird wahrscheinlich bahnbrechende Änderungen einführen.
Für Bibliotheken, die von Fable.React
sind, bedeutet dies, dass sie nicht nur npm-Metadaten ihrer Abhängigkeiten einschließen müssen, sondern auch kompatible Versionen von react
und react-dom
da Fable.React dies nicht tut tun Sie das nicht für sie (im Gegensatz zu Feliz, das mit react
und react-dom
beginnt, damit Feliz-Erweiterungen nur das hinzufügen, was sie brauchen). Leider habe ich noch keine dieser Bibliotheken gesehen, die die Initiative ergriffen haben, um die Situation zu verbessern, auch wenn die Lösung schon seit geraumer Zeit existiert.
Zur Formatierung: Fantomas ist noch nicht in der Lage, DSLs sinnvoll zu formatieren und benötigt etwas Arbeit, um die Listenformatierung konfigurierbar zu machen, oder hat eine Art "Feliz-Modus"-Flag, um die React-DSL mit schönen Standardeinstellungen zu formatieren (die wir noch kommen müssen .) hoch mit)
@Zaid-Ajaj Das Problem mit React npm-Abhängigkeiten ist auch komplexer, da es möglich sein sollte, Preact anstelle von Reaction zu verwenden, ohne Femto zu unterbrechen.
@l3m In der Tat, aber in diesem Fall könnten wir Femto hinzufügen, um diesen Fall zu unterstützen. Es erinnert mich an etwas, also haben wir vielleicht ein Problem mit dem Femto-Repo (sorry, ich habe gerade keine Zeit, das zu überprüfen ^^)
@l3m Preact kann unabhängig von Femto-npm-Metadaten anstelle von React verwendet werden, da Sie Modulimportaliase nur gemäß den Richtlinien in Wechsel zu Preact konfigurieren müssen, wenn Sie eine vorhandene React-Anwendung haben.
Das Erstellen einer reinen Preact-Bindung (100% Nicht-React-Code) ist nicht das Ziel von Feliz und sollte wahrscheinlich als eigenständige Bibliothek (Feliz.Preact, die nicht von Feliz abhängt) implementiert werden, von der aus nur Preact-Bindungen erweitert werden und Wird verwendet, falls Sie sich von preact/compat
fernhalten möchten
@Zaid-Ajaj Ich verwende Preact gerade in meiner Elmish-App und es funktioniert gut. Ich war nur vorsichtig, wenn Femto package.json modifiziert, wenn es ein Nuget mit React-Deps sieht, und ich wollte das hervorheben. Wenn das kein Problem ist, umso besser.
Außerdem wird preact/compat
mit dem neuesten Preact nicht mehr benötigt, es ist jetzt im Kern enthalten.
Auf die Gefahr hin, alte Diskussionen wieder zu eröffnen (sorry!) Ich wollte nur meine zwei Cent zur Einrückungsdebatte hinzufügen - dies ist (mehr oder weniger) das Styling, das wir verfolgen, das eine schöne, konsistente Identifizierung und Verfolgung für die Fable ermöglicht Stil.
Ich ziehe Code auf sehr ähnliche Weise von Isaac ein und ist ziemlich lesbar.
Ich weiß, dass es schwer ist, die Dinge mit einer einzigen Liste zu vergleichen, aber die Einrückung des ursprünglichen Beitrags könnte etwas Ähnliches wie sein Code widerspiegeln, um einen besseren Vergleich zu erzielen.
Ich nehme an, dass Feliz mit F# 5 und der Möglichkeit, statische Klassen zu öffnen, sowohl die
Html.div
als auch diediv
Syntax unterstützen kann, je nachdem, ob Sie die Html-Klasse öffnen oder nicht.
Das wäre supercool. Wäre es möglich, die Html-Klasse statisch zu machen, damit sie geöffnet werden kann?
@fc1943s Html
, prop
und style
sind alle statische Klassen. Ich empfehle jedoch nicht, sie zu öffnen, wenn das Feature in F# 5 verfügbar wird, da der springende Punkt darin besteht, eine Gruppierung und einen Einstiegspunkt für die Erkennung der verfügbaren Funktionen innerhalb dieser statischen Klasse zu haben.
Wie würde das Öffnen der statischen Klasse die Entdeckung behindern? Sie könnten weiterhin Feliz.Html eingeben.
@MaxWilsonMS Das erforderte zusätzliche Schritte, um den "endgültigen" Code auszugeben.
Und Sie würden Feliz.Html.div
schreiben und dann Feliz.Html.
löschen, was seltsam erscheint.
Das Gute ist, dass die Leute je nach ihren Vorlieben wählen können, ob sie die statische Klasse öffnen möchten oder nicht. :)
Ich bin mir nicht sicher, wie nützlich dies sein wird, da ich das oben Gesagte wiederhole, aber Erfahrungen als kompletter Anfänger:
Ich bevorzuge den Feliz-Ansatz für die Einrückung. Ich habe ähnliche Ansätze ausprobiert, wie Isaac vorgeschlagen hat, aber da Einzüge nicht alle 2s/4s sind, verbringe ich manchmal Zeit damit, darüber nachzudenken. Bei Feliz verbringe ich keine Zeit damit, darüber nachzudenken.
Wenn ich ein benutzerdefiniertes Element erstellen würde, würde ich es vorerst auf die Fable.React-Art machen. Ich habe mir das Bauen "nach Feliz-Art" angesehen und bin sofort weggelaufen (ich werde es irgendwann noch einmal besuchen!).
Ich fände es wirklich nützlich, wenn die Dokumentation den Aspekt "So erstellen Sie eine benutzerdefinierte Eigenschaft" regelmäßiger priorisieren. Ich denke, es ist fair zu akzeptieren, dass diese Bibliotheken mit nur wenigen Autoren oft Schwierigkeiten haben werden, eine API-Oberfläche für alles Mögliche in CSS (zum Beispiel) anzubieten. in "em" oder können "grid-template-rows" nicht finden oder haben keine Ahnung, dass sie ein "Screen.All" -Argument liefern sollen - es wäre gut, wenn sie wüssten, wie man es umgeht.
Ich denke, dass einige Verbesserungen der "Lebensqualität" vorgenommen werden könnten, die einige potenzielle Bedenken ausräumen ... zum Beispiel, wenn ich mir lange vertikale Listen von Stil-Requisiten in Feliz ansehe, frage ich mich, ob es ein style.paddingHorizontal
und style.paddingVertical
. Mir ist klar, dass ich meine eigenen Helfer erstellen könnte, und dies ist jedoch nicht der Ort, um Funktionsanfragen zu stellen, und dass es möglicherweise der Wunsch besteht, die Einführung von Dingen zu vermeiden, die nicht standardmäßig sind :)
Ich mag die Idee, die statische Klasse Html
im neuen F# zu öffnen. Kritisch – meine Kollegen könnten es verstehen, wenn sie mir über die Schulter schauen – und ich finde es wichtig, mehr Leute einzubeziehen. Um den Advokaten des Teufels zu spielen: div
braucht nicht lange zu tippen und wenn ich es entdecken muss, dann ist dies die geringste der Herausforderungen, die ich meistern werde, wenn ich ein Setup verwende, das währenddessen zaubert Javascript, React, CSS etc. etc. vor mir verstecken. Im Allgemeinen ist die Auffindbarkeit der API jedoch großartig.
Gerade bei Übergängen/Animationen auf Styles macht der Feliz-Weg einfach so viel Sinn - wirklich schön zu arbeiten.
Allgemeiner und wahrscheinlich tangentialer: Die Herausforderung, die ich ständig treffe, besteht darin, zu verstehen, wo die Elmish-Welt endet und die React-Welt beginnt. Dies ist für beide Bibliotheken nicht wirklich ein Problem - aber da ich nicht die geringste Ahnung von React habe, verwirrt mich die Tatsache, dass ich eine Funktionskomponente von Fable.React oder Feliz bekommen könnte. Das zu lernen liegt natürlich in meiner Verantwortung - aber ich fand es erwähnenswert. Ich kombiniere derzeit die Ansätze von Elmish und React und glaube, dass dies dazu führt, dass alle Komponenten beim Update neu gerendert werden - aber ich kenne nicht den "richtigen" Weg, dies zu vermeiden, da Beispiele für vollständig erstellte Apps wie diese sind schwer zu finden. Manchmal habe ich den Eindruck, dass ich lernen sollte, React-Apps in Produktionsqualität zuerst in Javascript zu erstellen und dann zu Fable/Elmish zu graduieren - aber das fühlt sich wie eine ziemlich große Eintrittsbarriere an. Haftungsausschluss: Ich habe die Feliz-Dokumentation nicht ausführlich gelesen und sie ist wirklich gut - also liegt das wahrscheinlich an mir!
Vielen Dank an alle für das Teilen dieser Bibliotheken!
Danke für deinen Beitrag @drk-mtr!
Wenn ich ein benutzerdefiniertes Element erstellen würde, würde ich es vorerst auf die Fable.React-Art machen. Ich habe mir das Bauen "nach Feliz-Art" angesehen und bin sofort weggelaufen (ich werde es irgendwann noch einmal besuchen!).
Ja, es kann auf den ersten Blick ziemlich entmutigend erscheinen, aber es ist ziemlich einfach, wenn man sich daran gewöhnt hat. Davon abgesehen ist dies für den Entwickler beim Schreiben von Bibliotheken ein ziemlicher Anfangsaufwand. Ich finde dies ein ziemlich akzeptabler Kompromiss, da die überwiegende Mehrheit der Benutzer keine Bibliotheken schreiben wird. Glücklicherweise ist die Arbeit selbst ziemlich einfach, und etwas Kopieren + Einfügen kann viel der Arbeit beschleunigen (oder wie einige von uns Generatoren schreiben, um den Code für uns zu erstellen).
Ich fände es wirklich nützlich, wenn die Dokumentation den Aspekt "So erstellen Sie eine benutzerdefinierte Eigenschaft" regelmäßiger priorisieren. Ich denke, es ist fair zu akzeptieren, dass diese Bibliotheken mit nur wenigen Autoren oft Schwierigkeiten haben werden, eine API-Oberfläche für alles Mögliche in CSS (zum Beispiel) anzubieten. in "em" oder können "grid-template-rows" nicht finden oder haben keine Ahnung, dass sie ein "Screen.All" -Argument liefern sollen - es wäre gut, wenn sie wüssten, wie man es umgeht.
Nur für den Fall, dass Sie es nicht wissen (ich konnte es aus diesem Kontext nicht genau sagen):
Es gibt eine custom
Methode für die Typen prop
und style
.
Alles, was ICssUnit
akzeptiert, kann wie style.fontSize (length.em 1)
eingestellt werden:
Das Aktualisieren der Dokumente sollte einfach sein.
Ich denke, es könnten einige Verbesserungen an der "Lebensqualität" vorgenommen werden, die einige potenzielle Bedenken ausräumen ... zum Beispiel, wenn ich mir lange vertikale Listen von Stil-Requisiten in Feliz ansehe, frage ich mich, ob es eine style.paddingHorizontal and . geben könnte style.paddingVertical. Mir ist klar, dass ich meine eigenen Helfer erstellen könnte, und dies ist jedoch nicht der Ort, um Funktionsanfragen zu stellen, und dass es möglicherweise der Wunsch besteht, die Einführung von Dingen zu vermeiden, die nicht standardmäßig sind :)
Alles, was die Benutzererfahrung erleichtert, ist in meinem Buch definitiv willkommen. Ich würde gerne ein Problem/eine PR für all diese Dinge sehen, die Sie bemerkt haben!
Allgemeiner und wahrscheinlich tangentialer: Die Herausforderung, die ich ständig treffe, besteht darin, zu verstehen, wo die Elmish-Welt endet und die React-Welt beginnt. Dies ist für beide Bibliotheken nicht wirklich ein Problem - aber da ich nicht die geringste Ahnung von React habe, verwirrt mich die Tatsache, dass ich eine Funktionskomponente von Fable.React oder Feliz bekommen könnte. Das zu lernen liegt natürlich in meiner Verantwortung - aber ich fand es erwähnenswert. Ich kombiniere derzeit die Ansätze von Elmish und React und glaube, dass dies dazu führt, dass alle Komponenten beim Update neu gerendert werden - aber ich kenne nicht den "richtigen" Weg, dies zu vermeiden, da Beispiele für vollständig erstellte Apps wie diese sind schwer zu finden. Manchmal habe ich den Eindruck, dass ich lernen sollte, React-Apps in Produktionsqualität zuerst in Javascript zu erstellen und dann zu Fable/Elmish zu graduieren - aber das fühlt sich wie eine ziemlich große Eintrittsbarriere an. Haftungsausschluss: Ich habe die Feliz-Dokumentation nicht ausführlich gelesen und sie ist wirklich gut - also liegt das wahrscheinlich an mir!
Meine Erfahrung in der Fable-Welt (vor Feliz) war, dass ich alles größtenteils als normale Funktionen geschrieben habe (wie eine Komponente für jede .fs). Das Ergebnis war, dass ich viele der Vorteile verloren habe, die das React-System bietet. Seit ich mit Feliz angefangen habe, musste ich wirklich mehr darüber erfahren, wie React funktioniert (eine gute Sache imo). Seitdem ich mich daran gewöhnt habe, denke ich nicht einmal mehr bewusst darüber nach. Jede einzelne Funktion, die ich schreibe, die rendert, ist eine Funktionskomponente.
Wenn Sie wirklich lernen möchten, wie man React idiomatisch schreibt, ist es wirklich so einfach, sich darauf zu beschränken, Elmish nicht zu verwenden und nur Funktionskomponenten / Hooks in Ihrer Demo-App zu verwenden. Sie können ganz einfach alles verfolgen, was in JS geschrieben wurde, da die API fast genau gleich ist.
Eine qualitativ hochwertige Open-Source-Anwendung in Feliz geschrieben zu haben, wäre definitiv von Vorteil. Ich habe vor einiger Zeit ein Problem dafür erstellt #67. Das nächste, was im Moment wahrscheinlich am nächsten kommt, ist wahrscheinlich die Docs-App selbst oder die Electron-Demo von @cmeeren .
Hilfreichster Kommentar
Hallo @MangelMaxime ,
Zunächst möchte ich mich bei Ihnen dafür bedanken, dass Sie sich die Zeit und Mühe genommen haben, Feliz nicht nur in einem Projekt auszuprobieren, sondern auch eine so umfangreiche Analyse zu schreiben. Ich bin sicher, dass viele Fable-Benutzer es sehr hilfreich und informativ finden werden.
Ich schätze diese Art von Feedback und Offenheit sehr und glaube, dass es entscheidend ist, diese Bibliothek zusammen mit ihrem Ökosystem so gut wie möglich zu machen :pray:
Ich werde gleich über Feliz.Bulma sprechen, weil ich denke, dass es etwas Besonderes im Ökosystem ist. Zuerst werde ich auf einige Probleme antworten, die Sie bereits haben, ohne dass Änderungen in der Bibliothek vorgenommen werden können.
Überladungen von
onChange
Eigentlich nicht. Der Typ sollte wie folgt aus Ihrem Nachrichtentyp abgeleitet werden:
Abhängig vom Typ von
ChangeGistToken
wird die richtige Überladung abgeleitet. Wenn der DU-FallChangeGistToken of string
ist, wird die Überladung vonstring -> unit
gewählt. Es kann aber auchFileSelected of File
wenn der Eingabetypfile
In diesem Fall wird die ÜberladungFile -> unit
abgeleitet und so weiter und so weiter. Sie brauchen nicht den Syntaxzucker vonev.Value
vonFable.React
Rückrufe mit mehreren Argumenten
@Shmew hat das Problem bereits angesprochen und tatsächlich können diese Arten von Eigenschaften so gelöst werden. Es ist wichtig zu verstehen, dass Sie bei der Implementierung von Feliz-Erweiterungen Transformationen durchführen können, bevor Sie die Eigenschaft festlegen:
Nach dieser Logik könnten Sie
'A -> 'B -> unit
Func<'A, 'B, unit>
intern inDies ist eine explizitere Version als die von @Shmew (Wie Sie bei Bindungen wissen, müssen Sie immer ein bisschen damit spielen, um sie richtig zu machen). Ein funktionierendes Beispiel dafür ist hier
Typsicherheit im Feliz-Ökosystem
Wie @Shmew oben erwähnt: Eine richtige Feliz-Erweiterung ermöglicht es Ihnen nicht, Code zu schreiben, der sich falsch verhält, und die Einschränkung der Eigenschaftstypen ermöglicht es Ihnen, dies zu implementieren. Sie können entweder Eigenschaften erstellen, die
IReactProperty
wie es Feliz.Recharts tut, was die Abwärtskompatibilität mit vorhandenen Eigenschaften inprop
oder Sie könnten einen spezialisierteren Typ implementieren, derISpecialiedProperty
unterstützt nur eine Teilmenge der Eigenschaften, während die Namen einiger Eigenschaften vonIReactProperty
dupliziert werden, um die Abwärtskompatibilität zu gewährleisten:Das habe ich mit Feliz.AntDesign gemacht, zum Beispiel hier, wo ich einige Eigenschaften dupliziere, um sie vom Einstiegspunkt
button
verfügbar zu machen (später könnte ich die Eigenschaften mit strikten Typen spezialisieren, aber zuerst , rückwärtskompatiert ist, wo Sie zuerst beginnen). Ich glaube, Feliz.MaterialUI tut ähnliche Dinge, umIReactProperty
anstatt Eigenschaften zu spezialisieren. Dies bringt den Fall von Feliz.Bulma.Der Fall Feliz.Bulma
Bevor Feliz.Bulma implementiert wurde, hatte ich die Idee, dass es keine Notwendigkeit gibt , Feliz-Erweiterungen für CSS-only-Frameworks zu bauen. Feliz macht es bereits sehr einfach, mehrere Klassennamen zusammenzustellen und bedingt damit zu arbeiten. Mit implizitem
yield
in F# ist es jetzt noch einfacher. Kombinieren Sie dies mit TypedCssClasses und Sie müssen keinNachdem ich jedoch die Implementierung von Feliz.Bulma von @Dzoukr gesehen habe, machte es Sinn: Sie könnten den Code stark vereinfachen, indem Sie bestimmte "Einstiegspunkte" in die CSS-Komponenten aus einem Modul von Bulma einführen, so dass Sie
Bulma.button
,Bulma.card
usw. Diese sind wirklich nett zu benutzen. Was die Modifikatoren angeht, denke ich, dass Romans Ansatz leicht zu verfolgen und zu handhaben ist, aber wie Sie sagten, kann er manchmal interessante Ergebnisse liefern. Sicherlich gibt es in dieser Abteilung noch mehr zu verbessern und auf jeden Fall denke ich, dass Roman großartige Arbeit geleistet hat, um der Vision von Feliz zu folgen, etwas leicht zu erlernen und zu verwenden.Paketverwaltung von Feliz
Ich möchte nur auf einen großen Unterschied zwischen den aktuellen
Fable.React
undFeliz
hinweisen: die Paketversionierung und -verwaltung. Feliz-Versionen sind alle seine Ökosystembibliotheken Femto- kompatibel, was den Benutzern die Last nimmt, die erforderlichen npm-Pakete manuell installieren zu müssen oder zu wissen, mit welcher Version sie kompatibel sind. Dies ist anders als bei vielen, wenn nicht sogar allen, abgeleitetenFable.React
Bibliotheken und sogarFable.React
selbst, bei denen dies nicht der Fall ist.Zukunftspläne