Feliz: フェリスとの私の旅| Fable.ReactとFelizの比較

作成日 2020年04月07日  ·  23コメント  ·  ソース: Zaid-Ajaj/Feliz

こんにちは、

この問題は、私の経験をFelizおよびFeliz.Bulmaと共有するためのものです。

このフィードバックは、からフェイブルREPL変換に基づいているFable.React + Fulmaフェリス+ Feliz.Bulma

最初のセクションでは、Felizを使用するときに気に入ったものや問題があったものをすべてリストします。 Fable.ReactとFulmaについても同様のことをします。なぜなら、それらは良い部分と悪い部分を免除されていないからです。

次に、もう一度、FelizとFeliz.Bulmaでの私の経験がどのように進んだかを説明しようと思います。 目標は、私の視点が時間の経過とともにどのように変化したか、そしてその理由をあなたと共有することです。

重要

私が分析している主題は敏感であり、私を恐れている何かがあることを私は知っています。 ただし、コメントセクションは前向きに保つことを忘れないでください。

目次

分類システム

フィードバックを整理する方法を見つけようとしましたが、古典的な「長所と短所」は制限が多すぎて攻撃的だと感じました。

代わりに、記号を使用します。

  • ✔️は私が好きなものを表しています
  • ⚠️はいくつかのことを表すことができます:

    • 私が慣れているものとは違うので、私に問題を引き起こした何か

    • 改善できる何か

    • ユーザーが注意する必要がある領域

  • ℹは、最初は明らかではなかったものの、フェリスによる問題とは直接関係のないものを表しています。

同じエントリに複数の記号を含めることができます:)

フェリス


✔️FelizはFable.Reactの上にあるレイヤーであるため、FelizとFable.Reactを混在させることができます


✔️リストが1つしかないため、コードはFable.Reactに比べてインデントしやすくなっています。 集計に従う方が簡単です。

詳細はこちら

** 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"
                    ]
                ]
            ]
        ]
    ]
]


✔️前のポイントのおかげで、コードを移動することも簡単です

feliz_move_code_demo


✔️DOMプロパティ用の強く型付けされたAPI


✔️ ICSSUnits介したCSSおよびCSSユニット用の強く型付けされたAPI

style.marginLeft (length.em 0.5)
style.width (length.percent (model.PanelSplitRatio * 100.))

✔️コンテキストを汚染しません。ほとんどのものはHtml.*またはProp.*


✔️⚠️Felizは、コード内のノイズを回避する可能性を提供します

詳細はこちら

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" ]
同じコードを書く方法はいくつかあるので、コードを単に「読み取る」ことはできません。 外側の文脈を理解するために、一歩後退する必要がある場合があります。 また、すべてが同じように記述されているわけではないため、コードの「一貫性」が低下します。
Html.tr [
    Html.th "Steps"
    Html.th [
        prop.className "has-text-right"
        prop.text "ms"
    ]
]


⚠️(まだ)SSRをサポートしていません


⚠️メソッド/プロパティのオーバーロードを発見するのは簡単ではありません(これはおそらく私が知らないIonideの制限です)

そうしなければならなかった:

  • 自分で実験して、コンパイラエラーを確認してください。 たとえば、フロートがあったときにprop.text 2.0がサポートされているかどうかをテストします。
  • Felizのソースコードを直接見てください

⚠️複数のパラメータを使用するコールバックの使用を難しくします。 Fable.REPLでは、 System.Func<_,_,_>を使用してアンカリーを強制する必要がありました。

詳細はこちら

[<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
これにより、呼び出し側でこのコードが得られます。
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は、ユーザーの生活を少し楽にするためのオーバーロードを提供しますが、これにはコストがかかります。

prop.onChange場合、聞きたいものに応じて6つのオーバーロードのように:

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

これは、人々が「no」の楽しいコードを書くことを回避するので便利ですが、対応するのは、どのイベントタイプが必要かを明示的に言う必要があるということです。

// Feliz
prop.onChange (fun (e : Types.Event) -> e.Value |> ChangeGistToken |> dispatch)

// Fable.React
prop.onChange (fun e -> e.Value |> ChangeGistToken |> dispatch)

✔️⚠️Felizエコシステムはほとんどタイプセーフですが、無効なコードの記述を妨げることはありません。 FelizとFeliz.Bulmaのようなその拡張機能の1つを使用する場合、プロパティを簡単に混在させることができますが、それを行うときは注意する必要があります。

詳細はこちら

このコードは、FelizとF#コンパイラの観点からは問題ないように見えますが、期待した結果は得られません。

Html.p [
    text.isUppercase
    text.isItalic
    color.hasTextSuccess
    prop.text "Hello Feliz"
]
`text.isUppsercase`、` text.isItalic`、 `color.hasTextSuccess`はすべて` ClassName "my-css-class`のようなものを出力します。しかし、Reactでは、最後の1つだけが効果を発揮するため、この場合、コードは生成:
<p class="has-text-success">Hello Feliz<\p>
それ以外の
<p class="is-uppercase is-italic has-text-success>Hello Feliz</p>
その解決策は、Feliz.Bulmaが提供する `++`を使用することです。
open Feliz.Bulma.Operators

Html.p [
    text.isUppercase
    ++ text.isItalic
    ++ color.hasTextSuccess
    prop.text "Hello Feliz"
]
互換性がある場合は、別のFelizライブラリからの動作を「Feliz要素」に追加できることを意味するため、これは依然として良い可能性です。 人々はただそれに注意する必要があります。


ℹ最初、FelizはFable.Reactを使用したときに得られるシンタックスシュガーev.Valueを提供していないと思いましたが、そうではありません。

Fable.React.Extensionはシンタックスシュガーをホストしているので、それを開くだけで、すべてのFable.React関数でコンテキストを汚染しないようにすることができます。

open Feliz
open Fable.React.Extensions

ℹ構文はHTMLの考え方を再現していません。 Felizは、HTMLよりもReactAPIの上位にあるシンタックスシュガーです。 childrenさえプロパティであるため、Felizはプロパティの観点から考えます。


Feliz.Bulma

✔️Felizとうまく統合します


✔️フルマに比べてインデントが簡単

詳細はこちら

// 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
]


✔️ Bulmaプレフィックスのおかげで、 Bulmaコンポーネントを簡単に識別できます


✔️⚠️プロパティはアクセス可能ですが、コンテキストbutton.*help.*columns.*汚染します。

