Atualizando Mathjax para a versão 4

@sam e todos os interessados em digitar matemática no Discourse. Eu atualizei o plugin discourse-math para que ele use o MathJax V3, em vez do V2, que é muito mais lento e muito desatualizado. Como esperado, o resultado é uma experiência de usuário muito mais ágil, mantendo o ambiente rico em recursos em comparação com o KaTeX.

Eu adoraria enviar uma solicitação de pull, se você achar que os resultados estão bons.


Você pode vê-lo em ação no site do fórum da minha turma:

A maior parte do conteúdo desse site é privada ou não listada. Deve haver vários tópicos no topo na categoria MathJax V3 que ilustram as ideias, no entanto.

Você pode examinar o código do plugin neste repositório autônomo do discourse-math: this standalone discourse-mathjax plugin repo. O arquivo que tem de longe a maior parte das modificações é o inicializador.

Você também pode usar esse repositório para instalá-lo em um site autônomo agora mesmo. Apenas certifique-se de remover o repositório antigo durante a instalação. Assim, você modificaria a técnica padrão de instalação de plugins para ficar assim:

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - rm -r discourse-math
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/mcmcclur/discourse-math.git

Comentários

A versão mais recente do MathJax é na verdade 4.0.0. Eu optei por usar a V3.2.2 por vários motivos

  • Embora a V4 seja certamente muito mais rápida que a V2, ela não é tão rápida quanto a V3.
  • A experiência do usuário é um pouco diferente na V4, especialmente se o usuário clicar na saída.
  • O status 4.0.0 me faz questionar quantos bugs podem existir.

Dito isto, a API para a V4 é idêntica à da V3. Deve ser possível atualizar mais tarde, simplesmente inserindo o repositório MathJax mais recente.

Eu tive que fazer uma pequena alteração no arquivo locales/server.en.yml. É claro que existem muito mais arquivos como esse para vários idiomas. Meu entendimento é que esses outros arquivos seriam traduzidos automaticamente mais tarde?

Eu realmente não uso o chat e não o testei nesse contexto.

4 curtidas

Pull request para atualizar o MathJax para a V3 feito com todos os testes aprovados!

2 curtidas

Em relação a:

Isto é fantástico :hugs: , mas eu me pergunto se podemos aproveitar isso como uma oportunidade para reduzir um pouco nosso repositório.

Agora que movemos o mathjax para o núcleo (core), podemos contar com o pnpm para buscar o pacote e evitar empacotar todo o código-fonte como fazemos para o FullCalendar, por exemplo.

Particularmente, temos o objetivo de ter apenas “links” em nosso repositório e, em seguida, podemos usar o processo de compilação (build) para buscar as dependências corretas.

Nos dê alguns dias, quero consultar a equipe de experiência de desenvolvimento (dev xp) aqui. Muito obrigado pelos seus esforços aqui!

4 curtidas

Sim, acho que essa é certamente a coisa certa a fazer. Eu sempre me perguntei por que você empacotava o projeto inteiro!

Então, acho que você criará uma função loadMathJax para sua biblioteca que é usada para carregar o MathJax?

Vou dizer que agrupar todos os plugins no core tornou um pouco mais complicado brincar com eles. Vincular as dependências ao processo de compilação só tornaria as coisas ainda mais difíceis, embora eu tenha certeza de que eu poderia buscar o MathJax ou o FullCalendar de uma CDN.

Estou falando principalmente sobre quando eu mexo com plugins para usar em meus próprios fóruns, e eu absolutamente acho que você deveria buscar o MathJax durante a compilação.

Com certeza! Eu uso o Discourse há anos e estou muito feliz que você ache isso fantástico! :rocket:

3 curtidas

Sim, exatamente. Um bom exemplo para copiar é o morphlex:

1 curtida

Gostaria de saber se você conseguiu conversar com o pessoal da experiência do desenvolvedor ainda? Ficarei feliz em ajudar, se puder. Minha impressão, no entanto, é que realmente não há nada que eu possa fazer sem o seu feedback sobre isso.

Fiz algumas mudanças adicionais em um branch separado, sobre as quais postarei em breve. Estou ciente de que você tem muita coisa para fazer, então não quero incomodar!

Modifiquei o plugin discourse-math para que ele possa analisar muito mais entradas matemáticas.

