Actualizando Mathjax a la versión 4

@sam および Discourse で数式を入力することに関心のあるすべての皆様へ。discourse-math プラグインを更新し、非常に遅く時代遅れの V2 ではなく MathJax V3 を使用するようにしました。ご想像の通り、その結果、KaTeX と比較して機能豊富な環境を維持しながら、はるかにすばやいユーザーエクスペリエンスが得られました。

結果が良ければ、プルリクエストを発行したいと思います。


私のクラスの Discourse サイトで実際に動作しているのを見ることができます。

そのサイトのコンテンツのほとんどは非公開または未掲載です。MathJax V3 カテゴリのトップに、アイデアを示すいくつかのトピックがあるはずですが。

プラグインのコードは、このスタンドアロンの discourse-mathjax プラグインリポジトリで確認できます。最も多くの変更が加えられているファイルは、initializer です。

また、そのリポジトリを使用して、スタンドアロンサイトに今すぐインストールすることもできます。インストール時に古いリポジトリを削除するようにしてください。したがって、標準のプラグインインストール手順を次のように変更する必要があります。

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

コメント

MathJax の最新バージョンは実際には 4.0.0 です。私が V3.2.2 を選択したのにはいくつかの理由があります。

  • V4 は V2 よりも間違いなく高速ですが、V3 ほど高速ではありません。
  • 特にユーザーが出力をクリックした場合など、V4 ではユーザーエクスペリエンスが少し異なります。
  • 4.0.0 のステータスは、バグがどれくらいあるのか疑問に思わせます。

とはいえ、V4 の API は V3 と同じです。後で最新の MathJax リポジトリをドロップするだけでアップグレードできるはずです。

locales/server.en.yml ファイルで 1 つの小さな変更を加える必要がありました。もちろん、さまざまな言語に対応する他のファイルもたくさんあります。私の理解では、それらの他のファイルは後で自動的に翻訳されるということでしょうか?

私はチャットをまったく使用せず、そのコンテキストでテストしていません。

4 Me gusta

¡Solicitud de extracción para actualizar MathJax a V3 realizada con todas las pruebas pasadas!

2 Me gusta

Con respecto a:

Esto es fantástico :hugs: , pero me pregunto si podemos aprovechar esto como una oportunidad para reducir un poco nuestro repositorio.

Ahora que hemos movido MathJax al núcleo, podemos apoyarnos en pnpm para obtener el paquete y evitar incluir en el paquete todo el código fuente como lo hacemos para FullCalendar, por ejemplo.

En particular, el objetivo es tener solo “enlaces” en nuestro repositorio y luego podemos usar el proceso de compilación para obtener las dependencias correctas.

Danos unos días, quiero consultar con el equipo de experiencia de desarrollo (dev xp) aquí. ¡Muchas gracias por tus esfuerzos!

4 Me gusta

Sí, creo que eso es sin duda lo correcto. Siempre me pregunté por qué empaquetabas todo el paquete.

Entonces, supongo que crearás una función loadMathJax para tu librería que se utiliza para cargar MathJax.

Debo decir que integrar todos los complementos en el núcleo ha hecho que sea un poco más complicado jugar con ellos. Vincular las dependencias al proceso de compilación solo lo haría aún más difícil, aunque estoy seguro de que podría obtener MathJax o FullCalendar desde una CDN.

Principalmente estoy hablando de cuando retoque complementos para usarlos en mis propios foros, y estoy absolutamente de acuerdo en que deberías obtener MathJax durante la compilación.

¡Absolutamente! He estado usando Discourse durante años y estoy muy feliz de que pienses que esto es fantástico. :rocket:

3 Me gusta

Sí, exactamente. Una buena para copiar es morphlex:

1 me gusta

Me pregunto si has podido hablar con tu gente de experiencia de desarrollador todavía. Estaría encantado de ayudar, si puedo. Mi impresión, sin embargo, es que realmente no hay nada que pueda hacer sin tus comentarios al respecto.

He hecho algunos cambios adicionales en una rama separada, sobre los que publicaré pronto. Soy consciente de que tienes mucho en tu plato, ¡así que no pretendo ser una molestia!

He modificado el plugin discourse-math para que pueda analizar muchas más entradas matemáticas.