理論的には、CSSフレームワークは1つだけ使用する必要があるため、 button.*columns.*などの一般的なプロパティで衝突することはないと思います。


✔️コンポーネントの階層は簡単に把握できるようです

Bulma.card > Bulma.cardHeader > Bulma.cardHeaderTitle

たとえば、ここをクリックしてください

Bulma.card [
    Bulma.cardHeader [
        prop.onClick (fun _ -> ToggleWidget title |> dispatch )
        prop.children [
            Bulma.cardHeaderTitle [
                // ...
            ]

            Bulma.cardHeaderIcon [
                // ...
            ]
        ]
    ]
]


⚠️しかし、一部のコンポーネントは同じ規則に従っていません

Bulma.passwordInput代わりにBulma.inputPassword

この場合、同じ「プレフィックス」で始まらないため、さまざまなタイプの入力を簡単に調べることはできません。


✔️⚠️Feliz.Bulmaを使用すると、コンポーネントの動作を簡単に組み合わせることができます。

詳細はこちら

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
        ]
    ]
]
ご覧のとおり、既存のコンポーネントに新しい動作を簡単に追加できるので、これはすばらしいことです。 ここでは、動作ツールチップをボタンに追加しました。 ただし、これは、次のような無効なコードを記述できることも意味します。
Html.select [
    select.isFullwidth
]
それ以外の
Bulma.select [
    select.isFullwidth
]
Fulmaはコンポーネントの分離についてより厳密であり、 `CustomClass`プロップを介してCSSクラスを渡さない限り、動作を混在させることはできません。


✔️⚠️Feliz.Bulmaは、出力するHTML要素を制御する方法を提供していません。

たとえば、 divを生成するBulma.fieldしかありません。 ただし、出力としてp要素が必要な場合があります。


✔️⚠️Feliz.BulmaはBulmaの正確なマッピングです

スリムなのでいいですね。

しかし、それはまた意味します:

  • Bulmaを十分に理解しているか、Bulmaのドキュメントを開いておく必要があります
  • それは騒々しいコードを避けません

たとえば、 Bulma.tabsコンポーネントを作成する場合、ガイドはなく、 tabsulが必要であり、その後にliaが必要であることを知っておく必要があります。

コードを表示するには、ここをクリックしてください

// 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を使用すると、ユーザーは「Bulmaコンポーネント」の観点からより多くのことを考えることができます。
// 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" ] ] ]

ノート:

Fulmaはtabをコンポーネントと見なし、 Tabs.Tab.*固有のラッパーを提供します。

Fulmaでは、 a要素が必要であることを知っておく必要がありますが、デフォルトで追加できます(一部のコンポーネントの場合)。


✔️⚠️Feliz.Bulmaは、小さなプロジェクトのバンドルサイズへの影響は小さくなりますが、プロジェクトサイズが大きくなると、より大きな影響があります。

詳細はこちら

Fulmaは、Bulmaクラスをモデル化するために多くのDUを使用しています。 [Common.fs](https://github.com/Fulma/Fulma/blob/2f99474cd6c793776001d07da009f7211be2f30c/src/Fulma/Common.fs);をご覧ください。 また、各コンポーネントには独自のDUがあります。 これには、FulmaがDUをクラスに変換する関数呼び出し `parseOptions`を実装する必要があります。 Feliz.Bulmaは、Bulmaクラスの上にDSLを作成するのではなく、クラスを直接出力することで、より直接的なアプローチを取ります。

// Fulma
Column.column
    [
        Column.Width (Screen.Desktop, Column.IsHalf)
        Column.Width (Screen.Mobile, Column.IsFull)
    ]
    [
        // ...
    ]

// Feliz
Bulma.column [
    column.isHalfDesktop
    column.isFullMobile
    prop.children [
        // ...
    ]
]
クラスを直接使用し、プロパティリストを操作することで、Feliz.Bulmaは、Fulmaに追加されたすべてのDUとコードのような大きなコストをかけません。 ただし、すべてのクラスに「参加」するには、追加のパスが必要です。 この部分は[Feliz.Bulma.ElementBuilders.Helpersモジュール](https://github.com/Dzoukr/Feliz.Bulma/blob/3ecbba1579d2a26281f24e6a6664b5d9c5222603/src/Feliz.Bulma/ElementBuilders.fs#L6-L23)を介して行われますが、すべてこれらの機能はインライン化されています。 そのため、プロジェクトが大きくなるほど、コードへの影響も大きくなります。


⚠️新しいカラーサポートを追加するのは簡単ではありません。

Feliz.Bulmaでは、各コンポーネントはbutton.isWarninghelp.isWarningなどの独自のカラー実装を保持します。

したがって、色を追加する場合は、すべてのbutton.isMyNewColorhelp.isMyNewColorを実装する必要があります。

フルマでは、それらはすべて同じ色タイプを共有します。 ドキュメントを参照してください


Fable.React

✔️プロパティのリストと子のリストと考えると、HTML構造に従います


⚠️インデントルールは、二重リストを整理する必要があるため確立するのが難しく、一般に、多くの例外的なケースを作成します。

詳細な説明はこちら

例:

// 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
プロパティリストのいくつかのケースを処理するときにわかるように、いくつかの可能な構文があります。 プロジェクトで一貫した構文を確立する必要がある場合は、次のようになります。
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... 🙄
フェリスでの比較のために、私はします:
// 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
            )
        ]
    ]
]
したがって、現在2つのケースしかなく、Felizコードを構造化する単一の方法が本当に必要な場合は、ノイズをあまり発生させずに空のバージョンを複数行に書き込むこともできます。


⚠️ほとんどのAPIは入力されていません

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

✔️⚠️一部のAPIは入力されていますが、すべてではありません。これは、コードに一貫性がないことを意味します。


✔️SSRをサポートしています


フルマ

✔️タイプセーフAPI

Modifier.TextAlignment (Screen.All, TextAlignment.Centered)

Button.button [ Button.Color IsWhite ]
    [ str "White" ]

✔️FulmaAPIは、その構造を理解していれば、インテリセンスを介して簡単に探索できます


✔️Fulmaはあなたにコンポーネントの観点から考えることを強制します


✔️ IsCustomColorおかげで、サポートされている色を簡単に拡張できます

// All you need to add `custom-purple` support to all your components is this line
let isCustomPurple = IsCustomColor "custom-purple"