@sam Quando contribuí pela primeira vez para este plugin em 2017, lembro que você era bem firme em querer uma análise muito rigorosa. Deixe-me dizer de antemão que minha principal motivação para relaxar e estender a análise foi para que funcionasse melhor com IA. Em particular, quando você conversa sobre matemática com um bot de IA, você frequentemente descobrirá que ele responde usando LaTeX e há muitas maneiras pelas quais ele pode escolher delimitar essa entrada LaTeX. Portanto, embora eu entenda sua motivação para uma análise rigorosa, as alterações que fiz são bastante essenciais para esse caso de uso.

É claro que você ainda pode não se importar com esse caso de uso, então coloquei as alterações em um branch separado da minha pull request V3. Se você decidir que gostou delas, ficarei feliz em emitir outra pull request.

As alterações específicas para a pull request são:

Ele aceita matemática inline delimitada por barra-parêntese como \\(a^2+b^2=c^2\\).

Ele aceita matemática de exibição delimitada por dólar duplo em linha única como
$$a^2+b^2=c^2.$$

Ele aceita matemática de exibição delimitada por barra-colchete em linha única como
\\[a^2+b^2=c^2.\\]

Ele aceita matemática de exibição delimitada por barra-colchete de múltiplas linhas como
\\[
a^2+b^2=c^2.
\\]

É claro, ele ainda aceita as entradas do original:

Matemática inline delimitada por dólar: $a^2+b^2=c^2$.

Matemática de exibição delimitada por dólar duplo de múltiplas linhas:
$$
a^2+b^2=c^2.
$$

Você pode encontrar o branch relevante aqui.

O código também existe como um plugin autônomo.

Ah, você também pode vê-lo em ação!

2 curtidas

@mcmcclur Obrigado pelo seu trabalho. Seria ótimo ver esses recursos no núcleo.

1 curtida

Muito obrigado, Mark.

Meu grande impedimento aqui é que eu realmente quero migrar para os novos padrões de distribuição de dependências, veja:

Você poderia dar uma olhada nisso?

Em relação à sintaxe relaxada, parece-me uma configuração do site, talvez até padrão, considerando todos os LLMs existentes?

3 curtidas

@mcmcclur Eu estava mexendo nisso hoje:

Longe de estar pronto… mas as coisas meio que iniciam com o 4.1, o que é bom.

2 curtidas

Sim, isso é definitivamente progresso!
A primeira questão chave a ser abordada, como suspeito que você saiba, é que as fontes não estão sendo encontradas. Na verdade, eu mexi nesta linha em discourse-math-mathjax.js:

fontURL: getURLWithCDN("/assets/mathjax/woff-v2"),

Como teste, configurei a URL para apontar simplesmente para um diretório temporário no meu próprio servidor web, e os resultados iniciais parecem muito bons. Portanto, é uma questão de fazer com que essas fontes sejam instaladas corretamente no Discourse.
Em um projeto pnpm simples na minha máquina, o seguinte comando instala as fontes:

pnpm install @mathjax/mathjax-newcm-font@4

Quando executo esse comando dentro de discourse/frontend/discourse, as fontes aparecem em

/discourse/frontend/discourse/npm_modules/@mathjax/mathjax-newcm-font/chtml/woff2/

No entanto, essas fontes não parecem chegar em /assets/mathjax/woff-v2 após a compilação. Eu tentei várias variações do diretório, mas não consegui fazer funcionar. Eu presumo que seja algum tipo de mágica de roteamento na qual não sou especialista. Tenho quase certeza de que poderia progredir bastante para resolver isso, assim que essa questão do caminho for resolvida.

1 curtida

@sam Eu acho que fiz um progresso bem significativo nisso, com uma ressalva importante. Não tenho certeza de onde carregar os componentes desejados. Expresso em código,

window.MathJax = {
    loader: {
      // Isto não funciona:
      // paths: { mathjax: getURLWithCDN("/assets/mathjax") },
      // Mas isto funciona muito bem:
      paths: { mathjax: "https://cdn.jsdelivr.net/npm/mathjax@4.1.0" },
      load: ["core", "input/tex", "input/mml", "output/chtml", "output/svg"],
    },
    // Mais configuração ...
  };

Quando digo que a versão comentada não funciona, quero dizer que recebo a mensagem explícita:
MathJax(core): Não foi possível carregar “/assets/mathjax/core.js”

Note que, em ambos os casos, a função loadMathJax está buscando a inicialização do MathJax da cópia local. Ou seja, eu tenho o seguinte em
/discourse/frontend/discourse/app/static/mathjax-bundle.js

