Feliz: Faça de Feliz uma API abstrata

Criado em 19 dez. 2020  ·  15Comentários  ·  Fonte: Zaid-Ajaj/Feliz

Estou prestes a propor uma alteração significativa, mas espero que exija apenas que os usuários finais e os autores da biblioteca atualizem os pacotes e nenhuma alteração real no código.

  1. F # é uma ótima linguagem para declarar UIs
  2. Cada desenvolvedor F # que faz algo relacionado à web escreve sua própria DSL para declarar UIs
  3. Feliz é uma ótima API / DSL para declarar interfaces de usuário web React

E se removêssemos "React" de 3? Isso pode resolver muitos problemas:

  • Feliz pode se tornar um padrão e resolver 2 na lista acima. Assim, a maioria dos componentes escritos com Feliz podem ser usados ​​automaticamente com diferentes motores de renderização
  • Isso também pode evitar a dependência Fable.React conforme discutido em # 285 (Fable.React implementaria IViewElement para manter a compatibilidade)
  • Isso também pode tornar mais fácil escrever um renderizador Feliz do lado do servidor sem ter que usar #if FABLE_COMPILER todos os lugares como com Fable.React
  • Pode acontecer que alguém em algum lugar esteja escrevendo um renderizador de front-end diretamente no Fable. Seria ótimo se pudesse usar o Feliz

Com o argumento de venda feito, se você acha que esta é uma boa jogada, podemos discutir a implementação. Eu não tentei nada ainda, então não tenho certeza de como poderia funcionar, mas o que tenho em mente é algo assim:

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

Não tenho certeza de como o intellisense funcionaria, talvez precisemos usar uma classe abstrata em vez de uma interface, mas espero que você tenha entendido. O que você acha?

Comentários muito úteis

@alfonsogarciacaro Isso parece incrível. Conforme mencionado no # 262, a única coisa que realmente sinto falta desde que mudei de Fable.React para Feliz é o SSR 'simplesmente funciona'. Ambos Feliz e Feliz.ViewEngine são projetos incríveis, mas ter dois projetos diferentes torna a reutilização de código difícil, já que qualquer pedaço de código que usa ifdefs só pode ser usado por outro código que usa ifdefs - criando silos apenas para js, dotnet- código único e de ambos os mundos. Qualquer coisa que feche essa lacuna certamente melhoraria a qualidade de vida ao trabalhar com servidores Feliz e .Net.

Todos 15 comentários

Olá @alfonsogarciacaro , para ser honesto com você, não _sinto_ que isso seja uma boa ideia. Teoricamente, é claro: vamos construir uma API padrão para HTML no Fable. Na prática, isso não se traduz muito bem. Aqui estão alguns motivos:

  • A API atual é tudo menos padrão; na verdade, é muito opinativa. Muitas pessoas ainda não gostam de toda a lista única e prop.children coisa que é claro que é totalmente normal.
  • A API atual é tornada "simples" porque parte do pressuposto de que é somente React: abstraí-la exigiria MUITO trabalho, onde a alternativa de escrever / duplicar uma API no estilo Feliz seria provavelmente a solução mais fácil.
  • Prefiro me concentrar em melhorar as ferramentas do React em vez de espalhar os recursos: Feliz está longe de estar "pronto", ainda há muito a fazer em relação à documentação, aplicativos de amostra, melhor história de teste etc.

Muito obrigado pela resposta @Zaid! Eu entendo seu raciocínio, ainda é uma pena termos tantas DSLs concorrentes, mas talvez existam outras soluções como você disse. Se eu encontrar tempo, vou tentar escrever um protótipo de qualquer maneira para ver como funcionaria.

BTW, comecei alguns trabalhos aqui: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/src/HtmlEngine.fs

Eu não testei, mas removi todos os unbox e truques semelhantes, então, em princípio, ele "deve" funcionar com qualquer renderizador que implemente esta interface . Seria bom, por exemplo, tentar combinar um renderizador React com @dbrattli Feliz.ViewEngine e ver se isso torna o SSR mais simples com Feliz.

Há algumas coisas que precisam ser descobertas / consideradas:

Intellisense

Não estou muito feliz que minha intellisense pareça funky, já que Html seria definida em Feliz como:

let Html = HtmlEngine(renderer)

No entanto, isso é mais um problema menor.