✔️⚠️すべてのコンポーネントの例を含む優れたドキュメントがあると思いますが、すべてのコンポーネントに同じレベルの情報が含まれているわけではありません


✔️⚠️バンドルサイズへのフルマの影響は「安定」しています。 この点については、Feliz.Bulmaのセクションで説明しています。


⚠️人々は「特別なヘルパー」を簡単に見つけることができません。

  • CustomClass
  • 小道具
  • 修飾子

⚠️強い型のDSLがあるため、フルマコードはコードにノイズを追加します

例については、ここをクリックしてください

// 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コードは、 PropsModifiersを組み合わせるとネストされたリストがたくさんあるため、正しくフォーマットするのはそれほど簡単ではありません。


私はこの分析に2〜3週間取り組んできましたが、それでも続行できます。 でも、時間がかかって終わらせないといけないので、状況がよく見えてきたと思います。

言うまでもなく、特にFable.ReactとFulmaについては、もっと良い点や問題を挙げられる可能性がありますが、それは私にとって最も難しい部分でもあります。 私は3年以上使用して設計しているので、客観的に見るのは難しいです。

変換は難しかったですか?

Fable.ReactからFelizへの変換は簡単に行えました。 FelizはFable.Reactと互換性があり、ファイルごと、コンポーネントごとなど、プログレッシブな方法で変換を行うことができます。

すべてを確実に変換するために、すべてのopen Fable.Reactおよびopen Fable.React.Props命令を削除しました。 また、依存関係としてFulmaを削除しました。

もちろん、いくつかのファイルを忘れていたので、コンパイラのエラーを修正して、それが機能していました。

ここで、変換をホストしているマージリクエストを確認でき


フェリスとの私の旅

フェリスを最初に発見したとき、それは「HTML / JSXの方法」に従わず、それは私が多大な努力を費やしたものの代替プロジェクトであるため、防御的でした。

それから私は、それがイノベーションの仕組みであり、私たちが成長することを可能にするものであることを思い出しました。 たとえば、今日はエルミッシュがいます。

私が覚えているもう1つのことは、JSXは「実際のReact API」ではなく、実際、React APIはReact.createElementです。 JSXはその上にあるシンタックスシュガーであり、Fable.ReactとFelizにも同じことが言えます。 私にとってそれは私が前進し、それについて好奇心をそそるのを助けたので、私はそれを主張します。

Felizをテストするために、FableREPLである中規模のプロジェクトを使用することにしました。 Fable REPLは複雑なアプリケーションではありませんが、FableとReactの多くの機能を使用しています。

この決定のおかげで私がテストしたものの網羅的ではないリスト:

  • フェリス
  • Feliz.Bulma
  • FelizとFable.Reactの互換性
  • Fable.ReactからFelizへの移行はいかに簡単か
  • FelizからDOMへのネイティブ呼び出しによる機能コンポーネントの使用
  • JavaScriptで書かれた重要なカスタムコンポーネントとのバインディングと相互運用の方法Felizの方法
  • FulmaからFeliz.Bulmaへの移行。これにより、Fulmaの同等物がFelizエコシステムでどのようになるかを確認できます。

変換を開始したとき、コードのフォーマットがいかに簡単であるかを本当に嬉しく思いました。 フェリスベースのビューを書くための慣習は本当に従うのが簡単だと思います。 アプリケーションが大きくなるほど、コードのフォーマットが重要になります。

それから途中で、私は何かに悩まされ始めましたが、何を見つけることができませんでした。

Fable REPLをFelizに変換し終えましたが、それが好きかどうかはわかりませんでした。

私が自分の分析を結論付けようとしているのは今だけであり、何が私を妨げているのかを理解しています。 それはFelizとはあまり関係がありませんが、Feliz.Bulmaとはもっと関係があります。

2。5年以上の間、私はFulmaに取り組み、それを改善してきたことを覚えておくことが重要です。 フルマは私の最大のプロジェクトの1つです。 それを使ってコードを書くことは、特にすべてが入力され、コンポーネントの観点から考えることを余儀なくされるので素晴らしいです。

Feliz.Bulmaは別のアプローチを取り、Fulmaよりも若いです。 生後わずか5ヶ月です。

そうは言っても、今こそ私の結論に移る時だと思います:)

結論

フェリスの最大の利点はシングルリストスタイルだと思います。 これは私がよく言及したことですが、コードを簡単にフォーマットでき、次の行をどこから始めるべきかを考える必要がないことは大きなプラスです。

第二に、タイプセーフAPIは必須です。 これはCSSの同等のものよりも冗長ですが、優れた機能だと思います。 私はそれで派手なことをしなかったので、すべてがサポートされているかどうかはわかりませんが、そうでない場合は、いつでもPRを作成してそれを修正できます:)。

Feliz.Bulmaは、Felizを拡張する有望な方法を示していますが、Fulmaと直接同等になるほど成熟していません。 これは私が@Dzoukrでもっと探求したいことであり、Feliz.Bulmaの単純さとFulmaの完全性と冗長性の中間点を見つけることができることを願っています。

3年前、2017年3月8日、Tomas、Eugeneと私は、Fable.ArchとElmishを統合することを決定しました。 これにより、コミュニティとして、今日の素晴らしいエコシステムを構築することができました。

私たちは現在、FelizやFable.Reactと同じような時代を生きていると思います。 フェリスは寓話よりも牽引力が上がると思います。
しかし、両方が共存します。 結局、それらの両方は一緒にうまく機能します。これは、人々が使用したいものを選択できることを意味します。

私の分析を読んでくれてありがとう、そしてコメントセクションであなたとそれについて話し合うことを嬉しく思います:)

awesome blog

最も参考になるコメント

こんにちは@MangelMaxime

まず第一に、プロジェクトでフェリスを試すだけでなく、そのような広範な分析を書くために時間と労力を費やしてくれてありがとう。 寓話のユーザーの多くは、それが非常に有益で有益であると感じると確信しています。

この種のフィードバックとオープン性に本当に感謝しており、このライブラリをそのエコシステムとともに可能な限り最高のものにすることが重要であると信じています:pray:

Feliz.Bulmaはエコシステムの中で特別なものだと思うので、すぐに話します。まず、ライブラリを変更せずにすでに修正できるいくつかの問題に答えます。

onChange過負荷

どのイベントタイプが必要かを明示的に指定する必要があります。

