Feliz: Haz de Feliz una API abstracta

Creado en 19 dic. 2020  ·  15Comentarios  ·  Fuente: Zaid-Ajaj/Feliz

Estoy a punto de proponer un cambio importante, pero con suerte, uno que solo requiera que los usuarios finales y los autores de la biblioteca actualicen los paquetes y no se realicen cambios en el código.

  1. F # es un gran lenguaje para declarar UI
  2. Cada desarrollador de F # que hace algo relacionado con la web escribe su propio DSL para declarar IU
  3. Feliz es una gran API / DSL para declarar interfaces de usuario web React

¿Qué pasa si eliminamos "React" de 3? Esto podría resolver muchos problemas:

  • Feliz podría convertirse en un estándar y resolver 2 en la lista anterior. Por lo tanto, la mayoría de los componentes escritos con Feliz podrían usarse automáticamente con diferentes motores de renderizado.
  • Esto también puede evitar la dependencia de Fable.React como se discutió en # 285 (Fable.React implementaría IViewElement para mantener la compatibilidad)
  • Esto también podría facilitar la escritura de un renderizador Feliz del lado del servidor sin tener que usar #if FABLE_COMPILER todas partes como con Fable.
  • Puede suceder que alguien en algún lugar esté escribiendo un renderizador de frontend directamente en Fable. Sería genial si pudiera usar Feliz

Una vez hecho el discurso del ascensor, si cree que esta es una buena medida, podemos discutir la implementación. Todavía no he probado nada, así que no estoy seguro de cómo podría funcionar, pero lo que tengo en mente es algo como esto:

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

No estoy seguro de cómo funcionaría intellisense, tal vez necesitemos usar una clase abstracta en lugar de una interfaz, pero espero que entiendas la idea. ¿Qué piensas?

Comentario más útil

@alfonsogarciacaro Esto se ve increíble. Como se mencionó en el n. ° 262, lo único que realmente extraño desde que cambié de Fable.React a Feliz es el SSR 'simplemente funciona'. Tanto Feliz como Feliz.ViewEngine son proyectos increíbles, pero tener dos proyectos diferentes dificulta la reutilización del código, ya que cualquier fragmento de código que use ifdefs solo puede ser usado por otro código que use ifdefs - creando silos solo para js, dotnet- código único y de ambos mundos. Cualquier cosa que cierre esa brecha ciertamente mejoraría la calidad de vida cuando se trabaja con servidores Feliz y .Net.

Todos 15 comentarios

Hola @alfonsogarciacaro , para ser honesto contigo, no creo que sea una buena idea. Teóricamente tiene sentido, por supuesto: construyamos una API estándar para HTML en Fable. En la práctica, eso no se traduce muy bien. Aquí hay un par de razones:

  • La API actual es cualquier cosa menos estándar, de hecho, tiene muchas opiniones. A muchas personas todavía no les gusta la lista completa y prop.children lo cual, por supuesto, está totalmente bien.
  • La API actual se hace "simple" porque se asume que es solo de React: abstraerla requeriría MUCHO trabajo donde la alternativa de escribir / duplicar una API de estilo Feliz probablemente sería la solución más fácil.
  • Prefiero concentrarme en mejorar las herramientas en React en lugar de distribuir los recursos: Feliz está lejos de "terminar", todavía hay mucho por hacer con respecto a la documentación, las aplicaciones de muestra, una mejor historia de pruebas, etc.

¡Muchas gracias por la respuesta @Zaid! Entiendo tu razonamiento, sigue siendo una pena que tengamos tantos DSL en competencia, pero tal vez haya otras soluciones, como dices. Si encuentro tiempo, intentaré escribir un prototipo de todos modos para ver cómo funcionaría.

Por cierto, he comenzado a trabajar aquí: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/src/HtmlEngine.fs

No lo he probado, pero he eliminado todos los unbox y trucos similares, por lo que en principio "debería" funcionar con cualquier renderizador que implemente esta interfaz . Sería bueno, por ejemplo, intentar combinar un renderizador React con @dbrattli Feliz.ViewEngine y ver si hace SSR más simple con Feliz.

Hay un par de cosas que deberían ser resueltas / consideradas:

Intellisense

No estoy muy contento de que mi intellisense se vea funky ya que Html se definiría en Feliz como:

let Html = HtmlEngine(renderer)

Sin embargo, eso es un problema menor.

Tamaño del paquete

Obviamente, querríamos que esto sea lo mismo que es actualmente (o mejor). ¿Quizás un complemento en Feliz.HtmlEngine que está envuelto en directivas del compilador? Sin embargo, esta solución haría que los servidores web tuvieran una dependencia de Fable.

Otras bibliotecas

Uno de los mayores problemas con SSR, tal como se hace actualmente, es que otras bibliotecas en la mayoría de los casos simplemente no funcionan, y las que sí lo hacen (como Feliz.Bulma / Feliz.Bulma.ViewEngine ) todavía necesitan ajustes a menos que ellos también construya una API abstracta para que ambos hagan referencia similar a lo que es esto.

Alternativas

Creo que la raíz del problema aquí es que intentar hacer SSR nosotros mismos no es muy factible cuando queremos emular completamente la primera pintura deseada. Lo que realmente necesitamos es algo como ReactDOMServer para .NET. Realmente no he profundizado demasiado en esto, pero ¿ React.NET (tal vez con un contenedor de F #) sería una mejor manera de avanzar?

Muchas gracias por los comentarios @Shmew y perdón por responder tarde:

  • Intellisense : Hmm, solo escribí un ejemplo simple con la API abstracta pero no vi ningún problema con el autocompletado. Intentaré comprobar de nuevo. En lugar de acceder a un tipo estático, los usuarios acceden a un valor. Supongo que debería estar bien y en muchos casos no será necesario cambiar el código. El principal inconveniente probablemente sería que open type no se puede usar.
  • Tamaño del paquete : también necesito verificar esto. Mi esperanza es que no cambie mucho porque los miembros de la clase son compilados por Fable como funciones separadas que se pueden agitar y también minificar bien. Aunque, desafortunadamente, el código generado no se verá tan bien como ahora después del # 284
  • Otras bibliotecas : Sí, otras bibliotecas deberían adaptarse para obtener los beneficios de una API abstracta. Ojalá con cambios mínimos.
  • Alternativas : TBH, realmente no sé cómo funciona SSR con React, aunque mirando el código (contribuido) en Fable.React no parece muy complicado (básicamente simplemente agregando algunos metadatos a las etiquetas html generadas) así que no estoy seguro si es más fácil usar algo como React.NET o no. Supongo que esto tampoco será utilizable con Feliz, ya que Feliz contiene trucos de Fable (principalmente lanzamientos inseguros) que incluirán .NET.

En realidad, para esto estoy pensando no solo en SSR sino también en _beyond React_: wink :, por ejemplo para generadores html en servidores F # que no necesariamente necesitan ser compatibles con React y en el caso de que queramos usar otros renderizadores que no sean Reacciona para la interfaz.

Muchas gracias por los comentarios @Shmew y perdón por responder tarde.

¡De nada y no te preocupes!

Intellisense: Hmm, solo escribí un ejemplo simple con la API abstracta pero no vi ningún problema con el autocompletado. Intentaré comprobar de nuevo. En lugar de acceder a un tipo estático, los usuarios acceden a un valor. Supongo que debería estar bien y en muchos casos no será necesario cambiar el código. El principal inconveniente probablemente sería que no se puede utilizar el tipo abierto.

Lo siento, no fui muy claro. Intellisense está bien, pero más bien el hecho de que Html sería de un color diferente. Como dije, realmente menor 😅. El hecho de que perdamos la posibilidad de open type es en realidad un problema un poco mayor. Sé que algunos realmente prefieren eso a tener que usar un espacio de nombres para todo.

Tamaño del paquete: también necesito comprobar esto. Mi esperanza es que no cambie mucho porque los miembros de la clase son compilados por Fable como funciones separadas que se pueden agitar y también minificar bien. Aunque, desafortunadamente, el código generado no se verá tan bien como ahora después del # 284

Ni siquiera me di cuenta de que las funciones de interoperabilidad no estaban ya integradas, ya las incluyo en mis bibliotecas. Estaba hablando más sobre el hecho de que todo el módulo Html no tiene un aumento de tamaño de paquete en comparación con si se hiciera de forma nativa en JS porque es solo un contenedor en línea. Con una clase concreta que ya no es el caso.

Otras bibliotecas: Sí, otras bibliotecas deberían adaptarse para obtener los beneficios de una API abstracta. Ojalá con cambios mínimos.

El problema con esto es que las bibliotecas que usan código de reacción nativo no pueden funcionar correctamente porque todos los componentes internos son solo JS.

Alternativas: TBH, realmente no sé cómo funciona SSR con React, aunque mirando el código (contribuido) en Fable.React no parece muy complicado (básicamente simplemente agregando algunos metadatos a las etiquetas html generadas) así que no estoy seguro si es más fácil usar algo como React.NET o no. Supongo que esto tampoco será utilizable con Feliz, ya que Feliz contiene trucos de Fable (principalmente lanzamientos inseguros) que incluirán .NET.

Sí, eso funciona para casos simples , pero si intentas usar cosas que son más complejas como algunos de los componentes en Feliz.MaterialUI , simplemente no funcionará. Por lo que tengo entendido, React SSR es bastante simple cuando se hace en node.js porque solo pueden ejecutar ReactDOMServer para escupir una cadena completa que es la primera pintura de la página. Tengo entendido que React.NET solo está envolviendo un proceso de node.js para hacer exactamente eso.

Sospecho que esto sería bastante fácil con el código Feliz, ya que ya admite este tipo de cosas. El proceso sería algo como:

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

más allá de React

Ese es un gran punto, y definitivamente es algo que me gustaría si estuviera buscando renderizar HTML puro sin React ni nada.

He experimentado con esta idea, puedes ver mi progreso aquí: https://github.com/alfonsogarciacaro/Feliz.Engine

Todavía hay trabajo por hacer y tengo algunas dudas sobre un par de cosas, pero ya está funcionando y cubre la mayor parte de Feliz API. Sin embargo, tuve que hacer algunos cambios, así que es cierto que será difícil reemplazar a Feliz con algo como esto. Pero todavía tiene valor tener una versión abstracta de Feliz, ya que abre muchas posibilidades. Algunos ejemplos:

  1. Úselo con otros marcos frontend, como Sutil: https://github.com/davedawkins/Sutil/pull/15
  2. Úselo para generar CSS en lugar de SASS: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Css/Feliz.Css.fs
  3. Úselo para generar html estático: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.StaticHtml/Feliz.StaticHtml.fs
  4. Úselo con otra implementación de dom virtual, como Snabbdom: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Snabbdom/Feliz.Snabbdom.fs

Todos estos son borradores, pero están funcionando y puede ver que requieren muy poco código. Más importante aún, todos ofrecen una API documentada y familiar para los usuarios, que también es extensible: por ejemplo, puede crear fácilmente un BulmaEngine que sea compatible con todas estas (y futuras) aplicaciones. En el caso de 2. y 3. Estoy usando Fable porque la compilación incremental es mucho más rápida que con .NET pero Feliz.Engine es compatible con .NET (eliminé todos los unbox ) por lo que debería ser trivial para hacerlos compatibles con los servidores F # .NET, y con suerte no debería requerir mucho trabajo hacer que el generador HTML también sea compatible con React.

¿Qué opinas @ Zaid-Ajaj? Ya he renunciado a la idea de reemplazar la API Feliz React actual 😅 ¿Pero crees que algo como esto debería pertenecer a la "familia Feliz" (tal vez en este repositorio)? ¿Está de acuerdo con el nombre o prefiere usar algo más?

Hola @alfonsogarciacaro , profundizaré en estas muestras en algún momento de esta semana y seguro que volveré a ellas 😄

Hola,

Eché un vistazo rápido al código y parece que esta versión abstracta tendrá algún impacto en el tamaño del paquete. Solo quería señalarlo, ya que era una de las características de Feliz en su forma actual.

Sí, se espera un impacto, la pregunta es qué tan grande es :) Espero que para las aplicaciones de tamaño mediano a grande no sea muy notable, pero por supuesto sería bueno tener algo como fulma-demo en ambos estilos para que podamos puede comparar y utilizar para probar oportunidades de optimización. También sería interesante comprobar cómo los ayudantes de Feliz en línea o no afectan el tamaño del paquete. En este momento, el código generado por Feliz es bastante bueno y se parece mucho a JSX compilado, pero las funciones se pueden minimizar, por lo que podría ser una forma de reducir la duplicación de muchas llamadas como .createElement("div") (no estoy seguro si gzip puede comprimir aunque estas llamadas).

