Feliz: Faire de Feliz une API abstraite

Créé le 19 déc. 2020  ·  15Commentaires  ·  Source: Zaid-Ajaj/Feliz

Je suis sur le point de proposer un changement de rupture, mais j'espère qu'il ne nécessite que les utilisateurs finaux et les auteurs de bibliothèques pour mettre à jour les packages et aucun changement de code réel.

  1. F# est un excellent langage pour déclarer des interfaces utilisateur
  2. Chaque développeur F# qui fait quelque chose en rapport avec le Web écrit son propre DSL pour déclarer les interfaces utilisateur
  3. Feliz est une excellente API/DSL pour déclarer les interfaces utilisateur Web React

Et si on supprimait "React" de 3 ? Cela pourrait résoudre de nombreux problèmes :

  • Feliz pourrait devenir un standard et résoudre 2 dans la liste ci-dessus. Ainsi, la plupart des composants écrits avec Feliz pourraient automatiquement être utilisés avec différents moteurs de rendu
  • Cela peut également éviter la dépendance Fable.React comme discuté dans # 285 (Fable.React implémenterait IViewElement pour garder la compatibilité)
  • Cela pourrait également faciliter l'écriture d'un moteur de rendu Feliz côté serveur sans avoir à utiliser #if FABLE_COMPILER partout comme avec Fable.React
  • Il peut arriver que quelqu'un quelque part écrive un moteur de rendu frontal directement dans Fable. Ce serait génial s'il pouvait juste utiliser Feliz

Une fois le pitch d'ascenseur terminé, si vous pensez que c'est une bonne décision, nous pouvons discuter de la mise en œuvre. Je n'ai encore rien essayé, donc je ne sais pas comment cela pourrait fonctionner, mais ce que j'ai en tête, c'est quelque chose comme ça :

type IViewElement = interface end
type IViewProp = interface end

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

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

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

// Then we have different implementations
module Feliz.React

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

let Html = Feliz.ReactHTML()

// Consumer code
open Feliz.React

Html.div [...]

Je ne sais pas comment fonctionnerait intellisense, nous devons peut-être utiliser une classe abstraite au lieu d'une interface, mais j'espère que vous comprenez l'idée. Qu'est-ce que tu penses?

Commentaire le plus utile

@alfonsogarciacaro Cela a l'air incroyable. Comme mentionné dans #262, la seule chose qui me manque vraiment, vraiment depuis le passage de Fable.React à Feliz, c'est le SSR "ça marche juste". Feliz et Feliz.ViewEngine sont des projets incroyables, mais avoir deux projets différents rend la réutilisation du code difficile, car tout morceau de code qui utilise les ifdefs ne peut être utilisé que par un autre code qui utilise les ifdefs - créant des silos pour js-only, dotnet- code seul et des deux mondes. Tout ce qui comblerait cet écart améliorerait certainement la qualité de vie lorsque vous travaillez avec des serveurs Feliz et .Net.

Tous les 15 commentaires

Salut @alfonsogarciacaro , pour être honnête avec vous, je n'ai pas l'impression que c'est une bonne idée. Théoriquement, cela a du sens bien sûr : construisons une API standard pour HTML dans Fable. En pratique, cela ne se traduit pas très bien. Voici quelques raisons :

  • L'API actuelle est tout sauf standard, en fait elle est très opiniâtre. Beaucoup de gens n'aiment toujours pas toute la liste et le prop.children ce qui est bien sûr tout à fait correct.
  • L'API actuelle est rendue "simple" parce qu'elle part du principe qu'elle est uniquement React : l'abstrait nécessiterait BEAUCOUP de travail où l'alternative d'écrire/dupliquer une API de style Feliz serait probablement la solution la plus simple.
  • Je préfère me concentrer sur l'amélioration de l'outillage autour de React plutôt que de disperser les ressources : Feliz est loin d'être « terminé », il reste encore beaucoup à faire concernant la documentation, les exemples d'applications, une meilleure histoire de test, etc.