実際には、あなたはしません。 タイプは、メッセージタイプから次のように推測する必要があります。

prop.onChange (ChangeGistToken >> dispatch)

ChangeGistTokenのタイプに応じて、正しい過負荷が推測されます。 DUの場合がChangeGistToken of string場合、 string -> unitのオーバーロードが選択されます。 ただし、入力タイプがfile場合はFileSelected of Fileになることもあります。その場合、オーバーロードFile -> unitが推測されます。 Fable.Reactからev.Valueのシンタックスシュガーは必要ありません

onChangeはすでにブールケースを処理しているため、prop.onCheckedChangeは削除されます

マルチ引数コールバック

@Shmewはすでにこの問題に触れており、実際、これがこれらのタイプのプロパティを解決する方法です。 Feliz拡張機能を実装する場合、プロパティを設定する前に変換を実行できることを理解することが重要です。

type myExtension = 
    static member inline extenstionProperty value = 
        // transform value here
        let transformedValue = doWeirdStuffWith value
        Interop.mkAttr "extenstionProperty" transformedValue

このロジックに従って、 'A -> 'B -> unitを内部でFunc<'A, 'B, unit>変換できます。

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

これは、 @ Shmewによって提供されるバージョンよりも明示的なバージョン正しく設定するには、常に少し遊んでおく必要があります)。 これの実用的な例はここにあり

フェリスエコシステムにおける型安全性

@Shmewが前述したように、適切なFeliz拡張機能では、正しく動作しないコードを記述できず、プロパティのタイプを制約することでそれを実装できます。 Feliz.RechartsのようにIReactPropertyを返すプロパティを構築して、 prop既存のプロパティとの下位互換性を確保するか、より特殊なタイプISpecialiedPropertyを実装してサポートすることができます。下位互換性を確保するために、一部のプロパティの名前をIReactPropertyから複製している間は、プロパティのサブセットのみを使用します。

type felizExtension = 
    static member inline specializedProp (value: string) : ISpecializedProperty = unbox (prop.text value) 

これは私がFeliz.AntDesignで行っていることです。たとえば、ここではいくつかのプロパティを複製してbuttonエントリポイントから利用できるようにしています(後で、プロパティを厳密な型でより特殊化することもできますが、最初は、下位互換性は最初に開始する場所です)。 Feliz.MaterialUIは、プロパティを特殊化するのではなく、 IReactPropertyを拡張するために同様のことを行うと思います。 これはFeliz.Bulmaの場合になります。

Feliz.Bulmaの場合

Feliz.Bulmaが実装される前は、CSSのみのフレームワーク用にFeliz拡張機能を構築する必要yieldを使用すると、さらに簡単になります。 これをTypedCssClassesと組み合わせると、CSSのみのフレームワークを実装する必要がなくなります。 実装とメンテナンスのコストはゼロです。 ドキュメントのWebサイトを自分で作成する代わりに、入力したスタイルシートを使用して、プロジェクト自体のすでに非常に優れたドキュメントを使用するだけです。

ただし、@ DzoukrによるFeliz.Bulmaの実装を見た後は、理に。Bulmaの1つのモジュールからCSSコンポーネントに特定の「エントリポイント」を導入して、 Bulma.buttonを取得することで、コードを大幅に簡素化できます。 Bulma.cardなど。これらは本当に使いやすいです。 モディファイアに関しては、Romanのアプローチは従い、操作しやすいと思いますが、あなたが言ったように、時にはそれが興味深い結果をもたらす可能性があります。 確かに、その部門にはさらに改善すべき点があります。いずれにせよ、Romanは、Felizのビジョンに従って、習得と使用が簡単なものを構築するのに素晴らしい仕事をしたと思います。

フェリスのパッケージ管理

現在のFable.ReactFeliz大きな違い、つまりパッケージのバージョン管理と管理について指摘したいと思います。 FelizバージョンはすべてのエコシステムライブラリがFemto互換であるため、必要なnpmパッケージを手動でインストールしたり、互換性のあるバージョンを知ったりする必要がなくなります。 これは、すべてではないにしても多くの派生Fable.Reactライブラリや、そうでない場合はFable.React自体とは異なります。

今後の計画

  • Felizスタイルの拡張機能を構築する方法と何に従うべきかについての(さらに多くの)ドキュメントを書く。
  • Feliz自体のために、しかしおそらくそのエコシステムのためにFelizアナライザーを構築する

全てのコメント23件

素晴らしい分析。

