Skip to content

MathJax v4.0.0-beta.2

Pre-release
Pre-release
Compare
Choose a tag to compare
@dpvc dpvc released this 17 Jul 16:44
· 440 commits to develop since this release

This is the second preliminary release of version 4, which we hope to be the last beta release before the official version becomes available. We include fixes for a number of issues reported with the alpha release, and add several new features and improvements as well. A significant one is that we now provide the MathJax JavaScript files as both ES modules as well as the older CommonJS format that we have been using in the past, and these newer ES modules are compiled into ES6 rather than the older ES5 used in earlier versions. This is discussed more fully below. There is a lot of information here, but you can use the links below to jump to the points that interest you.



New Features

This beta version of MathJax introduces the following significant new features in addition to those from the v4 alpha release.

ES6 Modules

When MathJax was first released, the current version of JavaScript was ES5, so when the code base was moved to Typescript for v3, it was down-compiled to produce ES5 code. Modern browsers support ES6, which include many new features, such as true object class creation and inheritance, proper import and export commands, Set and Map objects, promises, iterators, and many other features that make JavaScript programs faster and more reliable.

Along with new language features, ES6 introduced a new module structure that affects how individual javascript files obtain values from other files, and how they make their own definitions available to others. ES6 modules (which we will refer to as "MJS") use the new import and export commands to do this, while the older CommonJS module format (which we will call "CJS") used require() and the module.exports object to perform those functions.

MathJax v3 uses CommonJS modules with ES5 code (though this was not quite pure ES5, since one of its dependencies was actually ES6), but modern JavaScript applications are moving more and more to MJS format. Beginning with this beta version of v4, MathJax offers both MJS and CJS versions, with the MJS version being ES6, but the CJS version remaining ES5, as in past versions. The webpacked components for use in web pages are now based on the MJS versions.

Implications for MathJax in Web Pages

The webpacked MJS files are smaller than the earlier webpacked CJS files, so that should mean faster download and compile times, and the ES6 code is more efficient, so should run faster. But since this version is no longer ES5, the es5 directory that was part of the URLs for accessing MathJax from a CDN is no longer correct. The details of how the directories have been adjusted are given in the next section, but for use on the web, the only important difference introduced by the change to ES6 is that you simply remove the /es5 from the url. For example, you would use

https://cdn.jsdelivr.net/npm/mathjax@4.0.0-beta.2/tex-mml-chtml.js

to load the tex-mml-chtml.js combined component.

Support for IE11 has been dropped with this version, as it does not support enough of the ES6 standards. (It is possible to webpack the CJS versions, so you can build your own ES5 version if that is necessary for you. This is described at the end of this section below.) In version 3, we recommended a link to polyfill.io in order to support IE11. This can now be removed since this version will not work with IE11 even with the polyfill.

If your only usage is in a web browser, you can skip to the section on line breaking.

New Directory Structure

MathJax's new dual distribution of both MJS and CJS modules requires a new directory structure in the mathjax/MathJax-src repository and its associated mathjax-full npm package in order to accommodate both versions. In the past, the compiled JavaScript code was found in the js directory, and the webpacked components were in the es5 directory. Now that there are both CommonJS and ES-module versions of the compiled code, these are stored in the cjs and mjs directories, respectively.

The webpacked components are now based on the new mjs files, hence they are ES6 files, and so the es5 directory has been removed, with the components now being placed in the new generically named bundle directory. That way, if there is a move to ES7 or higher, the directory name doesn't need to change again. The mathjax/MathJax repository and associated mathjax package have also eliminated the es5 directory, and the combined components and component directories are now at the top level of the repository. That means you can access them without the need for /es5 in the URL that was needed in v3. (See the Availability section below for more information on how to access v4.0.0-beta.2 in a browser.)

Existing node applications that use MathJax may have code that refers to mathjax-full/js (e.g., the examples in the MathJax-demos-node repository), and mathjax-full/es5 or mathjax/es5 directories, which no longer exist. To accommodate these, this beta release includes an exports section in its package.json file that maps these references to the proper new locations. In particular, references to mathjax-full/es5 are routed to mathjax-full/bundle automatically, and similarly, mathjax/es5 is routed to mathjax. For the mathjax-full/js directory, references will be routed to mathjax-full/mjs or mathjax-full/cjs depending on whether the reference is from an import statement or a require() call. That means that ES modules (using import) will get the mjs versions, while CommonJS modules (using require()) will get the cjs ones, and so you can continue to use mathjax-full/js, mathjax-full/es5 and mathjax/es5 as you have in the past.

The main package.json file now includes a "type": "module" line so that the .js files are considered to be MJS files automatically. The cjs directory (and other directories that need to be marked as CJS files), contain separate package.json files that set the type to commonjs so that the .js files they contain will be treated as CJS files.

Similar changes have been made to the font directories in the font packages. In particular, there are mjs and cjs directories, and the es5 directory has been removed. The bundled files for the fonts are now in the top-level directory, as they are in the mathjax npm package.