Sí, no puedo imaginar que alguien se oponga a poder usar esta maravillosa API / estilo en otros proyectos. Mi única preocupación real era si afectaría la calidad de esta biblioteca y algunos de los problemas ergonómicos que describí anteriormente.

Hola @alfonsogarciacaro , he

  • El CssEngine genera CSS, cuál es el beneficio de eso en comparación con usar solo cadenas de herramientas CSS / SASS o CSS-en-JS como el construido en Feliz o usar otras librerías CSS-in-JS como FSS o Emotion. Generar CSS a partir de F # funcionaría por sí solo, pero no es algo que usaría con Feliz, ya que confiar en cadenas de herramientas existentes sería una mejor opción (también tiempos de compilación más rápidos si no desea que el compilador Fable / F # se ralentice al tener para compilar hojas de estilo enormes) Actualmente estoy más a favor de usar módulos CSS para componentes Feliz / React
  • El motor html estático: Feliz ya genera html estático usando ReactDOM en el nodo y en el navegador. Feliz.ViewEngine hace lo mismo para generar HTML estático en dotnet. Sé que la idea es compartir la API, pero eso se ve dificultado por otros desafíos, como mencionó @Shmew : en tercer lugar, las bibliotecas en parte que tienen que implementar ambas, afecta el código generado, que ahora está realmente limpio. También mezcla atributos, estilos y niños en una lista que rompe la API actual de Feliz.
  • Motor Snabbdom: ejemplo interesante, pero no tiene el ecosistema de bibliotecas como React.