個人的には、ダブルリストのフォーマットが面倒なこともありますが、Fable.Reactコードを見ると、基になるhtmlの構造がよくわかります。 div [..、Html.div [....(など)ではありません。 それは大したことではありませんが、私の脳はFable.Reactをより簡単に解析できるようです。

@MangelMaximeを書いて

私が集めたものから、これの主なポイントは、主にライブラリの拡張方法に関する問題と、最適に行われなかった場合に発生する問題です。

Felizライブラリを作成すると、開発者の作業が大幅に増えることに間違いなく同意できますが、結果のAPIが非常に使いやすい場合は、努力する価値があると思います。

私はFelizに対してかなりの数の拡張機能を作成したので、これらの問題の多くを軽減する方法についていくつかの洞察を提供できると思います。

過負荷

Visual Studioを使用していますが、使用可能なオーバーロードを見つけるのに問題はありません。これは、ionide側で改善できるものでしょうか。

prop.text 、メンバーtoStringを必要とし、任意のタイプを受け入れる単一のインライン関数にすることができますか?

コールバック:

それ以外の:

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

書く:

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

その後、クライアント側で期待するようにプロパティを呼び出すことができます。

無効なコードを書く

私のライブラリのいくつかで私が持っている範囲でこれを完全に適用する人を見たことがなく、 Html拡張するときに完全に適用できるとは限りません。 これを防ぐ方法は、定義したプロパティにインターフェイスタイプを追加することです。これは、私の最大のFelizライブラリFeliz.Plotly 、次の場合にコンパイラエラーが発生するように設定しています。無効なプロパティを使用してみてください。 唯一の欠点は、ライブラリ開発者にとってかなりの作業になることです。


クリックして展開

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

同様に、必要に応じて、ライブラリコードに実装して、プロパティを「自動的に」組み合わせることができます。 ただし、自分のライブラリ以外のものを使用する場合、これがどのように機能するかはわかりません。 これの秘訣は、これらのアイテムを単なるIReactPropertyは異なるタイプにすることです。 たとえば、 Feliz.Plotlyでは、指定された構成に応じて、ユーザー入力を変更/収集/変更して、実際のコードが必要なものに適切に変換する多くのことを行います。 常に存在するものを削除することは、いくつかの点で本当に素晴らしいです。

結論

あなたが抱えていた苦痛の多くは、「フェリス」の方法で独自のライブラリを作成する方法についてのより良いドキュメントで解決できると思います。 たぶん@ Zaid-Ajajと私は将来それに取り組むことができます。

ありがとう@ l3m

個人的には、ダブルリストのフォーマットが面倒なこともありますが、Fable.Reactコードを見ると、基になるhtmlの構造がよくわかります。 div [..、Html.div [....(など)ではありません。 それは大したことではありませんが、私の脳はFable.Reactをより簡単に解析できるようです。

実際、コードの読み取り方法を切り替えるのは簡単ではありません。そのため、私の場合はHTMLとして表示すべきではないと述べたので、切り替えに役立ちました。

F#5と「静的クラスを開く」機能により、Felizは、Htmlクラスを開くかどうかに応じて、 Html.divdiv両方の構文をサポートできるようになると思います。

コメントをありがとう@Shmew 、そして確かに私はフェリスのための「ライブラリ」のいくつかのタイプがあることを忘れました。

「無効なコードの書き込み」についてはい。ただし、一部のライブラリでは、 Propsなどの特別なヘルパーを介して標準プロパティを渡す必要があるFulmaの状況を回避するために、 IReactPropertyタイプを「拡張」する必要があります。 Props 。 その理由は、Bulmaの「コンポーネント」はDOM要素の単なる特殊化であるためです。

これらは、HTML要素にデフォルトでクラスを挿入する単なるコードです。

Bulma.button<div class="button">

「実際の」コンポーネントで動作するライブラリの場合(申し訳ありませんが、別の名前を付ける方法がわかりません)、ソリューションは確かに正しいものです。 たとえば、これはFable.ReactLeafletが採用したアプローチであり、各コンポーネントの特定のプロパティを定義しています。 したがって、コンポーネントはすべての標準HTMLプロパティをサポートする必要はありません。

「コールバック」の解決策については、私にはうまくいきませんでした。 しかし、Fableによって渡された関数にはカレー引数があり、 myFunction(arg1)(arg2)ようなものを書きたくない限り、 System.Func介してカレーなしのバージョンを強制する必要がありました。

それを機能させる方法を知っているなら、 https://github.com/fable-compiler/repl/pull/108/filesでそれを修正するためにPRが送られるのを見てうれしいです

こんにちは@MangelMaxime

まず第一に、プロジェクトでフェリスを試すだけでなく、そのような広範な分析を書くために時間と労力を費やしてくれてありがとう。 寓話のユーザーの多くは、それが非常に有益で有益であると感じると確信しています。

この種のフィードバックとオープン性に本当に感謝しており、このライブラリをそのエコシステムとともに可能な限り最高のものにすることが重要であると信じています:pray:

Feliz.Bulmaはエコシステムの中で特別なものだと思うので、すぐに話します。まず、ライブラリを変更せずにすでに修正できるいくつかの問題に答えます。

onChange過負荷

どのイベントタイプが必要かを明示的に指定する必要があります。

実際には、あなたはしません。 タイプは、メッセージタイプから次のように推測する必要があります。

prop.onChange (ChangeGistToken >> dispatch)

ChangeGistTokenのタイプに応じて、正しい過負荷が推測されます。 DUの場合がChangeGistToken of string場合、 string -> unitのオーバーロードが選択されます。 ただし、入力タイプがfile場合はFileSelected of Fileになることもあります。その場合、オーバーロードFile -> unitが推測されます。 Fable.Reactからev.Valueのシンタックスシュガーは必要ありません

onChangeはすでにブールケースを処理しているため、prop.onCheckedChangeは削除されます

マルチ引数コールバック

@Shmewはすでにこの問題に触れており、実際、これがこれらのタイプのプロパティを解決する方法です。 Feliz拡張機能を実装する場合、プロパティを設定する前に変換を実行できることを理解することが重要です。

type myExtension = 
    static member inline extenstionProperty value = 
        // transform value here
        let transformedValue = doWeirdStuffWith value
        Interop.mkAttr "extenstionProperty" transformedValue

このロジックに従って、 'A -> 'B -> unitを内部でFunc<'A, 'B, unit>変換できます。

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

これは、 @ Shmewによって提供されるバージョンよりも明示的なバージョン正しく設定するには、常に少し遊んでおく必要があります)。 これの実用的な例はここにあり

フェリスエコシステムにおける型安全性

@Shmewが前述したように、適切なFeliz拡張機能では、正しく動作しないコードを記述できず、プロパティのタイプを制約することでそれを実装できます。 Feliz.RechartsのようにIReactPropertyを返すプロパティを構築して、 prop既存のプロパティとの下位互換性を確保するか、より特殊なタイプISpecialiedPropertyを実装してサポートすることができます。下位互換性を確保するために、一部のプロパティの名前をIReactPropertyから複製している間は、プロパティのサブセットのみを使用します。

type felizExtension = 
    static member inline specializedProp (value: string) : ISpecializedProperty = unbox (prop.text value) 

これは私がFeliz.AntDesignで行っていることです。たとえば、ここではいくつかのプロパティを複製してbuttonエントリポイントから利用できるようにしています(後で、プロパティを厳密な型でより特殊化することもできますが、最初は、下位互換性は最初に開始する場所です)。 Feliz.MaterialUIは、プロパティを特殊化するのではなく、 IReactPropertyを拡張するために同様のことを行うと思います。 これはFeliz.Bulmaの場合になります。

Feliz.Bulmaの場合

Feliz.Bulmaが実装される前は、CSSのみのフレームワーク用にFeliz拡張機能を構築する必要yieldを使用すると、さらに簡単になります。 これをTypedCssClassesと組み合わせると、CSSのみのフレームワークを実装する必要がなくなります。 実装とメンテナンスのコストはゼロです。 ドキュメントのWebサイトを自分で作成する代わりに、入力したスタイルシートを使用して、プロジェクト自体のすでに非常に優れたドキュメントを使用するだけです。

ただし、@ DzoukrによるFeliz.Bulmaの実装を見た後は、理に。Bulmaの1つのモジュールからCSSコンポーネントに特定の「エントリポイント」を導入して、 Bulma.buttonを取得することで、コードを大幅に簡素化できます。 Bulma.cardなど。これらは本当に使いやすいです。 モディファイアに関しては、Romanのアプローチは従い、操作しやすいと思いますが、あなたが言ったように、時にはそれが興味深い結果をもたらす可能性があります。 確かに、その部門にはさらに改善すべき点があります。いずれにせよ、Romanは、Felizのビジョンに従って、習得と使用が簡単なものを構築するのに素晴らしい仕事をしたと思います。

フェリスのパッケージ管理

現在のFable.ReactFeliz大きな違い、つまりパッケージのバージョン管理と管理について指摘したいと思います。 FelizバージョンはすべてのエコシステムライブラリがFemto互換であるため、必要なnpmパッケージを手動でインストールしたり、互換性のあるバージョンを知ったりする必要がなくなります。 これは、すべてではないにしても多くの派生Fable.Reactライブラリや、そうでない場合はFable.React自体とは異なります。

今後の計画

  • Felizスタイルの拡張機能を構築する方法と何に従うべきかについての(さらに多くの)ドキュメントを書く。
  • Feliz自体のために、しかしおそらくそのエコシステムのためにFelizアナライザーを構築する

実際には、あなたはしません。 タイプは、メッセージタイプから次のように推測する必要があります。

prop.onChange (ChangeGistToken >> dispatch)

確かに、私はこの使用法について考えていませんでした。

マルチ引数コールバック

@Shmewはすでにこの問題に触れており、実際、これがこれらのタイプのプロパティを解決する方法です。

申し訳ありませんが、@ Shmewによって提供されたスニペットの終わりが表示されませんでした。 私は署名宣言を見たばかりで、機能しないようでした。

あなたは両方とも正しいです、私たちは値をプロパティに渡す前に変換を行うことができます。

Feliz.Bulmaの場合

はい、TypedCssClassesは問題ありませんが、FulmaやFeliz.Bulmaと比較すると、同じレベルの機能を提供することはできません。 すべてがCSSファイルに含まれているわけではないからです。

もう1つは、開発モードでは、ファイルが常にディスク上に生成されるとは限らず、TypedCssClassesがこのシナリオをサポートしているかどうかがわかりません。

ローマンは、フェリスのビジョンに従って、学びやすく使いやすいものを構築するのに素晴らしい仕事をしたと思います。

私は同意します。同様にするために、Fulmaで行われた作業を少し追加する必要があると思います。 私が言ったように、私たちはそれらの両方の間の正しい中間点を見つける必要があります。

私が今考えている不足している機能は、出力要素を制御し、サポートされている色のセットを簡単に拡張できるようにすることです。 それほど複雑になるとは思いません。

@ Zaid-Ajajはフィードバックをありがとう、特にFelizの可能性を使用する方法について正しい方向を示してくれてありがとう。
私はFelizのドキュメントを実際に読んでいないことを認めます(それは私が知っているのは悪いことです)ので、おそらくそれらはそこに文書化されています。 そうでない場合は、追加する必要があることがいくつかわかっていると思います:)

@MangelMaximeに感謝しFantomasについて言及したことはありませんが、Fable.ReactまたはFelizのいずれかを使用してFantomasを操作する機会はありましたか?
Fantomasを使用しているFableプロジェクトの1つで、Ionideのファイル保存で自動フォーマットをオンにしました。これは、生産性を大幅に向上させるものであると言わなければなりません。手動フォーマットについて心配する必要はまったくありません。
Fantomasは今勢いを増しており、FableやReact / Felizと組み合わせて、より広く採用されることを望んでいます。

@theimowski私は

主な理由は、コードが混乱していて、読みづらくなったためです。 私の経験から、Fable.ReactとFelizでうまく遊んでいませんでした。

また、デフォルトのFantomasが気に入らないので、コードをインデントする方法がわかったら、後でもう一度確認する必要があります。 しかし、私がリポジトリを見たところ、コンテキストのサイズに応じてコードをフォーマットするFantomasが主な理由で、私のニーズに合うとは思いません。

たとえば、私がそのようなものを書いた場合:

type Test =
    {
        Prop1 : string
    }

1行に収まるからといって、そのままにしてtype Test = { Prop1 : string }ならないようにしたいと思います。

おそらくレコードは良い例ではありませんが、私が何を意味するのか理解していただければ幸いです:)

@theimowski聞い

@MangelMaximeあなたの仕事に感謝します。 どういうわけかあなたのフルマプロジェクトは私を寓話の世界に攻撃しました。 そして、私は本当に旅を楽しんでいます。

私は単一のリストも好きですが、クラスのメンバーのオーバーライドよりもDUも好きです。 DUがオーバーライドをサポートしているかどうか疑問に思うことがあります。
私はすでにFable.Reactをたくさん使用していますが、それでも単一のリストが必要なので、演算子>を作成し、次のように使用できます。

let myView =
    div </> [
        Classes [ ""; ""; "" ]
        Children [
              ...
        ]
    ]

演算子は非常にシンプルで、DUも利用できます。ここで、私の大まかな実装を確認できます: //github.com/albertwoo/Fun.LightForm/blob/master/src/Fun.LightForm.Fable/Fable.React。 Extra.fs

@ Zaid-Ajajすばらしい仕事をありがとう、私もいくつかのプロジェクトをFelizとFeliz.Materialに変換し始めました。

ありがとう!

こんにちは@MangelMaxime
まずはありがとうございます! 率直に言って、私が主にドッグフーディング自身のプロジェクトのために作成し、副作用として公開したライブラリを誰かがこれほど深く見るとは思っていませんでした。 「ねえ、@ Zaid-AjajがFelizをどのように設計したか、ブルマについても同じことをしよう」という最初の考えが膨らんだのはおかしい。

私はすでにFeliz.Bulmaリポジトリで新しい問題を作成しており、v2をさらに改善する方法について話し合うのが大好きです。 ほとんどの問題について合意しているようですので、 version2ブランチを開始しても問題はありません。 また、次のメジャーリリースのZaidの計画を確認すると、最新のメジャーバージョン間でAPIを100%互換性を保つのに便利です。

とにかく、もう一度ありがとう-素晴らしい分析!

リスクのある古い議論を再開される(!申し訳ありません)私はインデントの議論に私の2セントを追加したい-これは(多かれ少なかれ)である私たちが素敵な、一貫性のインデントを許容どの従っスタイリングとFable.Reactのために、以下のスタイル。

ただし、これが完全に当てはまらない1つの場所は、重要なスタイリングです。 しかし、私たちの経験では、これはごく少数の要素(おそらく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"
                ]
            ]
        ]
    ]
]