Tamanho do pacote

Obviamente, queremos que seja o mesmo que é atualmente (ou melhor). Talvez um plugin em Feliz.HtmlEngine que está contido nas diretivas do compilador? Esta solução faria com que os servidores web dependessem do Fable.

Outras bibliotecas

Um dos maiores problemas com SSR como é feito atualmente é que outras bibliotecas na maioria dos casos simplesmente não funcionam, e aquelas que funcionam (como Feliz.Bulma / Feliz.Bulma.ViewEngine ) ainda precisam de ajustes, a menos que também construir uma API abstrata para que ambos façam referência semelhante a esta.

Alternativas

Acho que a raiz do problema aqui é que tentar fazer SSR por conta própria não é muito viável quando queremos emular totalmente a primeira tinta pretendida. O que realmente precisamos é algo como ReactDOMServer para .NET. Eu realmente não cavei muito nisso, mas o React.NET (talvez com um invólucro F #) seria uma maneira melhor de avançar?

Muito obrigado pelos comentários @Shmew e desculpe por responder tarde:

  • Intellisense : Hmm, eu apenas escrevi um exemplo simples com a API abstrata, mas não vi nenhum problema com o preenchimento automático. Vou tentar verificar novamente. Em vez de acessar um tipo estático, os usuários acessam um valor. Acho que não tem problema e, em muitos casos, o código não precisa ser alterado. A principal desvantagem provavelmente seria que open type não pode ser usado.
  • Tamanho do pacote : também preciso verificar isso. Minha esperança é que não mude muito porque os membros da classe são compilados pelo Fable como funções destacadas que podem ser alteradas e também minimizadas. Embora, infelizmente, o código gerado não pareça tão bom como agora, após # 284
  • Outras bibliotecas : Sim, outras bibliotecas teriam que ser adaptadas para obter os benefícios de uma API abstrata. Esperançosamente, com mudanças mínimas.
  • Alternativas : TBH, eu realmente não sei como o SSR com React funciona, embora olhando para o código (contribuído) em Fable.React não pareça muito complicado (basicamente apenas adicionando alguns metadados às tags html geradas), então não tenho certeza se é mais fácil usar algo como React.NET ou não. Eu acho que isso também não será utilizável com Feliz, já que Feliz contém truques de Fable (principalmente casts inseguros) que irão lançar em .NET.

Na verdade, para isso estou pensando não apenas em SSR, mas também _beyond React_: wink :, por exemplo, para geradores de html em servidores F # que não precisam necessariamente ser compatíveis com React e no caso de querermos usar outros renderizadores que não Reaja para o front-end.

Muito obrigado pelos comentários @Shmew e desculpe por responder tarde

De nada, e não se preocupe!

Intellisense: Hmm, eu apenas escrevi um exemplo simples com a API abstrata, mas não vi nenhum problema com o preenchimento automático. Vou tentar verificar novamente. Em vez de acessar um tipo estático, os usuários acessam um valor. Acho que não tem problema e, em muitos casos, o código não precisa ser alterado. A principal desvantagem provavelmente seria que o tipo aberto não pode ser usado.

Desculpe, não fui muito claro. IntelliSense é bom, mas sim o fato de que Html seria uma cor diferente. Como eu disse, realmente menor 😅. O fato de perdermos a possibilidade de open type é na verdade um problema um pouco maior. Eu sei que alguns realmente preferem isso a ter que definir o namespace de tudo.

Tamanho do pacote: também preciso verificar isso. Minha esperança é que não mude muito porque os membros da classe são compilados pelo Fable como funções destacadas que podem ser alteradas e também minimizadas. Embora, infelizmente, o código gerado não pareça tão bom como agora, após # 284

Eu nem percebi que as funções de interoperabilidade ainda não estavam embutidas, eu já as embuti em minhas bibliotecas. Eu estava mais falando sobre o fato de que todo o módulo Html não tem aumento de tamanho de pacote em comparação com se fosse feito nativamente em JS porque é apenas um wrapper embutido. Com uma aula concreta que não é mais o caso.

Outras bibliotecas: Sim, outras bibliotecas teriam que ser adaptadas para obter os benefícios de uma API abstrata. Esperançosamente, com mudanças mínimas.

O problema com isso é que as bibliotecas que usam código de reação nativo não podem funcionar corretamente porque todos os internos são apenas JS.

Alternativas: TBH, eu realmente não sei como funciona o SSR com React, embora olhando para o código (contribuído) em Fable.React não pareça muito complicado (basicamente apenas adicionando alguns metadados às tags html geradas), então não tenho certeza se é mais fácil usar algo como React.NET ou não. Eu acho que isso também não será utilizável com Feliz, já que Feliz contém truques de Fable (principalmente casts inseguros) que irão lançar em .NET.

Sim, isso funciona para casos simples , mas se você tentar usar coisas que são mais complexas, como alguns dos componentes em Feliz.MaterialUI , simplesmente não vai funcionar. Pelo que entendi, React SSR é muito simples quando feito em node.js porque eles podem simplesmente executar ReactDOMServer para realmente cuspir uma string completa que é a primeira pintura da página. Meu entendimento é que React.NET está apenas envolvendo um processo node.js para fazer exatamente isso.

Eu suspeito que isso seria realmente muito fácil com o código do Feliz, pois ele já suporta coisas assim. O processo seria algo como:

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

além de reagir

Esse é um ótimo ponto, e definitivamente algo que eu gostaria se estivesse procurando renderizar HTML puro sem React ou algo assim.

Estou experimentando essa ideia, você pode ver meu progresso aqui: https://github.com/alfonsogarciacaro/Feliz.Engine

Ainda há trabalho a fazer e tenho algumas dúvidas sobre algumas coisas, mas já está funcionando e cobre a maior parte do Feliz API. No entanto, tive de fazer algumas alterações, por isso é verdade que vai ser difícil substituir o Feliz por algo assim. Mas ainda vale a pena ter uma versão abstrata de Feliz, pois abre muitas possibilidades. Alguns exemplos:

  1. Use-o com outras estruturas de front-end, como Sutil: https://github.com/davedawkins/Sutil/pull/15
  2. Use-o para gerar CSS em vez de SASS: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Css/Feliz.Css.fs
  3. Use-o para gerar html estático: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.StaticHtml/Feliz.StaticHtml.fs
  4. Use-o com outra implementação de dom virtual, como Snabbdom: https://github.com/alfonsogarciacaro/Feliz.Engine/blob/main/samples/Feliz.Snabbdom/Feliz.Snabbdom.fs

Todos são rascunhos, mas estão funcionando e você pode ver que exigem muito pouco código. Mais importante ainda, todos eles oferecem uma API documentada e familiar aos usuários, que também é extensível: por exemplo, você pode criar facilmente um BulmaEngine que seja compatível com todos esses (e futuros) aplicativos. No caso de 2. e 3. Estou usando o Fable porque a compilação incremental é muito mais rápida do que com .NET, mas Feliz.Engine é compatível com .NET (removi todos os unbox ), então deve ser trivial para torná-los compatíveis com servidores F # .NET e, com sorte, não deve exigir muito trabalho tornar o gerador de HTML compatível com React também.

O que você acha @ Zaid-Ajaj? Já desisti de substituir a API Feliz React atual 😅 Mas você acha que algo assim deveria pertencer à "família Feliz" (talvez neste repo)? Aceita o nome ou prefere usar outro?

Olá @alfonsogarciacaro , farei um mergulho profundo nessas amostras ainda esta semana e voltarei com certeza 😄

Olá,

Dei uma olhada rápida no código e parece que essa versão abstrata terá algum impacto no tamanho do pacote. Queria apenas salientar que foi uma das características de Feliz na sua forma atual.

Sim, um impacto é esperado, a questão é o quão grande ele é :) Espero que para aplicativos de médio-grande porte não seja muito perceptível, mas é claro que seria bom ter algo como fulma-demo em ambos os estilos, então nós pode comparar e usar para testar oportunidades de otimização. Também seria interessante verificar como os ajudantes de Feliz inlining ou não afetam o tamanho do pacote. No momento, o código gerado por Feliz é muito bom e se parece muito com JSX compilado, mas as funções podem ser reduzidas para que possa ser uma forma de reduzir a duplicação de muitas chamadas como .createElement("div") (não tenho certeza se o gzip pode compactar embora essas chamadas).