Merci beaucoup pour la réponse @Zaid ! Je comprends votre raisonnement, c'est quand même dommage que nous ayons autant de DSL concurrents mais peut-être qu'il y a d'autres solutions comme vous le dites. Si je trouve le temps, j'essaierai d'écrire un prototype de toute façon pour voir comment cela fonctionnerait.

BTW, j'ai commencé quelques travaux ici : https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/src/HtmlEngine.fs

Je ne l'ai pas testé, mais j'ai supprimé tous les unbox et astuces similaires, donc en principe, cela "devrait" fonctionner avec n'importe quel moteur de rendu qui implémente cette interface . Ce serait bien, par exemple, d'essayer de combiner un moteur de rendu React avec @dbrattli Feliz.ViewEngine et de voir si cela simplifie la SSR avec Feliz.

Il y a plusieurs choses à comprendre/considérer :

Intellisense

Je ne suis pas super content que mon intellisense ait l'air génial puisque Html serait défini dans Feliz comme :

let Html = HtmlEngine(renderer)

C'est plus un problème mineur cependant.

Taille du paquet

Nous voudrions évidemment que ce soit le même qu'il est actuellement (ou mieux). Peut-être un plugin dans Feliz.HtmlEngine qui est enveloppé dans les directives du compilateur ? Cette solution rendrait cependant les serveurs Web dépendants de Fable.

Autres bibliothèques

L'un des plus gros problèmes avec le SSR tel qu'il est actuellement fait est que dans la plupart des cas, les autres bibliothèques ne fonctionneront tout simplement pas, et celles qui le font (comme Feliz.Bulma / Feliz.Bulma.ViewEngine ) ont encore besoin d'ajustements à moins qu'elles aussi construisez une API abstraite pour que les deux fassent référence de manière similaire à ce que c'est.

Alternatives

Je pense que le problème fondamental ici est qu'essayer de faire de la SSR nous-mêmes n'est pas super faisable lorsque nous voulons émuler pleinement la première peinture prévue. Ce dont nous avons vraiment besoin, c'est de quelque chose comme ReactDOMServer pour .NET. Je n'ai pas vraiment approfondi cela, mais React.NET (peut-être avec un wrapper F#) serait-il une meilleure voie à suivre ?

Merci beaucoup pour les commentaires @Shmew et désolé d'avoir répondu tardivement :

  • Intellisense : Hmm, je n'ai écrit qu'un exemple simple avec l'API abstraite mais je n'ai vu aucun problème avec l'autocomplétion. Je vais essayer de vérifier à nouveau. Au lieu d'accéder à un type statique, les utilisateurs accèdent à une valeur. Je suppose que ça devrait aller et dans de nombreux cas, le code n'aura pas besoin de changer. Le principal inconvénient serait probablement que open type ne peut pas être utilisé.
  • Taille du paquet : Je dois également vérifier cela. J'espère que cela ne changera pas beaucoup parce que les membres de la classe sont compilés par Fable en tant que fonctions détachées qui peuvent être secouées par l'arbre et également bien minimisées. Bien que malheureusement le code généré ne soit pas aussi beau qu'il l'est maintenant après #284
  • Autres bibliothèques : Oui, d'autres bibliothèques devraient être adaptées pour tirer parti d'une API abstraite. Espérons avec des changements minimes.
  • Alternatives : TBH, je ne sais pas vraiment comment fonctionne SSR avec React, bien qu'en regardant le code (contribué) dans Fable.React cela n'a pas l'air très compliqué (en gros, il suffit d'ajouter des métadonnées aux balises html générées) donc pas sûr s'il est plus facile d'utiliser quelque chose comme React.NET ou non. Je suppose que cela ne sera pas non plus utilisable avec Feliz, car Feliz contient des astuces Fable (principalement des castings dangereux) qui lanceront .NET.