export * from "mathjax/startup.js";

Em seguida, loadMathJax definido em
/discourse/frontend/discourse/app/lib/load-mathjax.js
chama

const bundle = await import("discourse/static/mathjax-bundle");

Isso sugere algumas possibilidades:

  1. Talvez /assets/mathjax não seja o local correto ou
  2. Talvez esses ativos precisem ser registrados de alguma forma para aparecerem na distribuição (dist)?

Trabalhando com a versão do CDN, parece que posso progredir significativamente, mas presumo que isso seja um grande impedimento para você.

Eu poderia compartilhar meu código com você, se quiser, mas talvez essas informações sejam suficientes para um diagnóstico?

1 curtida

Com certeza, o código será muito útil aqui, talvez você possa fazer um fork do Discourse e então enviar suas alterações para um branch, assim eu posso puxar as alterações do seu branch para o PR.

Fico muito feliz que você esteja progredindo na tentativa de diagnosticar este problema.

Você pode também puxar as últimas alterações? Eu fiz uma rodada de limpeza.

1 curtida

OK, aqui está o código:

Cuidado, porém, eu não trabalhei diretamente a partir do seu commit mais recente. Eu comecei diretamente do main do Discourse e fiz as alterações a partir daí. Portanto, aprendi bastante com o seu trabalho, mas a estrutura geral é diferente.

Eu acho que você poderia resumir a principal diferença da seguinte forma: Onde você (naturalmente) usa recursos do Discourse herdados do Ember para coordenar os tempos associados a coisas como carregamento e composição, eu uso recursos do MathJax. Assim, meus pacotes load-mathjax e mathjax (um para svg e outro para chtml) são muito mais simples que os seus. O carregamento é todo coordenado através do objeto window.MathJax em discourse-math-mathjax.

Eu ainda tenho o mesmo problema que descrevi antes, ou seja, que este carregador comentado não funciona; eu tenho que usar esta versão CDN em vez disso. Eu realmente não sei por quê.

Eu acho que o seu código sofre do mesmo problema. É por isso que o AsciiMath não parece funcionar.

1 curtida

você pode verificar meu último commit, eu acho que adicionei um funil para o ember, então a compilação do ember coloca todos os arquivos no lugar certo.

2 curtidas

OK, tenho ótimas notícias e notícias frustrantes.

Primeiro, você está absolutamente certo de que adicionar o funil coloca esses arquivos no lugar correto. Adicionei o funil ao meu branch e agora funciona muito bem sem a dependência de CDN. :tada:

Infelizmente, não consigo executar seu código no momento. Sempre que navego para uma página com matemática, a matemática não é formatada e vejo a seguinte mensagem de erro no console:
Uncaught (in promise) Error: State EXPLORER already exists

Tenho certeza de que seu código estava funcionando antes, então suponho que seja algo que eu fiz. Para ser claro, eu literalmente comecei um diretório totalmente novo usando as técnicas descritas em Install Discourse on macOS for development.

git clone https://github.com/discourse/discourse.git ./discourse
cd ./discourse
bundle install
pnpm install
bundle exec rake db:create
bundle exec rake db:migrate
RAILS_ENV=test bundle exec rake db:create db:migrate

# Em um terminal
bundle exec rails server

# Em outro terminal
bin/ember-cli

Então peguei seu código com

git checkout 71ad0305f812311f2a4570edf7c33f97de46c457
git switch -c mathjax-sam

Mesmo a partir dessa configuração nova, eu recebo o erro.


Neste ponto, estou bem satisfeito com minha versão do código, mas ainda curioso sobre o que está acontecendo com o seu. Preciso fazer uma pausa nisso para o feriado, no entanto. Ficarei feliz em dar outra olhada nisso em alguns dias.

Um ponto final, no entanto: até onde sei,

await import("tex-mml-chtml.js") // seguido por
await import("input/asciimath.js")

não deveria funcionar, que é efetivamente o que seu código está fazendo, eu acho.

Estou sendo impreciso com os caminhos aí, mas meu ponto é que não sei se chamadas dinâmicas consecutivas para import levam à estrutura correta do MathJax. Acho que carregar componentes do MathJax é bem complicado e é por isso que eles têm um processo de carregamento tão detalhado com o objeto MathJax e tudo mais.

Muito obrigado pela sua ajuda e paciência @sam!

2 curtidas

Tenho feito progresso aqui:

Eu movi os payloads gigantes de javascript para uma gem dedicada

Isso tornará significativamente mais fácil manter-se atualizado, além disso, o mathjax não estará mais incluído no repositório.

3 curtidas

Olá Sam - Estive mexendo bastante nisso hoje. Está ótimo! Acho que ainda há muito a ser feito, no entanto. Algumas coisas, eu definitivamente posso ajudar. Algumas delas estão possivelmente além da minha capacidade, especialmente com a minha universidade começando novamente.

De qualquer forma, aqui estão algumas das minhas considerações.

Zoom

O zoom ao passar o mouse não está mais disponível no MathJax V4. É fácil configurá-lo para dar zoom ao clicar com a tecla alt, no entanto. Eu fiz isso aqui:

Note que há um bug conhecido do MathJax que precisa ser resolvido com um pouco de CSS, conforme descrito neste Issue do GitHub. Eu incluí essa correção neste código também.

Opções de carregamento

No estado atual, o AsciiMath não pode ser ativado e a Acessibilidade não pode ser desativada. Eu acho que isso se deve à forma como os submódulos são carregados sequencialmente em load-mathjax.js.

Como afirmei na minha última mensagem, é muito mais comum pré-definir um objeto window.MathJax que especifica quais componentes você deseja. O objeto MathJax é redefinido quando o script principal é carregado. Foi assim que consegui fazer isso funcionar na minha versão V3. Eu acho que poderia incorporar essa abordagem na sua base de código durante a primeira parte da próxima semana, se você quiser que eu tente?

Assim que resolvermos as opções, também pode valer a pena considerar se há novas opções disponíveis na V4 que devem ser incluídas.

O editor rico

Isto é simplesmente ótimo - estou super feliz em ver isso!

Eu me pergunto se seria possível ter um menu de contexto de IA brilhante disponível dentro do modal? Pergunto isso porque os alunos (e professores :confused:) às vezes têm dificuldade em digitar LaTeX. Um pequeno corretor ortográfico de IA pode tornar isso muito mais suave. Eu incorporei isso no meu Discourse de sala de aula e estou ansioso para usá-lo neste próximo semestre.


OK, tenho certeza que há muito mais, mas estou quase terminando por hoje.

Muito obrigado!!! :rocket: :fire: :tada:

3 curtidas

Entendo que o plugin discourse-math depende da gem de assets MathJax/KaTeX separada, em vez de incorporar essas bibliotecas diretamente, o que mantém o plugin leve e permite que as bibliotecas de matemática sejam atualizadas independentemente.

Gostaria de ajudar a validar isso antes do primeiro lançamento de produção, realizando alguns testes no mundo real. Minha ideia inicial foi criar uma instância separada e descartável e habilitar o plugin lá para testar conteúdo com muita matemática, carregamento de assets através do pipeline padrão, comportamento de CSP e desempenho.

Antes de fazer isso, gostaria de perguntar qual é o ambiente recomendado neste estágio – se testes antecipados em uma configuração semelhante à de produção é apropriado, ou se você prefere que isso seja feito usando um ambiente de desenvolvimento até o primeiro lançamento de produção.

Fico muito feliz em testar da maneira que for mais útil e relatar quaisquer problemas ou casos extremos que encontrar. Não posso me comprometer com um cronograma de testes fixo devido aos meus compromissos universitários, mas estou feliz em fazer testes com o melhor esforço quando o tempo permitir, e provavelmente terei disponibilidade significativamente maior após 6 de junho.

As opções estão funcionando bem agora; você pode ver o código aqui:

Aqui estão alguns comentários:

  • Toda a configuração e carregamento são tratados pelo objeto MathJaxInitConfig definido em math-renderer.js.
  • Removi uma boa quantidade de código inerte de load-mathjax.js.
  • A extensão 'ui/safe' é carregada sempre.
  • Adicionei uma opção “Menu de ativação de matemática do Discourse”, que é verdadeira por padrão. Quando falsa, isso remove o menu inteiramente, o que torna o MathJax ainda mais rápido.
  • Os próximos dois itens do menu são
    • Zoom de matemática do Discourse ao clicar e
    • Ativação da acessibilidade de matemática do Discourse.
      Estes não têm efeito se o menu estiver desativado, mas são independentes um do outro quando está ativado.

O menu inteiro fica assim:

Eu ainda não adicionei testes, mas posso tentar, se você quiser uma pull request.