Changes to components/src

The files that are used to create the webpacked component files are ES6 modules, since they use import and export, and in previous versions of MathJax, you needed to use node -r esm to be able to require() these in your own programs (you can't use require() to load ES modules directly). Although you could load the webpacked versions of the component files in either MJS or CJS applications, the fact that the source component files are MJS modules made it difficult to use the source versions of the components in CJS applications.

Now that MathJax provides both MJS and CJS versions, we wanted to allow the source component files to be available in both forms as well. Originally, the component files were found in components/src; with this beta version, those are now in components/mjs, since they are ES modules.

Prior to this version, MathJax used Babel to convert these to ES5 during the webpack process, but since the webpacked versions are now ES6, that is no longer necessary, and Babel is no longer needed as a dependency for MathJax. Instead, for those who wish to use the components from source in a CommonJS node application, we use Typescript to down-compile the components/mjs files into the components/cjs directory as CJS modules of ES5 code.

In previous versions, require('mathjax-full') would load components/src/node-main/node-main.js, which would load the components from source rather than the webpacked versions. With the mathjax package, which only includes the webpacked versions, require('mathjax') would get es5/node-main.js, the webpacked version. In this beta version, the two have been standardized so that they both load the webpacked version. When used with require(), you will get bundle/node-main.cjs, while import will load bundle/node-main.mjs. This is accomplished via the exports section of the package.json file.

In order to get the source versions in mathjax-full, use require('mathjax-full/source').init(...) or import {init} from 'mathjax-full/source' and then call init(...). These load components/mjs/node-main/node-main.mjs or components/cjs/node-main/node-main.cjs, respectively.

For those who have been using components/src to load individual components from source, we map components/src to components/mjs when included via an import command, and to components/cjs when included via require().

The end result is that you should always get an appropriate version for your situation, whether you are importing MathJax into an MJS application or requiring it into a CJS one.

More MJS/CJS Issues

Since MathJax now needs to produce javascript files in two different formats, we use different typescript configuration files for the different setups. These are stored in the tsconfig directory. The MJS files are produced using tsconfig/mjs.json and the CJS one use tsconfig/cjs.json. Both of these call in tsconfig/common.json to set the parameters that are common to both, and then specify the target and module values to be correct for the desired JavaScript version and module format. The main tsconfig.json file simply calls in tsconfig/mjs.def and is there as a convenience for tools that expect a tsconfig.json file in the main directory.

In order to support both MJS and CJS versions, MathJax's dependencies also must provide both versions. The speech-rule-engine, mj-context-menu, and mhchemparser packages all now include both module formats using dual directories similar to MathJax itself. This means that the imports used by MathJax for these packages need to change depending on which module version is being created. In order to accomplish this, the references to those packages are handled using pseudo-package references that are remapped to the correct locations via the tsconfig.json and package.json files.

To this end, MathJax now uses the #sre, #menu, and #mhchem pseudo-package names to refer to these packages. The main package.json file uses the imports section to map these to the actual package directories that contain their MJS JavaScript files. E.g., #mhchem/* is mapped to mhchemparser/esm/*, to obtain the ES module versions of the parser. Conversely, the package.json file that is placed in the cjs directory maps #mhchem/* to mhchemparser/js/* to obtain the CommonJS versions. Similar mappings are done for the other two packages.

In addition to the mappings in the package.json file to let node (and webpack) know which directory to use, Typescript must also be told where to look for the .d.ts files for these packages. This is accomplished through the tsconfig json files via the paths array.

MathJax takes its default font from one of the MathJax font packages, and that also has separate MJS and CJS directories, so the MathJax code uses a pseudo-package, #default-font, to link to the proper mjs or cjs directory in the font package. This also provides a means of specifying what the default font is (mathjax-modern by default), as changing the mappings in the package.json files and the tsconfig files would change the default font.

For the most part, MathJax's typescript source code can be used to produce either ES modules or CommonJS modules without alteration. But there are a few differences between MJS and CJS code that do need to be taken into account. For example, CommonJS code provides __dirname for the location of the file being compiled, but this is not available in MJS modules; meanwhile, MJS files must use new URL(import.meta.url).pathname to get that data, and import is not available in CJS modules. That means there is no common method that can be used for this in both cases, and so MathJax has some module-specific files to handle the few instances where module-specific code is needed.

To accommodate this, we introduce additional pseudo-package names that can be used to select between MJS and CJS files that export the needed data using the module-specific mechanisms. The #root and #mml3 pseudo-package names are used for these two situations in the Typescript code, and #js and #source are used in the components/mjs definitions to link to the mjs or cjs JavaScript code and to module-specific code for obtaining the directory name. These are mapped to the proper locations in the package.json files and the tsconfig files. The module-specific code that these link to are stored in mjs and cjs directories where they are needed, so that #root/root.js gets mapped to ts/components/mjs/root.js when MJS files are being produced, but to ts/components/cjs/root.js for CJS files. The tsconfig files exclude the directories for the other format so that they are not compiled when not needed.

Finally, since modern browsers can import MJS files, it is possible to load the MathJax files into a browser directly via a <script type="module"> tag. To do so, however, you need to include a <script type="importmap"> tag that tells the browser how to find the pseudo-packages described above. Something like

<script type="importmap">
{
  "imports": {
    "#js/": "./node_modules/mathjax-full/mjs/",
    "#source/source.cjs": "./node_modules/mathjax-full/components/mjs/source-lab.js",
    "#root/": "./node_modules/mathjax-full/mjs/components/mjs/",
    "#mml3/": "./node_modules/mathjax-full/mjs/input/mathml/mml3/mjs/",
    "#default-font/": "./node_modules/mathjax-modern-font/mjs/",
    "#sre/": "./node_modules/speech-rule-engine/js/",
    "#menu/": "./node_modules/mj-context-menu/js/",
    "#mhchem/": "./node_modules/mhchemparser/esm/",
    "mathjax-full/components/src/a11y/util.js": "./node_modules/mathjax-full/components/src/a11y/util-lab.js",
    "mathjax-full/components/src/": "./node_modules/mathjax-full/components/mjs/",
    "mathjax-full/js/": "./node_modules/mathjax-full/mjs/",
    "mathjax-full/": "./node_modules/mathjax-full/"
  }
}
</script>

should do the trick. Then you can set up your MathJax configuration in a file mathjax-config.js as in

import {source} from 'mathjax-full/components/src/source.js';

window.MathJax = {
  loader: {
    load: ['input/tex', 'output/chtml'],
    source: source
  }
};

and then use

<script type="module">
  import './mathjax-config.js';
  import 'mathjax-full/components/src/startup/startup.js';
</script>

to load MathJax components via their source code rather than webpacked files.

This is useful for testing changes to MathJax, but should not be used in production, as the number of files that will be loaded can be quite large, and each file will need to be retrieved separately, making for unneeded network overhead.

Component JSON files

In past versions of MathJax, the components/src directory contained files that control the production of the webpacked component files in the es5 directory. Each component had a subdirectory that contained files that told the MathJax build tools how to construct the component. These included at least one .js file that imported the needed MathJax modules and did any setup needed for the component, along with one or more of build.json, copy.json, and webpack.config.js that contain the data needed for the build tools to process the component.

In this version, these three .json files have been combined into a single config.json file that contains sections for each of the three original ones. The build property of config.json contains the data that used to be in build.json, the copy property holds what was in copy.json, and the webpack property holds the data needed to pack the component.

The webpack data primarily consists of the data that used to be passed to the PACKAGE() function in webpack.config.js, but as named properties, and only those that differ from the defaults need to be included (unlike the calls to PACKAGE() where all arguments were needed). The defaults are set up so that most properties don't need to be specified, just the name of the component and the libs array, in most cases. There are some additional properties that control whether the default font should be included in the packed file, or whether a function from an external file should be called to modify the default webpack configuration after it has been constructed. See the config.json files in the various components/mjs subdirectories for examples.

Building MJS and CJS versions

There are a large number of new package scripts used for building the files used by MathJax. The main changes are that there are separate commands for building the MJS and CJS files, along with new commands to make everything all in one step, and for making single components individually.

The npm run -s compile and npm run -s make-components scripts perform these steps for the MJS versions, and there is a new

npm run -s build

command that does both of these at once. The command

npm run -s build-all

not only compiles and packs the MJS versions, but also compiles the CJS versions.

Additional commands and details are given in the section on Changes to the Build Tools section below.

Reproducing the Old ES5 Webpack Files

The new webpacked components in the bundle directory are based on the MJS files, which are ES6 JavaScript files. In contrast, the earlier versions of MathJax had CJS versions of ES5 code. If you need to support an ES5 environment (like IE11), it is possible to build that using

npm run -s compile-cjs
npm run -s make-cjs-components

which will create a bundle-cjs directory that contains ES5 versions of the webpacked components, comparable to the old es5 directory.

The tsconfig.json file has the settings for the MJS versions of the JavaScript files, and if you use an editor like emacs, the typescript editing mode automatically compiles the .ts files based on tsconfig.json into the mjs directory. If you need to make modifications to the typescript files and your application links to the CJS versions of the compiled files, it may be convenient to switch the tsconfig.json file to produce the CJS versions instead. To do that, use

npm run -s use-cjs

which will point the tsconfig.json file to the parameters for compiling into the cjs directory instead. When you are done,

npm run -s use-mjs

will set things back to the original arrangement.

Improvements to Line Breaking

The v4 alpha release was the first to include MathJax's new line-breaking algorithm, and while it has been received well by those who have used it, some issues did arise.

First, there were situations in which the line-breaking could lead to an internal error; these have been resolved in this beta release.

Second, the spacing at potential breakpoints for in-line math was not always correct. This turned out to be due to some browsers' minimum font size limitations, and so this beta version uses a different approach to providing that space to avoid that problem.

Third, there was an issue when using the contextual menu to switch from SVG to CHTML output that would cause unwanted breaks for in-line expressions; that has been resolved here.

Finally, the TeX \allowbreak and related macros originally used mo elements for inserting the potential breakpoints; but this could lead to the mo being treated as an embellished operator, making the breakpoint appear in the wrong location. So this beta version now uses mspace elements instead, as they can't form embellished operators.

A subtler problem occurs within tables when breaks are needed in multiple columns. By default, the baseline of a cell that contains breakpoints is the baseline of the top line of the cell, and since the default row alignment is on the cell's baseline, this means that the rows align on the top lines' baselines. In the situation where the table is from an alignment environment, such as \begin{align}...\end{align}, if the first column requires breaks and the second has an equal sign at the beginning of it, then the equal sign appears to be after the top line of the first column, as shown below:

bad-align

which can cause confusing results. This beta version introduces additional controls for how cells containing line breaks should be aligned, and sets the defaults for environments like align so that the first column aligns on its bottom line while the second is on the top line, producing more effective results:

good-align

In addition, it introduces a new non-standard \breakAlign macro that can be used to set the vertical alignment for the various cells, rows, or columns in the alignment. The format is \breakAlign{type}{align}, where type is one of c, r, or t, indicating whether the alignment is for the single cell in which it occurs, the row in which it occurs, or for the entire table, and align is one of t, c, m, b, for top, center, middle, or bottom. The difference between c and m is that c always centers the cell regardless of line breaks, while m only centers if there are line breaks, and otherwise aligns on the cell baseline. When type is r or t, then align can be a sequence of these letters giving the alignments to use in each entry in the row, with the last one being repeated if there are more columns than letters. When type is t the alignments are applied as row alignments to each row in the table.

For example, \breakAlign{t}{bt} could be used at the beginning of an alignment to make the baseline of the bottom row of the first column align with that of the top row of the second column, as in the diagram above.

The same can be accomplished in MathML input using the new data-break-align attribute on the mtable, mtr, or mlabeledtr elements, or the data-vertial-align attribute for mtd elements. These can have values of top, center, middle, or bottom (repeated and space-separated for tables and rows).

The data-vertical-align attribute can be used on msqrt, mroot, and mrow elements as well to adjust how they are aligned when they contain line breaks. The default for roots is bottom, so that if line-breaks occur within a root, the root will align on its bottom line:

root-break

In TeX there is no direct control over this attribute within roots.

Improvements to Assistive Support

The following are the major improvements of a11y support in MathJax:

  • New Korean locale for speech output.
  • Explorer adaptation to support the exploration of line-broken elements.
  • New text heuristics that distinguishes genuine text elements from expressions that only use text to enforce font changes to roman or mathvariant=normal.
  • Improved speech output for tensor expressions.
  • Better support of self-voicing and synchronised highlighting via automatic marking of elements in SRE's SSML renderer. This also removes the old step renderer as it is no longer necessary.

Some changes that are available in this beta release, but that are still in an
experimental stage:

  • Option aria allows the generation of enriched expression that provide compatibility support for the ARIA tree role.
  • Generation of LaTeX snippets for subexpression, which are included in the MathJax data structure. This supports SRE's Euro Braille output also for sub-expressions. Note, that the Euro Braille option still needs to be set manually.
  • Improvements in alphabet generation and symbol translations reduces the size of the locale files in the distribution.

Changes To SRE's Code Structure

  • Updated build process to use ES modules instead of CommonJS modules. For compatibility reasons, CommonJS versions are still created, and both ES module and CommonJS sources are distributed.
    • New package structure: js contains JavaScript files in ES module format, cjs contains JavaScript files in CommonJS format.
  • XML handling in node now based on the latest @xmldom/xmldom library, making xmldom-sre obsolete.
  • Computation of Clearspeak moved to the MathJax code base.

Fixes

  • Correctly marks all newly created elements during the enrichment process by adding an added attribute.
  • Initialization bug in tree colorer.
  • Solves Firefox-related Xpath issue in tree colorer.
  • Correct treatment of all maction elements with toggle attribute.

The following are fixes related to libraries used in node:

  • Security fix due to xmldom vulnerability.
  • Fixes for Xpath problems due to incomplete implementation in xmldom-sre.

New TeX Features

This update includes several new features for the TeX input jax, including updated Unicode positions for some macros, new macros for characters that are now available in the fonts, updates to some TeX extensions packages, new configuration parameters, and a new macro for controlling vertical alignment of blocks with line breaks. More details are given below.

The Unicode characters produced by \vdash, \models, and \backslash have been adjusted to produce better results. The \iddots, \dddot, \ddddot, \oiint, \oiiint, \ointop, and \AA macros have been added, as have the displaymath, math, and darray environments.

The non-standard \bbFont and \scr macros have been removed, and the \frak macro has been made compatible with its usual LaTeX version.

The \underline, \llap, \rlap, \phantom, \vphantom, \hphantom, \smash, \mmlToken macros have been added to the textmacros package for use in text mode.

The \char macro is now available for inserting characters by their Unicode character positions. It produces an internal mn, mi, mo, or mtext element depending on the character specified. E.g., \char"61 produces <mi>a</mi> internally.

A new non-standard macro \U is now available for inserting a Unicode character into the TeX input string to be processed as though it had been in the input stream originally. It takes on argument, which is the Unicode code point in hexadeciaml notation. For example, \U{229E} would produce the character U+229E, a plus sign in a square. Note in particular that these macros can be used in the second argument to \mmlToken, as in \mmlToken{mi}{\U{213C}}.

A new non-standard macro \breakAlign has been added to control the vertical alignment of blocks that contain line breaks. This is discussed in the previous section on line breaks.

The units package has been added, which makes the \units, \unitfrac, and \nicefrac macros available. There are new tex.units.loose and tex.units.ugly configuration options. Both are boolean values, and the first controls how large the space is before units (true is a large space, false a smaller one), while the second determines whether \nicefrac produces bevelled fractions (false) or stacked fractions (true).

The configmacros package now allows you to create active characters that are bound to macros, so that

MathJax = {
  tex: {
    active: {
      'x': '\\mmlToken{mi}[mathvariant="bold"]{x}'
    }
  }
}

defined x to always produce a boldface x.

Note that you need to take care not to cause a loop by using the character you are making active in its own definition. In the example above, since the argument to \mmlToken is not further processed as TeX commands (except for instances of \U), that is not the case here.

A new formatRef configuration option has been added to the tagformat package that allows you to specify how \eqref is formatted. It should be a function that takes one argument, the tag associated with the specified label, and returns the string that should be used in place of the \eqref. The default is to use the result of formatTag, which is the string that will be used for the equation number on the equation itself. The returned string will be used as the link text for the link that targets the specified expression.

A new tex.tagAlign configuration option is now available that specifies how tags should be vertically aligned compared to their equations. The default is to align on the baseline, but you can specify top, center, bottom, baseline, or axis. One use case for this is when the equation is likely to have automatic line breaks inserted, in which case the baseline will be the baseline of the top line of the equation (in most cases), but you may want to have the alignment be the center of the broken equation rather than the baseline of the top line. Setting tagAlign to center would make sense in this case, without harming the usual placement for most equations.

A new tex.mathStyle configuration parameter has been added to control the italicization of variables in TeX expressions, as can be done in LaTeX via the math-style document setting. This can be set to one of TeX, ISO, French, or upright. The setting affects how upper- and lower-case Latin and Greek letters are italicized. TeX uses italics for all but upper-case Greek, whereas ISO makes everything italic, upright makes them all upright, and French makes everything upright except lower-case Latin letters.

When converting TeX to MathJax's internal MathML format, the TeX input jax will put multi-letter sequences into a single mi element when they appear inside \mathrm, \mathbf, and related macros. What constitutes a "letter" in this setting is now configurable via the tex.identifierPattern configuration option, which is a regular expression that indicates what characters should be combined into one identifier. The default value is /^[a-zA-Z]+/, but it can be extended to include other characters (e.g., numbers or accented characters) via this configuration option. Note that the pattern must begin with ^ to tie it to the beginning of the string.

Similarly, there is now a configuration option tex.ams.operatornamePattern to specify what should be put into a single mi within the argument to \operatorname. Because LaTeX treats - and * as text characters (rather than mathematical operators) within \operatorname, the default for this pattern is /^[-*a-zA-Z]+/. Again, the pattern should always begin with ^.

In the past, if an array environment had lines around the outside of the array, and there were mixed solid and dotted lines used, then MathJax might change some of them so that they are all the same style. This has been fixed in this version, so the boundary lines should now have the correct style in all cases.

Finally, the checking for proper nesting of AMS environments has been improved. This may affect existing expressions that are improperly nested but were not flagged by MathJax in the past. Previously, there was no check that these environments appeared at the top level of the expression, so an align environment could be used inside an array, for example; this now generates an error. On the other hand, gather should be allowed within align (but not another gather), but was being flagged as erroneous nesting; this is now allowed.

See the TeX Updates section for additional bugs that have been fixed.

New Output Features

The SVG output jax has two new configuration options. The first is svg.blacker, which is a number that indicates the stroke width (in thousandths of an em) to use for the character paths. Because some parts of some characters are very thin, the default is 3 in an attempt to help prevent those sections from disappearing at small sizes. Some page authors may wish to increase or decrease this in order to help the weight of the MathJax fonts better match the surrounding text font.

The second is svg.useXlink, which is either true or false, and specifies whether the SVG elements should use xlink namespaces for their href attributes. In HTML5, the xlink namespace is no longer necessary, but older systems may still require it, so the option is available.

In addition, the SVG output jax now groups characters that are not in the MathJax fonts into a single <text> element. That allows combining characters to combine, so that languages and emojis that use multiple characters to form a single glyph will be handled properly. So use \text{} around such characters to allow them to combine properly.

An improvement has been made in a long-standing issue with WebKit-based browsers, like Safari, where characters (particularly in runs of text) would not line up on the baseline properly. This is a bug in WebKit, but this version of MathJax includes a work-around that should help with the alignment in \text{}, \mathrm{} and similar macros, and other situations where the character are grouped into a single MathML element.

In the past, the hidden MathML that is produced by the assistive-mml extension could be rendered by the browser larger than the math typeset by MathJax, which could interfere with the size of the container for the expression. This version includes additional CSS to resolve this problem.

There are a number of improvements to the handling of accents and stretchy characters. In particular, there was an issue with some accents in some of the fonts where they could be offset too far to the left in some browsers (due to differences in how browsers treat combining characters whose width is not set to zero); this version includes a work-around for those differences. There are also improvements to the placement of accents, as well as for the handling of italic correction for super- and subscripts when the base is in \it or \mathit. In the alpha version, the skew data needed for proper accent placement was missing from the mathjax-tex font; that data is now included in this version.

Finally, data for additional stretchy characters was added to all the fonts for consistency so that they all now can stretch at least the ones that were stretchable in the original MathJax TeX font. The font npm packages have been updated to new versions that contain this data.

User-Interface Updates

Several new items have been added to the Show Math As and Copy to Clipboard submenus of the MathJax contextual menu. These include:

  • SpeechText, which is the generated speech string for the mathematical expression.
  • SVG Image, which is a serialized SVG object representing the expression, which can be pasted into a stand-alone image file for use elsewhere.
  • Error Message, which is the full error message when there is a TeX or MathML input error, or an internal MathJax error. In particular, when the TeX noerrors extension is used (so that error messages are not displayed within the page), this can give you the actual error message for an expression that doesn't typeset.

Note that SpeechText is only available when the assistive tools are available (as is the case for the default combined components). Similarly, SVG Image is only available when the SVG output jax is available (either in a configuration that loads it, or if the user changes to SVG output in the contextual menu).

There is also a new Filter semantic annotations entry in the Math Settings submenu that controls whether the MathML versions produced by the Show Math As and Copy to Clipboard menus will include the attributes that have been added by the semantic enhancement. There are a lot of these, and they can make the MathML hard to read, and generally are not necessary for use outside of MathJax, so the default is to filter these attributes, but you can uncheck that item if you want to include them in the MathML output.

API Changes

There are several API changes in this release, though most should not be breaking changes, as described below.

In the past, promise-based functions, like MathJax.typesetPromise(), MathJax.tex2chtmlPromise(), etc., could not be called while another one was currently in effect. That is, you needed to use the promise from one such call to tell when you could do the next call, and the documentation encouraged you to use MathJax.startup.promise to help chain these calls together. In this release, these functions now use MathJax.startup.promise internally to prevent more than one from running concurrently. In particular, you should no longer use MathJax.startup.promise yourself to serialize your calls to these functions.

In earlier versions, the MathDocument's inputJax array included any input jax that you have loaded. E.g., in the tex-mml-svg.js combined component, it would contain entries for both the TeX and MathML input jax. Because this is an array, it was not obvious which of the two entries was which (you would need to check each entry's name property to see if it is the one you want). In this release, the inputJax array also includes properties that point to the input jax by name. That is, inputJax.tex will point to the TeX input jax, if any, and similarly for inputJax.mathml.