また、VSCodeやRainbowBracketsなどを使用している場合は、ブラケットの過負荷を回避するのに役立ちます。

他に考慮すべきこと(おそらく私は上記でこれを見逃した)は、GiraffeViewEngineがFable.Reactスタイル、つまり要素attr-list children-listを使用していることです。したがって、2つの間を移行する人々の観点から考える必要があります。

@ Zaid-AjajはFemtoについて良い点を述べています。 これをFable.Reactスタイルのコンポーネントで実装できなかった理由はありますか、それともFemtoが結合されているFelizスタイルに固有の何かがありますか?

これをFable.Reactスタイルのコンポーネントで実装できなかった理由はありますか、それともFemtoが結合されているFelizスタイルに固有の何かがありますか?

@isaacabraham

Fable.Reactから派生したライブラリは、Femtoメタデータを追加できます(また、追加する必要があります)が、Fable.React自体は、 reactreact-dom 、およびreact-native互換性のない組み合わせがあるため、追加できません@MangelMaximeパッケージの分割に関するいくつかの重大な変更が導入されるでしょう。

Fable.Reactから派生したライブラリにとってこれが意味することは、依存関係のnpmメタデータだけでなく、互換性のあるバージョンのreactreact-domも含める必要があるということです。 ( reactreact-domで始まるFelizとは異なり、Feliz拡張機能は必要なものだけを追加します)。 残念ながら、解決策がかなり前から存在しているとしても、これらのライブラリのいずれかが状況を改善するために主導権を握っているのを見たことがありません。