@sam Cuando contribuí por primera vez a este plugin en 2017, recuerdo que fuiste muy firme en que querías un análisis muy estricto. Permíteme decir de entrada que mi principal motivación para relajar y extender el análisis fue para que funcionara mejor con la IA. En particular, cuando chateas sobre matemáticas con un bot de IA, a menudo descubrirás que responde usando LaTeX y hay muchas maneras en que podría elegir delimitar esa entrada LaTeX. Por lo tanto, aunque entiendo tu motivación para un análisis estricto, los cambios que he realizado son bastante esenciales para ese caso de uso.

Por supuesto, es posible que todavía no te importe ese caso de uso, así que he puesto los cambios en una rama separada de mi solicitud de extracción (pull request) V3. Si decides que te gustan, estaré encantado de emitir otra solicitud de extracción.

Los cambios específicos en la solicitud de extracción son:

Acepta matemáticas en línea delimitadas por barra invertida y paréntesis como \(a^2+b^2=c^2\).

Acepta matemáticas de visualización delimitadas por doble signo de dólar de una sola línea como
$$a^2+b^2=c^2.$$

Acepta matemáticas de visualización delimitadas por barra invertida y corchetes de una sola línea como
\[a^2+b^2=c^2.\]

Acepta matemáticas de visualización delimitadas por barra invertida y corchetes de varias líneas como
\[
a^2+b^2=c^2.
\]

Por supuesto, todavía acepta las entradas del original:

Matemáticas en línea delimitadas por signo de dólar: $a^2+b^2=c^2$.

Matemáticas de visualización delimitadas por doble signo de dólar de varias líneas:
$$
a^2+b^2=c^2.
$$

Puedes encontrar la rama relevante aquí.

El código también existe como un plugin independiente.

¡Ah, también puedes verlo en acción!

2 Me gusta

@mcmcclur Gracias por tu trabajo. Sería genial ver estas características en el núcleo.

1 me gusta

Muchas gracias, Mark.

Mi gran obstáculo aquí es que realmente quiero adoptar los nuevos patrones para la distribución de dependencias, mira:

¿Podrías echarle un vistazo a esto?

Con respecto a la sintaxis relajada, me parece una configuración del sitio, ¿quizás incluso predeterminada dado todos los LLM que existen?

3 Me gusta

@mcmcclur Estuve jugando con esto hoy:

Lejos de estar listo… pero las cosas arrancan con 4.1, lo cual es bueno.

2 Me gusta

¡Sí, esto es definitivamente un progreso!
El primer problema clave a abordar, como sospecho que sabes, es que las fuentes no se encuentran. De hecho, modifiqué esta línea en discourse-math-mathjax.js:

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

Como prueba, configuré la URL para que apunte simplemente a un directorio temporal en mi propio servidor web, y los resultados iniciales se ven muy bien. Así que es una cuestión de instalar esas fuentes correctamente en Discourse.
En un proyecto simple de pnpm en mi máquina, el siguiente comando instala las fuentes:

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

Cuando ejecuto ese comando dentro de discourse/frontend/discourse, las fuentes aparecen en

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

Sin embargo, esas fuentes no parecen terminar en /assets/mathjax/woff-v2 después de la compilación. He probado varias variaciones del directorio, pero no he logrado que funcione. Supongo que es algún tipo de magia de enrutamiento en la que no soy experto. Estoy bastante seguro de que podría lograr un buen progreso para limpiarlo una vez que se resuelva ese problema de ruta.

1 me gusta

@sam Creo que he logrado un progreso bastante significativo en esto, con una advertencia importante. No estoy seguro de dónde cargar los componentes deseados. Expresado en código:

window.MathJax = {
    loader: {
      // Esto no funciona:
      // paths: { mathjax: getURLWithCDN("/assets/mathjax") },
      // Pero esto funciona muy bien:
      paths: { mathjax: "https://cdn.jsdelivr.net/npm/mathjax@4.1.0" },
      load: ["core", "input/tex", "input/mml", "output/chtml", "output/svg"],
    },
    // Más configuración ...
  };

Cuando digo que la versión comentada no funciona, me refiero a que recibo el mensaje explícito:
MathJax(core): No se puede cargar “/assets/mathjax/core.js”

Nótese que, en ambos casos, la función loadMathJax está extrayendo el inicio de MathJax de la copia local. Es decir, tengo lo siguiente en
/discourse/frontend/discourse/app/static/mathjax-bundle.js

