mathjax / MathJax

Beautiful and accessible math in all browsers
http://www.mathjax.org/
Apache License 2.0
10.03k stars 1.16k forks source link

MathJax 4 warning and TeX conversion failure #2943

Open NSoiffer opened 1 year ago

NSoiffer commented 1 year ago

Issue Summary

In trying out v4, I get a warning "MathJax: Invalid option "enableAssisitiveMml" (no default value)."

I have

    MathJax = {
      loader: {load: ['input/tex', 'input/asciimath']},
      options: {
        enableMenu: false, // interferes with navigation
        enableAssistiveMml: true,
      }
    };

I didn't see anything in https://github.com/mathjax/MathJax-src/releases/tag/4.0.0-alpha.1 about a change regarding that option. The application doesn't run.

After fixing the above by commenting out the line, the application (see #2937) doesn't run. The error in the console is:

(index):30 MathJax conversion error:  Error: MathJax retry
    at t.retryAfter (tex-mml-chtml.js:1:768405)
    at a.enrich (tex-mml-chtml.js:1:43964)
    at Object.renderMath (tex-mml-chtml.js:1:82401)
    at t.renderConvert (tex-mml-chtml.js:1:83214)
    at e.convert (tex-mml-chtml.js:1:92292)
    at e.convert (tex-mml-chtml.js:1:86327)
    at t.MathJax.<computed> [as tex2mml] (tex-mml-chtml.js:1:70018)
    at ConvertToMathML ((index):25:28)
    at imports.wbg.__wbg_ConvertToMathML_1ba3a1bdd5856d88 (index-efa97dbedd7f5bfc.js:317:21)
    at <math_cat_demo::Model as yew::html::component::Component>::update::h0af6f1cc7b48c509 (index-efa97dbedd7f5bfc_bg.wasm:0x556ff)

The input is x = {-b \pm \sqrt{b^2-4ac} \over 2a} and the JS being run is

    function ConvertToMathML(math_str, math_format) {
      MathJax.startup.defaultReady();
      let options = {display: true};
      let mathml;
      try {
        if (math_format == 'ASCIIMath') {
          mathml = MathJax.asciimath2mml(math_str, options);
        } else if (math_format == 'TeX') {
          mathml = MathJax.tex2mml(math_str, options);
        } else {  // should be "MathML"
          mathml = MathJax.mathml2mml(math_str, options);
        };
      } catch (e) {
        console.error("MathJax conversion error: ", e);
        mathml = "<math><merror>MathJax conversion error</merror></math>"
      }
      console.log("ConvertToMathML:\n" + mathml.toString());
      return mathml;
    }

Environment

This is on Windows 10. In Firefox, I only see the warning. In Chrome, I get the above error:

dpvc commented 1 year ago

Thanks for trying out v4.0.0-alpha.

In the release notes section on the expression explorer, it mentions that the assistive MathML extension has been removed from the combined components (of which tex-mml-chtml.js is one). The various extensions make their options available when they are loaded, and enableAssistiveMML is part of the assistive MathML extension, so since that is no longer loaded, its options are no longer available. That could be made more clear in the documentation.

The "retry" error is due to dynamic loading components, in this case it seems to be something in the enrichment, probably waiting for SRE to fully initialize itself. There have been significant changes to SRE in this version, so its startup process may have different timing than in earlier versions. You probably should switch to using the promise-based conversion commands, as described in the v4.0.0 and promises section of the release notes. See the asynchronous typesetting main documentation for more details on these issues.

That section of the release notes also says some things you could do if you need to stay with synchronous calls, but in that case, you will probably still need to wait on MathJax's initialization promise before making any MathJax calls, so that you are sure everything is ready when you do. E.g., use something like

MathJax.startup.promise.then(() => {
  (start your application here)
});

An alternative is described in the two section of documentation on performing actions during initialization, which uses the startup object's ready() or pageReady() functions to synchronize your actions with MathJax's startup process.

Since the retry is coming from semantic enrichment (which is now on by default), If you are not interested in using semantic enrichment, you could disable it, and the explorer that depends on it, using configuration options:

MathJax = {
  options: {
    enableEnrichment: false,
    enableExplorer: false
  }
};

That might let you get by without the retry, though I haven't tried it out.

NSoiffer commented 1 year ago

Thanks for the quick response!

Unfortunately, at the time I wrote my WASM app, asynchronous execution wasn't an option (it appears I can do it now using a different library, but I don't have time for a rewrite at the moment). So I'm stuck with synchronous MathJaX usage, but that shouldn't be much of an issue since there is a lot of dead time after the page loads and there is only one MathJaX expression in the page.

I thought the MathJax.startup.defaultReady(); line at the start of the JS function was supposed to force a wait for MathJax to be ready. Did I misread the documentation or did it change in V4? It was working in V3.

Based on your suggestions and the documentation regarding the mhchem package, I changed the config to be:

    MathJax = {
      loader: {load: ['input/tex', '[tex]/mhchem', 'input/asciimath']},
      tex: {packages: {'[+]': ['mhchem']}},
      options: {
        enableMenu: false, // interferes with navigation
        enableEnrichment: false,
        enableExplorer: false,
      }

In the little bit of testing I did, this seems to be working and doesn't have the problem that started in v3.2 (see https://github.com/mathjax/MathJax/issues/2937 -- FYI I'm going to switch that page on Monday to 3.1 because I need to point some people to it to try some things out).

dpvc commented 1 year ago

I thought the MathJax.startup.defaultReady(); line at the start of the JS function was supposed to force a wait for MathJax to be ready. Did I misread the documentation or did it change in V4?

You misread the documentation. Javascript does not have the ability to "force a wait" for something without making the function that is doing the waiting into an asynchronous function itself (so whatever called it would need to wait for it, and whatever called that one would need to wait, and so on). If javascript had that ability, there synchronization would be much easier, and you would not have the same need for promises that we do. That need is built into the language, unfortunately, and is not really related to MathJax at all, as anything that would require a program to dynamically load something in a browser (as MathJax does) would need to deal with the fact that that loading is not synchronous, and that the program would have to deal with waiting for that using promises.

It was working in V3.

That is because there was no asynchronous action during startup of v3. Now that the explorer is included and active by default, that means enrichment by SRE is being performed, and so SRE must be ready to do the enrichment when you convert your mathematics. But SRE needs to load its language translation maps, and even though those are packages with the combined component, the loading is mediated by promises, and those always are asynchronous, even if they can be resolved immediately. (SRE can't tell whether the map files are packaged with it or not, and so always uses promises.)

Your use of MathJax.startup.defaultReady(); is non-standard (it was designed to be used in the ready() function in the startup block of your MathJax configuration, and only to be called once), so using it as you do is unusual, and may be the cause of the problems you report in your other open issue. One of the results of calling this will be to re-instantiate all MathJax's internal structures like the input and output jax and the main MathDocument object that kept track of the math that is in the page. That does give you a "fresh" input processor that is unaffected by previous expressions, but it also gives you a new output jax, and that one will not know about the CSS created by the previous one, and so the dynamically created CSS that is used to control the CHTML output may well get messed up by this.