Considerándolo todo, un ejercicio interesante. Para ser honesto contigo, no soy un gran admirador de la nueva API y personalmente preferiría dedicar tiempo a mejorar la experiencia actual con más documentos, ejemplos y enlaces en React en lugar de intentar estandarizar las bibliotecas. Lo siento si estoy saliendo un poco negativo al respecto, probablemente hayas trabajado mucho. No me importa tener el mismo nombre que Feliz, ya que se inspiró en la biblioteca.

¡Muchas gracias por revisar las muestras @ Zaid-Ajaj! Agradezco tu honestidad. La impresora css y html fueron solo ejemplos rápidos para comprobar lo fácil / difícil que fue adaptar Feliz.Engine a usos potenciales (el código para hacer la impresión es de solo 50 líneas). Usé Fable & node porque la compilación incremental es mucho más rápida, pero "en principio" debería ser fácil adaptarla a .net. El adaptador Snabbdom estaba destinado a ser también otro ejemplo rápido, pero en realidad me está empezando a gustar, aunque eso es otro asunto :)

De todos modos, finalmente me di cuenta de que no será posible abstraer las aplicaciones Feliz React actuales sin romper los cambios (tal como dijiste desde el principio 😅), así que mantengamoslo como un proyecto paralelo para los usuarios que quieran probar otros renderizadores con una API similar a Feliz 👍

@alfonsogarciacaro Esto se ve increíble. Como se mencionó en el n. ° 262, lo único que realmente extraño desde que cambié de Fable.React a Feliz es el SSR 'simplemente funciona'. Tanto Feliz como Feliz.ViewEngine son proyectos increíbles, pero tener dos proyectos diferentes dificulta la reutilización del código, ya que cualquier fragmento de código que use ifdefs solo puede ser usado por otro código que use ifdefs - creando silos solo para js, dotnet- código único y de ambos mundos. Cualquier cosa que cierre esa brecha ciertamente mejoraría la calidad de vida cuando se trabaja con servidores Feliz y .Net.

Si. ese sería un gran caso de uso. Sin embargo, es complicado porque al final Feliz.Engine tiene algunas diferencias con Feliz, lo que significa que tendríamos que escribir una implementación de Feliz.Engine React que competiría con el mismo Feliz, algo que me gustaría evitar;) Pero con suerte podemos encontrar un solución.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

cmeeren picture cmeeren  ·  13Comentarios

heimeshoff picture heimeshoff  ·  6Comentarios

cmeeren picture cmeeren  ·  4Comentarios

alfonsogarciacaro picture alfonsogarciacaro  ·  6Comentarios

Zaid-Ajaj picture Zaid-Ajaj  ·  8Comentarios