フォーマットについて:FantomasはまだDSLを適切な方法でフォーマットすることができず、リストのフォーマットを構成可能にするための作業が必要であるか、ReactDSLを適切なデフォルトを使用してフォーマットするための何らかの「Feliz-mode」フラグが必要です(と)

@ Zaid-Ajaj React npmの依存関係の問題も、Femtoを壊すことなく、reactの代わりにpreactを使用できるはずなので、より複雑です。

@ l3m確かに、しかしこの場合、このケースをサポートするためにFemtoに追加することができます。 それは私に何かを覚えているので、おそらくフェムトレポでそれについて問題があります(申し訳ありませんが今チェックする時間がありません^^)

@ l3m Preactは、Femto npmメタデータに関係なく、Reactの代わりに使用できます。既存のReactアプリケーションがある場合は、 Preactへの切り替えのガイドラインに従ってモジュールインポートエイリアスを構成するだけでよいためです。

純粋なPreactバインディング(100%非Reactコード)の構築はFelizの目標ではなく、おそらくPreactのみのバインディングが拡張されるスタンドアロンライブラリ(Feliz.PreactはFelizに依存しない)として実装する必要があります。 preact/compatから離れたい場合に使用します

@ Zaid-Ajaj現在、Elmishアプリでpreactを使用していますが、うまく機能します。 Femtoがpackages.jsonを変更するのを警戒していたのですが、React depsのあるnugetが表示された場合は、それを強調したいと思いました。 それが問題でなければ、なおさらです。

また、 preact/compatは、最新のpreactでは不要になり、コアになりました。

危険にさらされているのは、古い議論を再開することです(申し訳ありません!)インデントの議論に2セントを追加したかっただけです-これは(多かれ少なかれ)私たちが従うスタイリングであり、Fable.Reactの素晴らしい一貫した識別とフォローを可能にしますスタイル。

私はIsaacと非常によく似た方法でコードをインデントしており、かなり読みやすくなっています。
物事を行う単一のリストの方法と比較するのは難しいことを私は知っていますが、元の投稿のインデントは、よりよく比較するために彼のコードに似たものを反映している可能性があります。

F#5と「静的クラスを開く」機能により、Felizは、Htmlクラスを開くかどうかに応じて、 Html.divdiv両方の構文をサポートできるようになると思います。

それはとてもクールだろう。 Htmlクラスを静的にして開くことができるようにすることは可能でしょうか?

@ fc1943s Htmlprop 、およびstyleはすべて静的クラスです。 ただし、F#5で機能が利用可能になったときにそれらを開くことはお勧めしません。これは、ポイント全体に、その静的クラス内で利用可能な関数へのグループ化と検出のエントリポイントがあるためです。

静的クラスを開くと、検出がどのように妨げられますか? それでもFeliz.Htmlと入力できます。

@MaxWilsonMS 「最終的な」コードを出力するには、追加の手順が必要でした。

そして、 Feliz.Html.divを書き込んでから、奇妙に思えるFeliz.Html.部分を消去します。

良い点は、ユーザーが好みに応じて静的クラスを開くかどうかを選択できることです。 :)