As mentioned above, the fact that the webpacked components are now ES6 files means that MathJax will no longer run in IE11, so there is no need to include the polyfill.io script that was recommended in the documentation for IE11 support.

Also as mentioned earlier, the es5 directory has been removed from the MathJax distribution, so the /es5 should be removed from the URL used to access MathJax's components. Similarly, the font packages no longer need es5 in their URLs, so if you have set the output.fontPath or chtml.fontURL configuration options, you may need to remove the /es5 from them.

The tex.skipHtmlTags configuration property now includes select and option tags, since pop-up menu items can only contain textual content, not other HTML tags.

In addition to the new configuration options discussed the other sections above, there are two additional options available in this release:

  • options.menuOptions.settings.filterSRE, which controls whether to remove the data attributes generated by the speech-rule-engine from MathML output in the "Show Math As" and "Copy to Clipboard" menus.

  • mathml.verify.checkMathvariants, which controls whether the MathML input jax will check that mathvariant attribute values are valid math variants and report an error if not. Invalid mathvariant values can cause MathJax to crash under some circumstances, so the default value of this option is true, but this may cause current expressions with invalid math variant values that used to render to now show those nodes as having errors.

The lineWidth property of the Metrics object, used to store information about the font metrics of the container surrounding an expression, has been removed, as the line-breaking algorithm ended up using the containerWidth property directly. That affects functions that accept metric data as their inputs (such as MathDocument.convert() and MathJax.tex2chtml()), as these will no longer accept lineWidth in the options passed to them.