En fait, pour cela, je pense non seulement à SSR mais aussi à _beyond React_ :wink:, par exemple pour les générateurs html dans les serveurs F# qui n'ont pas nécessairement besoin d'être compatibles avec React et dans le cas où nous souhaitons utiliser d'autres moteurs de rendu que Réagissez pour le frontend.

Merci beaucoup pour les commentaires @Shmew et désolé d'avoir répondu tardivement

De rien, et pas de soucis !

Intellisense : Hmm, je n'ai écrit qu'un exemple simple avec l'API abstraite, mais je n'ai vu aucun problème avec la saisie semi-automatique. Je vais essayer de vérifier à nouveau. Au lieu d'accéder à un type statique, les utilisateurs accèdent à une valeur. Je suppose que ça devrait aller et dans de nombreux cas, le code n'aura pas besoin de changer. Le principal inconvénient serait probablement que le type ouvert ne peut pas être utilisé.

Désolé, je n'ai pas été très clair. Intellisense est bien, mais plutôt le fait que Html serait une couleur différente. Comme je l'ai dit, vraiment mineur . Le fait que nous perdions la possibilité de open type est en fait un peu plus important. Je sais que certains préfèrent vraiment cela plutôt que d'avoir à tout espacer.

Taille du paquet : je dois également vérifier cela. J'espère que cela ne changera pas beaucoup parce que les membres de la classe sont compilés par Fable en tant que fonctions détachées qui peuvent être secouées par l'arbre et également bien minimisées. Bien que malheureusement le code généré ne soit pas aussi beau qu'il l'est maintenant après #284

Je n'avais même pas réalisé que les fonctions d'interopérabilité n'étaient pas déjà intégrées, je les ai déjà intégrées dans mes bibliothèques. Je parlais plus du fait que l'ensemble du module Html n'a pas d'augmentation de la taille du bundle par rapport à s'il était fait nativement dans JS, car il ne s'agit que d'un wrapper en ligne. Avec une classe concrète qui ne devient plus le cas.

Autres bibliothèques : Oui, d'autres bibliothèques devraient être adaptées pour tirer parti d'une API abstraite. Espérons avec des changements minimes.

Le problème avec ceci est que les bibliothèques qui utilisent du code de réaction natif ne peuvent pas fonctionner correctement car tous les composants internes sont uniquement JS.

Alternatives: TBH, je ne sais pas vraiment comment fonctionne SSR avec React, bien qu'en regardant le code (contribué) dans Fable.React, cela n'a pas l'air très compliqué (en gros, il suffit d'ajouter des métadonnées aux balises html générées) donc pas sûr s'il est plus facile d'utiliser quelque chose comme React.NET ou non. Je suppose que cela ne sera pas non plus utilisable avec Feliz, car Feliz contient des astuces Fable (principalement des castings dangereux) qui lanceront .NET.

Oui, cela fonctionne pour des cas Feliz.MaterialUI cela ne fonctionnera tout simplement pas. D'après ce que je comprends, React SSR est assez simple lorsqu'il est effectué sur node.js car ils peuvent simplement exécuter le ReactDOMServer pour réellement cracher une chaîne complète qui est la première peinture de la page. D'après ce que j'ai compris, React.NET enveloppe simplement un processus node.js pour faire exactement cela.

Je soupçonne que ce serait en fait assez facile avec le code Feliz car il prend déjà en charge ce genre de choses. Le processus serait quelque chose comme :

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

au-delà de Réagir

C'est un excellent point, et certainement quelque chose que je voudrais si je cherchais à rendre du HTML pur sans React ou quoi que ce soit.

J'ai expérimenté cette idée, vous pouvez voir mes progrès ici : https://github.com/alfonsogarciacaro/Feliz.Engine

Il y a encore du travail à faire et j'ai quelques doutes sur certaines choses, mais cela fonctionne déjà et couvre la plupart de l'API Feliz. Cependant, j'ai dû faire quelques changements donc c'est vrai que ça va être difficile de remplacer Feliz par quelque chose comme ça. Mais il y a toujours de la valeur à avoir une version abstraite de Feliz, car elle ouvre de nombreuses possibilités. Quelques exemples:

  1. Utilisez-le avec d'autres frameworks frontend, comme Sutil : https://github.com/davedawkins/Sutil/pull/15
  2. Utilisez-le pour générer du CSS au lieu du SASS : https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Css/Feliz.Css.fs
  3. Utilisez-le pour générer du HTML statique : https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.StaticHtml/Feliz.StaticHtml.fs
  4. Utilisez-le avec une autre implémentation de dom virtuel, comme Snabbdom : https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Snabbdom/Feliz.Snabbdom.fs

Ce sont tous des brouillons, mais ils fonctionnent et vous pouvez voir qu'ils nécessitent très peu de code. Plus important encore, ils offrent tous une API documentée et familière aux utilisateurs, qui est également extensible : par exemple, vous pouvez facilement créer un BulmaEngine compatible avec toutes ces applications (et futures). Dans le cas de 2. et 3. J'utilise Fable car la compilation incrémentielle est beaucoup plus rapide qu'avec .NET mais Feliz.Engine est compatible avec .NET (j'ai supprimé tous les unbox ) donc ça devrait être trivial pour les rendre compatibles avec les serveurs F# .NET, et j'espère que cela ne devrait pas nécessiter beaucoup de travail pour rendre le générateur HTML compatible avec React également.

Qu'en penses-tu @Zaid-Ajaj ? J'ai déjà abandonné l'idée de remplacer l'API Feliz React actuelle 😅 Êtes-vous d'accord avec le nom, ou préférez-vous utiliser autre chose ?

Salut @alfonsogarciacaro , je vais me plonger dans ces échantillons cette semaine et j'y reviendrai à coup sûr

Bonjour,

J'ai jeté un coup d'œil très rapide au code et il semble que cette version abstraite aura un impact sur la taille du bundle. Je voulais juste le souligner car c'était l'une des caractéristiques de Feliz dans sa forme actuelle.

Oui, un impact est attendu, la question est de savoir quelle est sa taille :) J'espère que pour les applications moyennes-grandes, ce n'est pas très perceptible, mais bien sûr, ce serait bien d'avoir quelque chose comme fulma-demo dans les deux styles, donc nous peut comparer et utiliser pour tester les opportunités d'optimisation. Il serait également intéressant de vérifier dans quelle mesure les assistants d'intégration ou non de Feliz affectent la taille du paquet. À l'heure actuelle, le code généré par Feliz est plutôt sympa et ressemble beaucoup à du JSX compilé, mais les fonctions peuvent être minimisées, ce qui pourrait être un moyen de réduire la duplication de nombreux appels comme .createElement("div") (je ne sais pas si gzip peut compresser ces appels cependant).

Ouais, je ne peux pas imaginer que quelqu'un s'opposerait à pouvoir utiliser ce merveilleux API/style dans d'autres projets. Mes seules vraies préoccupations étaient de savoir si cela aurait un impact sur la qualité de cette bibliothèque et sur certains des problèmes ergonomiques que j'ai décrits ci-dessus.

Salut @alfonsogarciacaro , j'ai bien regardé l'exemple de code. J'ai été surpris de voir que le moteur css et le moteur html statique sont tous deux des applications uniquement nodejs car ils utilisent des flux node.js. Bien que l'idée soit intéressante, j'ai du mal à me voir utiliser l'un des éléments ci-dessus :

  • Le CssEngine génère du CSS, quel est l'avantage de cela par rapport à l'utilisation de chaînes d'outils CSS/SASS ou CSS-in-JS comme celle intégrée à Feliz ou d'autres bibliothèques CSS-in-JS comme FSS ou Emotion. Générer du CSS à partir de F# fonctionnerait tout seul, mais ce n'est pas quelque chose que j'utiliserais avec Feliz car s'appuyer sur les chaînes d'outils existantes serait un meilleur choix (également des temps de compilation plus rapides si vous ne voulez pas que le compilateur Fable/F# soit ralenti en ayant pour compiler d'énormes feuilles de style) Actuellement, je suis plus en faveur de l'utilisation de modules CSS pour les composants Feliz/React
  • Le moteur html statique : Feliz génère déjà du html statique en utilisant ReactDOM dans le nœud et dans le navigateur. Feliz.ViewEngine fait de même pour générer du HTML statique dans dotnet. Je sais que l'idée est de partager l'API, mais cela est rendu difficile par d'autres défis, comme @Shmew l'a mentionné : les bibliothèques tierces devant implémenter les deux ont un impact sur le code généré qui est maintenant vraiment propre. Il mélange également les attributs, les styles et les enfants dans une seule liste qui brise l'API actuelle de Feliz.
  • Moteur Snabbdom : exemple intéressant mais n'ayant pas l'écosystème des librairies comme le fait React.

Bref, un exercice intéressant. Pour être honnête avec vous, je ne suis pas un grand fan de la nouvelle API et je préférerais personnellement passer du temps à améliorer l'expérience actuelle avec plus de documents, d'exemples et de liaisons dans React au lieu d'essayer de standardiser les bibliothèques. Désolé si je suis un peu négatif à ce sujet, vous y avez probablement beaucoup travaillé. Cela ne me dérange pas d'avoir le même nom que Feliz puisqu'il a été inspiré par la bibliothèque.

Merci beaucoup d'avoir vérifié les échantillons @Zaid-Ajaj ! J'apprécie votre honnêteté. Les imprimantes css et html n'étaient que des exemples rapides pour vérifier à quel point il était facile/difficile d'adapter Feliz.Engine aux utilisations potentielles (le code pour faire l'impression ne fait que 50 lignes). J'ai utilisé Fable & node car la compilation incrémentielle est beaucoup plus rapide, mais "en principe" il devrait être facile de l'adapter à .net. L'adaptateur Snabbdom était censé être aussi un autre exemple rapide mais je commence en fait à aimer, même si c'est une autre affaire :)

Quoi qu'il en soit, j'ai finalement réalisé qu'il ne serait pas possible d'abstraire les applications Feliz React actuelles sans casser les modifications (comme vous le disiez depuis le début 😅) alors gardons-le comme projet parallèle pour les utilisateurs qui souhaitent essayer d'autres moteurs de rendu avec une API de type Feliz 👍

@alfonsogarciacaro Cela a l'air incroyable. Comme mentionné dans #262, la seule chose qui me manque vraiment, vraiment depuis le passage de Fable.React à Feliz, c'est le SSR "ça marche juste". Feliz et Feliz.ViewEngine sont des projets incroyables, mais avoir deux projets différents rend la réutilisation du code difficile, car tout morceau de code qui utilise les ifdefs ne peut être utilisé que par un autre code qui utilise les ifdefs - créant des silos pour js-only, dotnet- code seul et des deux mondes. Tout ce qui comblerait cet écart améliorerait certainement la qualité de vie lorsque vous travaillez avec des serveurs Feliz et .Net.

Oui. ce serait un excellent cas d'utilisation. C'est délicat car à la fin, Feliz.Engine a quelques différences avec Feliz, ce qui signifie que nous devrions écrire une implémentation Feliz.Engine React qui concurrencerait Feliz lui-même, quelque chose que j'aimerais éviter ;) Mais j'espère que nous pourrons trouver un Solution.

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

alfonsogarciacaro picture alfonsogarciacaro  ·  6Commentaires

Zaid-Ajaj picture Zaid-Ajaj  ·  8Commentaires

nojaf picture nojaf  ·  4Commentaires

l3m picture l3m  ·  7Commentaires

Dzoukr picture Dzoukr  ·  9Commentaires