JSX em vez da função h (createElement) em widgets e outros locais

Oi, tenho experimentado JSX em widgets para melhorar a experiência do desenvolvedor em temas (criei minha própria configuração para desenvolvimento de temas sem header.html etc., falarei mais sobre isso em outro tópico).

Estava me perguntando por que o Discourse não utiliza plugins Babel dentro do seu próprio código. No Discourse, temos disponível o plugin Babel transform-react-jsx, que pode ser usado para transformar JSX em uma função createElement personalizada usando as opções jsxPragma. Tudo isso já está disponível no Discourse.

Adicionar o transform-react-jsx aqui https://github.com/discourse/discourse/blob/master/lib/discourse_js_processor.rb#L143-L149 e, de alguma forma, expor a configuração do Babel para alterar o jsxPragma aqui https://github.com/discourse/discourse/blob/master/vendor/assets/javascripts/babel.js
poderia tornar isso possível.

Já implementei a primeira parte; a parte da pragma ainda precisa de mais investigação. Infelizmente, não há um arquivo .babelrc para configurar plugins individuais. Estou recebendo a função React.createElement em vez de uma função personalizada.

Mais informações sobre o uso de JSX sem React aqui: Using jsx WITHOUT React | r0b blog

Alguma ideia ou talvez ajuda sobre como isso poderia ser alcançado?

ATUALIZAÇÃO:
Consegui fazer isso funcionar alterando a configuração da pragma em vendor/assets/javascripts/babel.js, na linha 26586:

var id = state.opts.pragma || "React.createElement";
// para
var id = state.opts.pragma || "h";

Você já viu isso? Agora você pode usar Templates se não gostar do Hyperscript:

4 curtidas

@merefield sim, eu sei sobre hbs, mas não sou “o desenvolvedor típico de temas do Discourse” :slight_smile:. Gostaria de usar o poder do JSX, que é JavaScript real, em vez do hbs, que tem funcionalidades limitadas.

E consegui usar JSX em um tema do Discourse agora. Mas foi na minha própria fork do Discourse, então não é muito útil para o desenvolvimento geral de temas.

2 curtidas

No final, a decisão é do @eviltrout. Posso, no entanto, compartilhar minha opinião. Sim, o JSX pode ser agradável de usar e poderíamos incluí-lo no Discourse, mas não acho que o faremos, pois teríamos que dar suporte a ele e estamos mais inclinados a eliminar os widgets em algum momento do que a adicionar mais opções.

9 curtidas

Eu entendo completamente seu ponto. Estou apenas me perguntando, por que não abrir a configuração do Babel (e de um monte de outras coisas) para desenvolvedores de temas e plugins?

Por exemplo, o arquivo .babelrc na pasta do tema pode ser usado para algumas opções adicionais do transpilador de JS. Se o .babelrc estiver presente, o discourse_js_processor pode usá-lo, estender sua configuração do Babel e habilitar um monte de recursos adicionais de JS.

Apenas uma ideia.

É apenas uma questão de ‘API pública’ em um sentido amplo: tudo o que permitirmos, teremos que dar suporte. O que parece fácil de manter hoje pode se tornar difícil amanhã. Estamos definitivamente experimentando muitas coisas no pipeline e na parte do lado do cliente do aplicativo ultimamente. Vamos ver o que o Robin acha de tudo isso.

5 curtidas

Por favor, não sinta pressão; sou apenas um desenvolvedor curioso com algumas perguntas. Cheguei ao Discourse vindo do mundo full stack JS (Node/Vue), onde o Ember simplesmente não é uma opção, especialmente quando você tem o React ou, melhor ainda, o Vue.

O Ember parece tão pouco natural, e os handlebars estão simplesmente desatualizados em termos de funcionalidades. O poder de template do JSX e, especialmente, dos Vue SFC, não pode ser comparado com algo básico como hbs.

2 curtidas

Eu discordo de que Ember não seja uma opção para full stack JS. Entendo o argumento de que o Ember não é tão popular quanto outros frameworks e que você pode querer escolher outro framework por esse motivo, mas certamente existem muitos e muitos sites usando Node no back-end e Ember no front-end. Afinal, toda a ferramenta do Ember é baseada no Node.

Dito isso, JSX não faz parte do futuro do núcleo do Discourse, mas se houver algo que possamos fazer para permitir seu uso em plugins, estou aberto a isso. Por favor, faça uma proposta de como isso funcionaria!

9 curtidas

É uma opção, mas no meu desenvolvimento e no trabalho relacionado a ele, não é. E eu pessoalmente não o usaria, pois o Vue parece ser uma escolha natural para esse tipo de aplicação.

Apenas um pouco de contexto:

Nos últimos meses, tenho trabalhado no desenvolvimento de um tema bastante personalizado para um cliente, onde aprendi várias coisas sobre o funcionamento interno do Discourse, mas isso provavelmente representa apenas uma pequena porcentagem.

Atualmente, estou refatorando vários erros de iniciante e tentando tornar as coisas o mais amigável possível para futuros colegas que possam acabar mantendo meu trabalho. Por isso, fiz algumas experimentações em relação ao JSX.

Hoje, tentei a abordagem do primeiro post do tópico. Incluí transform-react-jsx aqui: https://github.com/discourse/discourse/blob/master/lib/discourse_js_processor.rb#L143-L149:

      if opts[:module_name] && !@skip_module
        filename = opts[:filename] || 'unknown'
        "Babel.transform(#{js_source}, { moduleId: '#{opts[:module_name]}', filename: '#{filename}', ast: false, presets: ['es2015'], plugins: [['transform-es2015-modules-amd', {noInterop: true}], 'transform-decorators-legacy', 'transform-react-jsx', exports.WidgetHbsCompiler] }).code"
      else
        "Babel.transform(#{js_source}, { ast: false, plugins: ['check-es2015-constants', 'transform-es2015-arrow-functions', 'transform-es2015-block-scoped-functions', 'transform-es2015-block-scoping', 'transform-es2015-classes', 'transform-es2015-computed-properties', 'transform-es2015-destructuring', 'transform-es2015-duplicate-keys', 'transform-es2015-for-of', 'transform-es2015-function-name', 'transform-es2015-literals', 'transform-es2015-object-super', 'transform-es2015-parameters', 'transform-es2015-shorthand-properties', 'transform-es2015-spread', 'transform-es2015-sticky-regex', 'transform-es2015-template-literals', 'transform-es2015-typeof-symbol', 'transform-es2015-unicode-regex', 'transform-regenerator', 'transform-decorators-legacy', 'transform-react-jsx',exports.WidgetHbsCompiler] }).code"
      end

E alterei a configuração de pragma em vendor/assets/javascripts/babel.js na linha 26586:

var id = state.opts.pragma || "React.createElement";
// para
var id = state.opts.pragma || "h";

Isso me permitiu usar a função h do virtual-dom em vez de React.createElement no código processado pelo Babel. A função h faz parte do Discourse e isso pareceu uma escolha natural.

Não conheço a história do desenvolvimento do Discourse e vocês provavelmente tiveram suas razões para adicionar o arquivo completo do babel.js com vários plugins úteis no código. É uma pena que esses plugins não estejam disponíveis para o desenvolvedor final, como eu. Minha proposta seria:

  1. Usar algum tipo de configuração do Babel, como .babelrc, .babel.yml, ou definir um campo de configuração do Babel no about.json, semelhante ao que é feito no package.json (Configure Babel · Babel). Essa configuração poderia referenciar todos esses plugins no babel.js (ou talvez outros, veja o item 3).

  2. Em discourse_js_processor.rb#babel_parse (https://github.com/discourse/discourse/blob/master/lib/discourse_js_processor.rb#L138), ler essa configuração e estendê-la à configuração atual.

  3. Se um desenvolvedor quiser ter um plugin personalizado do Babel, ele poderia adicioná-lo à pasta vendor/assets/javascripts/babel/plugins (ou apenas babel/plugins) e o Discourse o detectaria e o utilizaria no processo de transpilação.

Não tenho experiência no desenvolvimento do backend em Rails, então esta é minha proposta meta.

E outra pergunta, já que estamos nisso: quão difícil seria para o Discourse ler as dependências de, por exemplo, o package.json de temas, instalá-las na primeira execução e usá-las (mantendo-as em cache ou algo assim) dentro do tema? (Se as dependências mudarem, verificar quais mudaram e instalá-las ou removê-las, etc.).

Mais uma vez, vocês estão fazendo um ótimo trabalho e seu trabalho é incrível. Por favor, não sintam nenhuma pressão da minha parte; estou aqui apenas para aprender, participar de boas discussões e compartilhar opiniões e ideias. Não espero que vocês implementem minhas solicitações ou nada disso.

3 curtidas

O que você quer dizer com isso? O que não é possível fazer com Handlebars e Ember que já foi implementado em outro framework?

O que quis dizer é que o JSX é JavaScript, não uma linguagem de template. Por ser JavaScript puro, ele é mais poderoso (por exemplo: operador ternário, função map, etc.). Você pode fazer o que quiser no Ember/Handlebars, mas o JSX é mais conveniente e amigável para desenvolvedores, na minha opinião.

1 curtida

E isso funcionou? Você conseguiu adicionar JSX e tudo ficou OK?

Agora, sobre as outras perguntas que você fez sobre por que o Babel está configurado dessa forma: o Discourse é construído sobre o Rails usando o pipeline de ativos, e o suporte ao webpack foi adicionado ao Rails apenas na versão 6. A base de código do Discourse tem 8 anos! Com o tempo, adicionamos coisas a ela, mas superamos suas limitações.

Um dos grandes projetos deste ano é a migração para o Ember CLI — se você observar nossos commits, verá trabalhos em direção a esse objetivo sendo integrados ao Discourse, mas é um caminho longo.

Uma vez que isso esteja em vigor, você poderá usar muitos mais recursos de construção de JavaScript que atualmente não funcionam, a menos que sejam executados dentro do Ruby, o que é trabalhoso. Enquanto isso, não vejo a possibilidade de dedicarmos tempo à leitura do package.json e fazer com que isso seja integrado automaticamente ao pipeline do Rails.

6 curtidas

Vou criar um PR de POC para demonstrar como isso funciona.

Obrigado pela visão e explicação!

3 curtidas

Uma atualização — Consegui criar um ThemeField para o Babel, que é usado para ler o babel.config.json do tema e injetar plugins no Babel.transform dentro do discourse_js_processor.

Espero conseguir enviar o PR em breve, apenas para mostrar um proof of concept. Um aviso: vai ser uma bagunça enorme :sweat_smile:.

PS: Ruby é tão fácil de trabalhar :star_struck:

Aqui está:

2 curtidas