Some backward-compatibility code in v3 has been removed; e.g., when the tex.multlineWidth configuration option was moved to tex.ams.multlineWidth in an earlier version, there was code to move the old value to the new location, but that code has been removed in v4.

Changes to the Build Tools

The tools used for creating the webpacked component files have been significantly updated for this beta release. Partly this is to accommodate the changes needed for the production of the dual MJS/CJS files, and partly in order to make it easier to do individual steps of the build process in isolation. There are now package scripts for performing most of the development tasks that you might need to do if you are modifying MathJax or building your own components.

In the past, to compile the typescript files into javascript, you would use npm run -s compile, and to build the webpacked component files, you did npm run -s make-components. These commands are still available, but there is a new

npm run -s build

command that does both at once.

Because we now make both MJS and CJS versions of the MathJax files, there are commands to make each type. The commands above make the MJS versions, but there are also module-specific commands that make the MJS and CJS versions separately.

npm run -s compile-cjs
npm run -s compile-mjs

npm run -s make-cjs-components
npm run -s make-mjs-components

npm run -s build-cjs
npm run -s build-mjs

The generic versions are just aliases for the MJS-specific ones. Note that because the webpacked versions use the MJS JavaScript files, the make-cjs-components script is never run, but if you want to make ES5-based versions of the webpacked files,