Sim, eu não posso imaginar que alguém se oporia a ser capaz de usar esta API / estilo maravilhoso em outros projetos. Minha única preocupação real era se isso afetaria a qualidade desta biblioteca e algumas das questões ergonômicas que descrevi acima.

Olá @alfonsogarciacaro , dei uma boa olhada no código de exemplo. Fiquei surpreso ao ver que o mecanismo css e o mecanismo html estático são aplicativos somente nodejs, uma vez que usam fluxos node.js. Embora a ideia seja interessante, acho difícil me ver realmente usando qualquer uma das opções acima:

  • O CssEngine gera CSS, qual é a vantagem disso ao invés de usar apenas conjuntos de ferramentas CSS / SASS ou CSS-in-JS como o construído em Feliz ou usar outras bibliotecas CSS-in-JS como FSS ou Emotion. Gerar CSS a partir do F # funcionaria por conta própria, mas não é algo que eu usaria com Feliz, já que depender de cadeias de ferramentas existentes seria uma escolha melhor (também tempos de compilação mais rápidos se você não quiser que o compilador Fable / F # fique lento por ter para compilar folhas de estilo enormes) Atualmente, sou mais a favor do uso de módulos CSS para componentes Feliz / React
  • O motor html estático: Feliz já gera html estático usando ReactDOM no nó e no navegador. Feliz.ViewEngine faz o mesmo para gerar HTML estático em dotnet. Eu sei que a ideia é compartilhar a API, mas isso é dificultado por outros desafios, como @Shmew mencionou: em terceiro lugar, as bibliotecas tendo que implementar ambos, impactam o código gerado que agora está realmente limpo. Também mistura atributos, estilos e filhos em uma lista que quebra a API atual de Feliz.
  • Motor Snabbdom: exemplo interessante, mas não tem o ecossistema de bibliotecas como o React.

Em suma, um exercício interessante. Para ser honesto com você, eu não sou um grande fã da nova API e pessoalmente prefiro gastar tempo melhorando a experiência atual com mais documentos, exemplos e ligações no React em vez de tentar padronizar as bibliotecas. Desculpe se estou parecendo um pouco negativo sobre isso, você provavelmente trabalhou muito nisso. Não me importo de ter o mesmo nome de Feliz, pois foi inspirado na biblioteca.

Muito obrigado por verificar as amostras @ Zaid-Ajaj! Agradeço sua honestidade. A impressora css e html foram apenas exemplos rápidos para verificar o quão fácil / difícil foi adaptar o Feliz.Engine para usos potenciais (o código para fazer a impressão tem apenas 50 linhas). Usei Fable & node porque a compilação incremental é muito mais rápida, mas "em princípio" deve ser fácil adaptá-la para .net. O adaptador Snabbdom deveria ser também outro exemplo rápido, mas estou começando a gostar, embora isso seja outro assunto :)

De qualquer forma, finalmente percebi que não será possível abstrair os aplicativos Feliz React atuais sem interromper as alterações (como você dizia desde o início 😅), então vamos mantê-lo como um projeto paralelo para usuários que desejam experimentar outros renderizadores com uma API do tipo Feliz 👍

@alfonsogarciacaro Isso parece incrível. Conforme mencionado no # 262, a única coisa que realmente sinto falta desde que mudei de Fable.React para Feliz é o SSR 'simplesmente funciona'. Ambos Feliz e Feliz.ViewEngine são projetos incríveis, mas ter dois projetos diferentes torna a reutilização de código difícil, já que qualquer pedaço de código que usa ifdefs só pode ser usado por outro código que usa ifdefs - criando silos apenas para js, dotnet- código único e de ambos os mundos. Qualquer coisa que feche essa lacuna certamente melhoraria a qualidade de vida ao trabalhar com servidores Feliz e .Net.

sim. seria um ótimo caso de uso. É complicado porque no final Feliz.Engine tem algumas diferenças com Feliz, o que significa que teríamos que escrever uma implementação Feliz.Engine React que competisse com o próprio Feliz, algo que eu gostaria de evitar;) Mas, com sorte, podemos encontrar um solução.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

Dzoukr picture Dzoukr  ·  10Comentários

heimeshoff picture heimeshoff  ·  6Comentários

alfonsogarciacaro picture alfonsogarciacaro  ·  6Comentários

cmeeren picture cmeeren  ·  13Comentários

cmeeren picture cmeeren  ·  13Comentários