上で述べたことを繰り返しているので、これがどれほど役立つかはわかりませんが、完全な初心者としての経験:

  • インデントにはFelizアプローチが好きです。 Isaacが提案したのと同様のアプローチを試しましたが、インデントがすべて2s / 4sであるとは限らないため、「私は時々それについて考えることに時間を費やします」。 フェリスと一緒に、私はそれについて考えるのに全く時間を費やしません。

  • カスタム要素を作成する場合は、今のところFable.Reactの方法で作成します。 私は「フェリスの方法」で物事を構築することを検討し、すぐに逃げました(いつか再訪します!)。

  • ドキュメントが「これがカスタムプロパティを作成する方法です」という側面をより定期的に優先する場合、私は本当に便利だと思います。 ほんの数人の作者だけで、これらのライブラリはCSSで可能なすべてのAPIサーフェスを提供するのに苦労することがよくあることを受け入れるのは公正だと思います(たとえば)。したがって、初心者が「fontSize」を設定できないときに行き詰まった場合「em」にあるか、「grid-template-rows」が見つからないか、「Screen.All」引数を提供することが期待されているかどうかわからない-回避方法を知っていればよいでしょう。

  • いくつかの潜在的な懸念を削ぎ落とし始めるいくつかの「生活の質」の改善が行われる可能性があると思います...たとえば、フェリスのスタイル小道具の長い垂直リストを見ると、 style.paddingHorizontalがあるかどうか疑問に思い始めますstyle.paddingVertical 。 私は自分でヘルパーを作ることができることを理解していますが、ここは機能をリクエストする場所ではなく、標準ではないものを導入することを避けたいと思うかもしれません:)

  • 新しいF#でHtml静的クラスを開くというアイデアが好きです。 批判的に-私の同僚は私の肩越しにそれを理解することができるでしょう-そして私はより多くの人々を巻き込むことが重要だと思います。 悪魔の代弁者を演じるには: divは入力に時間がかからず、それを発見する必要がある場合、これは魔法を実行しているセットアップを使用するときに私が直面するであろう課題の中で最も少ないものです。 Javascript、React、CSSなどを私から隠します。 ただし、一般的に、APIの検出可能性は優れています。

  • 特にスタイルのトランジション/アニメーションの場合、Felizの方法は非常に理にかなっています。

  • より一般的でおそらく接線的:私が一貫して直面している課題は、エルミッシュの世界がどこで終わり、Reactの世界がどこから始まるのかを理解することです。 これはどちらのライブラリの問題でもありませんが、Reactについて最も曖昧な手がかりがないため、Fable.ReactまたはFelizから関数コンポーネントを取得できるという事実は私を混乱させます。 もちろん、これを学ぶことは私の責任ですが、言及する価値があると思いました。 私は現在、ElmishとReactのアプローチを組み合わせており、これによりすべてのコンポーネントが更新時に再レンダリングされると思いますが、このような完全に構築されたアプリの例は次のとおりであるため、これを回避するための「正しい」方法がわかりません。見つけにくい。 最初にJavascriptでプロダクショングレードのReactアプリを作成し、次にFable / Elmishに移行することを学ぶ必要があるという印象を受けることがありますが、それは参入障壁のかなり重要なように感じます。 免責事項:私はFelizのドキュメントをあまり読んでいませんが、それは本当に良いことです-ですから、これはおそらく私にあります!

これらのライブラリを共有してくれたすべての人に感謝します!

ご入力いただきありがとうございます@ drk-mtr!

カスタム要素を作成する場合は、今のところFable.Reactの方法で作成します。 私は「フェリスの方法」で物事を構築することを検討し、すぐに逃げました(いつか再訪します!)。

ええ、最初はかなり気が遠くなるように見えるかもしれませんが、慣れればかなり簡単です。 そうは言っても、ライブラリを作成するときの開発者にとってはかなりの初期費用です。 大多数のユーザーがライブラリを作成することはないので、これはかなり許容できるトレードオフだと思います。 幸いなことに、作業自体は非常に単純であり、コピーと貼り付けを行うと、多くの作業を高速化できます(または、私たちのように、コードをビルドするためのジェネレーターを作成することもできます)。

ドキュメントが「これがカスタムプロパティを作成する方法です」という側面をより定期的に優先する場合、私は本当に便利だと思います。 ほんの数人の作者だけで、これらのライブラリはCSSで可能なすべてのAPIサーフェスを提供するのに苦労することがよくあることを受け入れるのは公正だと思います(たとえば)。したがって、初心者が「fontSize」を設定できないときに行き詰まった場合「em」にあるか、「grid-template-rows」が見つからないか、「Screen.All」引数を提供することが期待されているかどうかわからない-回避方法を知っていればよいでしょう。

あなたが気付いていない場合に備えて(私はこの文脈からは完全にはわかりませんでした):

prop styleタイプとcustomメソッドがあります。

ICssUnitを受け入れるものはすべて、次のように設定できます: style.fontSize (length.em 1)

ドキュメントの更新は簡単なはずです。

いくつかの潜在的な懸念を削ぎ落とし始めるいくつかの「生活の質」の改善が行われる可能性があると思います...たとえば、フェリスのスタイル小道具の長い垂直リストを見ると、style.paddingHorizo​​ntalとstyle.paddingVertical。 私は自分でヘルパーを作ることができることを理解していますが、ここは機能をリクエストする場所ではなく、標準ではないものを導入することを避けたいと思うかもしれません:)

私の本では、ユーザーエクスペリエンスを容易にするのに役立つものは何でも大歓迎です。 私はあなたが気づいたこれらの事柄のいずれかの問題/広報を見たいです!

より一般的でおそらく接線的:私が一貫して直面している課題は、エルミッシュの世界がどこで終わり、Reactの世界がどこから始まるのかを理解することです。 これはどちらのライブラリの問題でもありませんが、Reactについて最も曖昧な手がかりがないため、Fable.ReactまたはFelizから関数コンポーネントを取得できるという事実は私を混乱させます。 もちろん、これを学ぶことは私の責任ですが、言及する価値があると思いました。 私は現在、ElmishとReactのアプローチを組み合わせており、これによりすべてのコンポーネントが更新時に再レンダリングされると思いますが、このような完全に構築されたアプリの例は次のとおりであるため、これを回避するための「正しい」方法がわかりません。見つけにくい。 最初にJavascriptでプロダクショングレードのReactアプリを作成し、次にFable / Elmishに移行することを学ぶ必要があるという印象を受けることがありますが、それは参入障壁のかなり重要なように感じます。 免責事項:私はFelizのドキュメントをあまり読んでいませんが、それは本当に良いことです-ですから、これはおそらく私にあります!

寓話の世界(フェリス以前)での私の経験では、ほとんどの場合、すべてを通常の関数として記述していました(.fsごとに1つのコンポーネントのように)。 その結果、Reactシステムが提供する多くのメリットを失いました。 Felizから始めてから、Reactがどのように機能するかについてもっと深く掘り下げなければなりませんでした(良いことです)。 慣れてきたので、意識的に考えることすらありません。 レンダリングを行う私が作成するすべての関数は、関数コンポーネントです。

Reactを慣用的に書く方法を本当に学びたいのなら、Elmishを使用せず、デモアプリで関数コンポーネント/フックのみを使用するように制限するのと同じくらい簡単だと思います。 APIはほぼ同じであるため、JSで記述されたものを簡単にフォローできます。

Felizで書かれた高品質のオープンソースアプリケーションを持つことは間違いなく有益なことです。私はしばらく前にその問題を作成しました#67。 現在最も近いのは、おそらくドキュメントアプリ自体、または@cmeerenElectronDemoです。

このページは役に立ちましたか?
0 / 5 - 0 評価