npm run -s compile-cjs
npm run -s make-cjs-components

will create a bundle-cjs directory containing the ES5 webpacked files comparable to the ones that used to be in the es5 directory.

There is also

npm run -s build-all

that does both the build-mjs and build-cjs actions, creating all the files in the mjs, cjs, bundle and components/cjs directories.

Because the make-components action webpacks all the components, a time consuming process, there is a make-one script that webpacks only one component. The format for this is

npm run -s make-one <component> <module-type>

where <component> is the name of the directory in components/mjs that defines the component, and <module-type> is either mjs or cjs. For example

npm run -s make-one input/tex mjs

would pack only the TeX input component.

These commands all rely on the components/bin/makeAll script, which has been enhanced for this version. It now has a number of command-line options to control its functions, including:

  • --no-subdirs to prevent it from processing all the subdirectories of the given directory
  • --cjs to process using CJS rules
  • --mjs to process using MJS rules (the default)
  • --terse to only print the main headings rather than the file details like the files included in a webpacked version
  • --build to only perform the build steps (i.e., creating the lib directories used for shared imports)
  • --copy to only perform the copy steps (e.g., copying the CHTML woff files into place)
  • --pack to only do the webpack steps
  • --bundle-cjs to webpack into the bundle-cjs directory rather than the bundle directory

These can also be passed to npm run -s -- make-one if you want to restrict the steps performed (it already uses --no-subdirs and one of --cjs or --mjs).

These changes mean you only need to use makeAll, since it handles calling components/bin/build, components/bin/copy and components/bin/pack itself. The arguments for these sub-programs have changed in this version, particularly for components/bin/pack, so you should not call these by hand yourself unless you have looked at the internals of them carefully.

If you use a checked-out copy of this repository for your development, then there needs to be a symbolic link from node_modules/mathjax-full to this repository directory. That should be created automatically when you do npm install, but if you need to install other npm packages, that link will be removed by npm, so you will need to recreate the link. To do so, you can use

npm run -s link:full

which should produce the proper link for you.


Updates and Issues Resolved

This section lists the issues that are fixed and pull requests that are included in this release. Many of these include more details about the changes in the pull request associated with the issue, so be sure to look at both.

TeX Updates

MathML Updates

  • Fix problem with MML3 extension when MathML includes &nbsp;. (mathjax/MathJax#3030) (#949)

  • Add checks for valid mathvariant attributes. (#940)

  • Add a tooltip for MathML verification short errors that shows the full error. (#939)

  • Verify that <math> elements are not nested. (#938)

  • Add <html>, <head>, and <body> tags to MathML when parsing a MathML expression as HTML. (#880)

Output Updates

  • Allow inline-breaking within top-level nodes added by SRE (#971)

  • Honor the rule_thickness and surd_height font parameters. (#948)

  • Work around WebKit bug that causes baseline alignment problems. (mathjax/MathJax#2866) (#957)

  • Remove forced breaks that SVG inserted when switching to CHTML. (#956)

  • More reliable handling of stretchy assemblies. (#952)

  • Use <mspace> for \allowbreak, etc., and fix issues with <mspace> breaking. (#935)

  • Move handling of overflow scrolling to CSS and allow tagged expressions to scroll. (#945)

  • Remove Safari hack that is not needed with v4. (mathjax/MathJax#3023) (#933)

  • Better control over breaking in tables, and over vertical alignment of nodes containing breaks. (#927)

  • Handle <mrow> with class INNER as a unit to get spacing after it correct. (mathjax/MathJax#3018) (#930)

  • Fix issue with size of spaces for potential in-line break points, and improve line spacing when a breakpoint occurs. (mathjax/MathJax#3005) (#919)

  • Combine unknown characters into a common <text> element in SVG output. (mathjax/MathJax#2672) (#903)

  • Allow space for labels when deciding on a table's width for line breaking its columns. (#926)

  • Fix potential crash with line breaks. (mathjax/MathJax#3015) (#925)

  • Use left alignment and no indent for forced inline breaks when inline breaking is off. (mathjax/MathJax#3005) (#919)

  • Provide option to control how <mi> is italicized. (mathjax/MathJax#2570) (#900)

  • Add option to not use xlink namespace in serialized SVG output. (mathjax/MathJax#2929) (#910)

  • Allow SVG character stroke-width to be specified. (mathjax/MathJax#2859) (#909)

  • Better handling of scriptminsize. (mathjax/MathJax#2975) (#901)

  • Allow borders to inherit surrounding color in SVG. (mathjax/MathJax#2939) (#896)

  • Fix problems with size of horizontal stretchy characters in some cases. (mathjax/MathJax#2981)

  • Fix CHTML so that depth is correct for empty <mpadded> elements that have depth specified. (#891)

  • Improve vertical separation for x-arrows (#mathjax/MathJax#2981) (#887)

  • Work around combining characters being handled as 0-width automatically by some browsers. (#885)

  • Use proper scaling factors for placement of top and bottom of <munderover> when the construct is scaled (mathjax/MathJax#2983) (#898)

  • Update use of skew values from accents to allow better placement. (mathjax/MathJax#3051) (#966)

  • Don't remap U+0060 to U+2035 so \grave works properly. (#967)

User Interface Updates

  • Add SVG Image and Speech Text to Show As and Copy As menu items. (#942)

  • Better handling of dynamic submenus in the MathJax contextual menu. (#872)

  • Fix longstanding issues with the assistive explorer, and add autovoicing. (#857)

  • Update CSS used by assistive-mml so its size matches that of the typeset math. (mathjax/MathJax#2936) (#920)

  • Fix scaling of tooltips when text font is inherited. (mathjax/MathJax#2957) (#908)

API Updates

  • Make it easier to find a specific input jax by name. (#959)

  • Use promises when changing the renderer so that dynamic files can be loaded properly. (#950)

  • Make promise-based calls use MathJax.startup.promise to avoid concurrency. (#941)

  • Remove lineWidth from the Metrics object, since it is never used. (#936)

  • Remove backward-compatibility code from previous version. (#934)

  • Make sure math in multiple container elements are typeset in order. (mathjax/MathJax#2999) (#912)

  • Don't typeset within <select> or <option> nodes by default. (mathjax/MathJax#3006) (#911)

  • Allow semantic-enrich to enrich HTML-in-MML. (#890)

  • Only activate explorer if in a browser. (#878)


Availability of v4.0.0-beta

The MathJax 4.0.0-beta.2 version can be accessed via CDN as

https://cdn.jsdelivr.net/npm/mathjax@4.0.0-beta.2/tex-mml-chtml.js

or using one of the other combined configuration files:

  • tex-html.js
  • tex-svg.js
  • tex-mml-chtml.js
  • tex-mml-svg.js
  • mml-html.js
  • mml-svg.js

Each of these includes the mathjax-modern font, but also comes in a version ending in -nofont.js (e.g., tex-mml-chtml-nofont.js) that does not include it, where you are expected to specify the font using the output.font configuration option. This saves your readers from having to download the data for the mathjax-modern font that is not going to be used.

Note that the es5 directory is no longer needed in the URL when you are using mathjax@4.0.0-beta.2, as all the combined configuration files are now at the top level of the mathjax npm package that is used by CDNs to deliver MathJax.

The source code for MathJax v4 is available in the mathjax-full@4.0.0-beta.2 npm package, or in the v4.0.0-beta branch of the MathJax-src repository on GitHub.

The fonts are each in their own npm package, e.g., mathjax-modern-font, mathjax-stix2-font, etc., which you can install in your own node applications as needed. In a browser, MathJax should access the fonts from cdn.jsdelivr.com automatically. These font packages also include combined configuration files that are like tex-mml-chtml.js and tex-mml-svg.js, but that include that package's font rather than mathjax-modern. For example, the mathjax-stix2-font package include tex-mml-chtml-mathjax-stix2.js and tex-mml-svg-mathjax-stix2.js, so you can use

https://cdn.jsdelivr.net/npm/mathjax-stix2-font/tex-mml-chtml-mathjax-stix2.js

in order to get a single-file MathJax component that includes the mathjax-stix2 font rather than mathjax-modern. In particular, you can get the equivalent of the tex-mml-html.js file with the original MathJax TeX font all-in-one file using

https://cdn.jsdelivr.net/npm/mathjax-tex-font/tex-mml-chtml-mathjax-tex.js

This font does not have dynamic ranges (all the font data is in one file), so it should operate much the same as MathJax v3 in that respect, but it does have a more limited character coverage than the other fonts.