export * from "mathjax/startup.js";

Luego, loadMathJax definido en
/discourse/frontend/discourse/app/lib/load-mathjax.js
llama a

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

Esto sugiere un par de posibilidades:

  1. ¿Quizás /assets/mathjax no es la ubicación correcta o
  2. ¿Quizás estos activos necesitan registrarse de alguna manera para que aparezcan en la distribución (dist)?

Trabajando con la versión CDN, parece que puedo lograr un progreso significativo, pero supongo que ese es un gran obstáculo para ti.

Podría compartir mi código contigo, si quieres, ¿pero es esta información suficiente para un diagnóstico?

1 me gusta

Absolutamente, el código será muy útil aquí, quizás bifurcar Discourse y luego enviar tus cambios a una rama, entonces podré obtener los cambios de tu rama para la PR.

Muy contento de que estés progresando, tratando de diagnosticar este problema.

¿Puedes también obtener la última versión? Hice una ronda de limpieza.

1 me gusta

OK, aquí está el código:

Sin embargo, ten cuidado, no trabajé directamente a partir de tu último commit. Empecé directamente desde el main de Discourse e hice cambios a partir de ahí. Por lo tanto, aprendí bastante de tu trabajo, pero la estructura general es diferente.

Creo que podrías resumir la principal diferencia de la siguiente manera: donde tú (naturalmente) usas características de Discourse heredadas de Ember para coordinar los tiempos asociados con cosas como la carga y el formateo, yo uso características de MathJax. Por lo tanto, mis paquetes load-mathjax y mathjax (uno para svg y otro para chtml) son mucho más simples que los tuyos. La carga se coordina a través del objeto window.MathJax en discourse-math-mathjax.

Todavía tengo el mismo problema que describí antes, a saber, que este cargador comentado no funciona; tengo que usar esta versión CDN en su lugar. Realmente no sé por qué.

Creo que tu código sufre del mismo problema. Por eso AsciiMath no parece funcionar.

1 me gusta

¿Puedes revisar mi último commit? Creo que añadí un funnel para Ember, así que la compilación de Ember pone todos los archivos en el lugar correcto.

2 Me gusta

OK, tengo muy buenas noticias y algunas frustrantes.

Primero, tienes toda la razón en que agregar el embudo coloca esos archivos en el lugar correcto. Agregué el embudo a mi rama y ahora funciona muy bien sin la dependencia de CDN. :tada:

Desafortunadamente, no puedo ejecutar tu código en este momento. Cada vez que navego a una página con matemáticas, estas no se componen y veo el siguiente mensaje de error en la consola:
Uncaught (in promise) Error: State EXPLORER already exists

Estoy seguro de que tu código funcionaba antes, así que supongo que es algo que hice. Para ser claro, literalmente comencé con un directorio completamente nuevo usando las técnicas descritas en 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

# En una terminal
bundle exec rails server

# En otra terminal
bin/ember-cli

Luego tomé tu código con

git checkout 71ad0305f812311f2a4570edf7c33f97de46c457
git switch -c mathjax-sam

Incluso desde esa configuración nueva, obtengo el error.


Llegados a este punto, estoy bastante contento con mi versión del código, pero sigo sintiendo curiosidad por lo que está pasando con el tuyo. Necesito tomarme un descanso de esto por las vacaciones, sin embargo. Estaré encantado de echarle un vistazo en unos días.

Un último punto, sin embargo: hasta donde sé,

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

no debería funcionar, que es efectivamente lo que tu código está haciendo, creo.

Estoy siendo impreciso con las rutas ahí, pero mi punto es que no sé si las llamadas dinámicas consecutivas a import conducen a la estructura correcta de MathJax. Creo que cargar los componentes de MathJax es bastante complicado y por eso tienen un proceso de carga tan detallado con el objeto MathJax y todo lo demás.

¡Muchas gracias por tu ayuda y paciencia, @sam!

2 Me gusta

He estado progresando aquí:

Moví las cargas útiles gigantes de javascript a una gema dedicada

Esto hará que sea significativamente más fácil mantenerse actualizado, además de que mathjax ya no se registra en el repositorio.

3 Me gusta

Hola Sam, he estado jugando con esto bastante hoy. ¡Se ve genial! Aunque creo que todavía queda mucho por hacer. Algunas cosas, definitivamente puedo ayudar. Otras, posiblemente están más allá de mi capacidad, particularmente con el inicio de mi universidad.

De todos modos, aquí hay algunas de mis ideas.

Zoom

El zoom al pasar el ratón ya no está disponible en MathJax V4. Sin embargo, es fácil configurarlo para que haga zoom con alt-clic. Lo he hecho aquí:

Ten en cuenta que hay un error conocido de MathJax que debe abordarse con un poco de CSS, como se describe en este Issue de GitHub. También he incluido esa corrección en este código.

Opciones de carga

Tal como está, AsciiMath no se puede activar y Accesibilidad no se puede desactivar. Creo que eso se debe a la forma en que los submódulos se cargan secuencialmente en load-mathjax.js.

Como mencioné en mi último mensaje, es mucho más común predefinir un objeto window.MathJax que especifique qué componentes deseas. El objeto MathJax se redefine cuando se carga el script principal. Así es como pude hacer que esto funcionara en mi versión V3. ¿Crees que podría incorporar ese enfoque en tu base de código durante la primera parte de la próxima semana, si quieres que lo intente?

Una vez que resolvamos las opciones, también podría valer la pena considerar si hay nuevas opciones disponibles en V4 que deberían incluirse.

El editor enriquecido

Esto es simplemente genial, ¡estoy muy feliz de verlo!

Me pregunto si sería posible tener un menú contextual de IA brillante disponible dentro del modal. Lo pregunto porque a los estudiantes (y profesores :confused:) a veces les cuesta escribir LaTeX. Un pequeño corrector de pruebas de IA puede hacer que eso sea mucho más fluido. Lo he incorporado en mi Discourse de clase y estoy deseando usarlo el próximo semestre.


OK, estoy seguro de que hay mucho más, pero por hoy ya he terminado.

¡¡¡Muchas gracias!!! :rocket: :fire: :tada:

3 Me gusta

Entiendo que el complemento discourse-math depende de la gema de activos MathJax/KaTeX separada en lugar de incorporar esas bibliotecas directamente, lo que mantiene el complemento ligero y permite que las bibliotecas de matemáticas se actualicen de forma independiente.

Me gustaría ayudar a validar esto antes del primer lanzamiento en producción realizando algunas pruebas en el mundo real. Mi idea inicial era iniciar una instancia separada y desechable y habilitar el complemento allí para probar contenido con muchas matemáticas, la carga de activos a través de la canalización estándar, el comportamiento de CSP y el rendimiento.

Antes de hacerlo, quería preguntar cuál es el entorno recomendado en esta etapa: si una prueba temprana en una configuración similar a la de producción es apropiada, o si preferirían que esto se hiciera utilizando un entorno de desarrollo hasta el primer lanzamiento en producción.

Estoy muy dispuesto a probar de la manera que sea más útil e informar cualquier problema o caso extremo que encuentre. No puedo comprometerme a un horario de pruebas fijo debido a mis compromisos universitarios, pero estoy dispuesto a hacer pruebas lo mejor que pueda cuando el tiempo lo permita, y es probable que tenga mucha más disponibilidad después del 6 de junio.

Ya he conseguido que las opciones funcionen bien; puedes ver el código aquí:

Aquí hay algunos comentarios:

  • Toda la configuración y carga son manejadas por el objeto MathJaxInitConfig definido en math-renderer.js.
  • He eliminado una buena cantidad de código inerte de load-mathjax.js.
  • La extensión ‘ui/safe’ se carga siempre.
  • He añadido una opción “Discourse math enable menu” (Habilitar menú de matemáticas de Discourse), que es verdadera por defecto. Cuando es falsa, esto elimina el menú por completo, lo que hace que MathJax sea aún más rápido.
  • Los siguientes dos elementos del menú son
    • Discourse math zoom on click (Zoom de matemáticas de Discourse al hacer clic) y
    • Discourse math enable accessibility (Habilitar accesibilidad de matemáticas de Discourse).
      Estos no tienen efecto si el menú está deshabilitado, pero son independientes el uno del otro cuando está habilitado.

El menú completo se ve así:

Aún no he añadido ninguna prueba, pero podría intentarlo si quieres una solicitud de extracción (pull request).