Feliz: Meine Reise mit Feliz | Ein Vergleich zwischen Fable.React und Feliz

Erstellt am 7. Apr. 2020  ·  23Kommentare  ·  Quelle: Zaid-Ajaj/Feliz

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.

Inhaltsverzeichnis

Kategorisierungssystem

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:

  • ✔️ steht für etwas, das mir gefallen hat
  • ⚠️ kann mehrere Dinge darstellen:

    • etwas, das mir Probleme bereitet hat, weil es anders ist, als ich es gewohnt bin

    • etwas was verbessert werden könnte

    • Bereiche, in denen der Benutzer vorsichtig sein muss

  • ℹ steht für etwas, das für mich zunächst nicht offensichtlich war, aber nicht direkt mit einem Problem von Feliz zusammenhängt

Der gleiche Eintrag kann mehrere Symbole haben :)

Feliz


✔️ 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

feliz_move_code_demo


✔️ 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:

  • experimentiere selbst und überprüfe den Compilerfehler. Zum Beispiel testen, ob prop.text 2.0 unterstützt wird oder nicht, wenn ich einen Float hatte.
  • Schauen Sie sich direkt den Feliz-Quellcode an

⚠️ 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.


Feliz.Bulma

✔️ 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 von
Bulma.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:

  • Sie müssen Bulma gut genug kennen oder die Bulma-Dokumentation geöffnet haben
  • Es vermeidet keinen lauten Code

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


Fable.Reagieren

✔️ 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


Fulma

✔️ 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.

  • Benutzerdefinierte Klasse
  • Requisiten
  • Modifikatoren

⚠️ 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.

War die Umstellung schwierig?

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 .


Meine Reise mit Feliz

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:

  • Feliz
  • Feliz.Bulma
  • Wie gut Feliz und Fable.React kompatibel sind
  • Wie einfach der Übergang von Fable.React zu Feliz . ist
  • Verwendung einer funktionalen Komponente mit nativem Aufruf des DOM von Feliz
  • So schreiben Sie eine Bindung und Interop mit einer nicht trivialen benutzerdefinierten Komponente, die in JavaScript auf Feliz-Art geschrieben wurde
  • Der Übergang von Fulma zu Feliz.Bulma, damit ich sehen kann, was ein Fulma-Äquivalent im Feliz-Ökosystem sein könnte

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 :)

Abschluss

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 :)

awesome blog

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

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

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:

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

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 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.

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 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.

Paketverwaltung von Feliz

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.

Zukunftspläne

  • Schreiben (noch mehr) Dokumentation darüber, wie man Erweiterungen im Feliz-Stil erstellt und was man beachten sollte.
  • Aufbau eines Feliz-Analysators für Feliz selbst, aber möglicherweise für sein Ökosystem

Alle 23 Kommentare

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:

Überlastungen

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?

Rückrufe:

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.

Ungültigen Code schreiben

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.

Abschluss

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.

Überladungen von 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

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:

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

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 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.

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 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.

Paketverwaltung von Feliz

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.

Zukunftspläne

  • Schreiben (noch mehr) Dokumentation darüber, wie man Erweiterungen im Feliz-Stil erstellt und was man beachten sollte.
  • Aufbau eines Feliz-Analysators für Feliz selbst, aber möglicherweise für sein Ökosystem

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.

Der Fall Feliz.Bulma

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 die div 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 .

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen