upgrading/whats-new-4.0/breaking.rst
.. _v4-breaking-changes:
A number of breaking changes have already been mentioned elsewhere:
v4-scoped-packages discusses the change to scoped npm
packages, and in particular, moving from mathjax-full to
@mathjax/src.v4-promises discusses the greater need to use promises in v4.v4-es6-modules discusses the changes to the directory
structure and the removal of the /es5 from the URLs used to
obtain MathJax from a CDN.v4-tex-improvements discusses some potentially breaking
changes for some pages, including the fact that the the
:ref:tex-textmacros extension is now included in all combined
components, the update to the :ref:tex-mathtools extension to
include the changes in the corresponding LaTeX package from 2022 and
2024, and the change from :data:digits to :data:numberPattern
for configuring the pattern used to identify a number in TeX input.In addition to those, there are a number of other potentially breaking changes, as described below.
.. _v4-all-packages:
The AllPackages.ts file and the all-packages extension were
intended as a means of loading most of the TeX extensions up front so
that you did not need to worry about asynchronous loading of
extensions via the autoload package. But now that MathJax's
output is also asynchronous, using AllPackages is no longer
sufficient to allow for synchronous processing. As more extensions
have been created, they have not all been added to AllPackages.ts,
and as the library of extensions, both core and third-party, grows, it
is impractical to keep all of them in one package. So in this
release, these files have been removed. For those employing MathJax
in node applications, you can use
.. code-block:: js
import {source} from '@mathjax/src/components/js/source.js'; const AllPackages = Object.keys(source).filter((name) => name.substring(0,6) === '[tex]/').sort();
to get a list of the main TeX packages. For use on the web, you could use
.. code-block:: html
<script type="importmap"> { "imports": { "#source/source.cjs": "https://cdn.jsdelivr.net/npm/@mathjax/src@4/components/mjs/source-lab.js" } } </script> <script type="module"> import {source} from 'https://cdn.jsdelivr.net/npm/@mathjax/src@4/components/mjs/source.js'; const load = Object.keys(source).filter((name) => name.substring(0,6) === '[tex]/').sort(); const packages = ['base'].concat(load.map((name) => name.substring(6))); window.MathJax = { loader: {load}, tex: {packages} }; </script>to load all the extensions. Add any other configuration options that
you need to the :data:window.MathJax variable.
.. _v4-breaking-speech:
The :ref:v4-api-changes section describes the separation of the
semantic enrichment from the speech generation and the introduction of
a new speech component. Because the speech is now generated within
a web worker or node worker thread, the speech-generation code is no
longer in the main MathJax components, but is in a separate file that
is run in the worker. That means there is no more access to speech
generation directly within MathJax (it is only available in the
worker). In particular, the ts/a11y/sre.ts file now only includes
the semantic-enrichment methods of the speech-rule engine, and
:js:meth:Sre.toSpeech() is no longer available. In a node
application, you can load this function directly from the
speech-rule-engine's API, however. Here is an example command-line
script that takes a TeX expression and returns its speech string using
this approach:
.. code-block:: js
// // Load the modules needed for MathJax // import {mathjax} from '@mathjax/src/js/mathjax.js'; import {TeX} from '@mathjax/src/js/input/tex.js'; import {liteAdaptor} from '@mathjax/src/js/adaptors/liteAdaptor.js'; import {RegisterHTMLHandler} from '@mathjax/src/js/handlers/html.js'; import {SerializedMmlVisitor} from '@mathjax/src/js/core/MmlTree/SerializedMmlVisitor.js'; import {STATE} from '@mathjax/src/js/core/MathItem.js';
// // Import the speech-rule-engine // import '@mathjax/src/components/require.mjs'; import {setupEngine, engineReady, toSpeech} from 'speech-rule-engine/js/common/system.js';
// // Import the needed TeX packages // import '@mathjax/src/js/input/tex/base/BaseConfiguration.js'; import '@mathjax/src/js/input/tex/ams/AmsConfiguration.js'; import '@mathjax/src/js/input/tex/newcommand/NewcommandConfiguration.js'; import '@mathjax/src/js/input/tex/noundefined/NoUndefinedConfiguration.js';
// // The em and ex sizes and container width to use during the conversion // const EM = 16; // size of an em in pixels const EX = 8; // size of an ex in pixels const WIDTH = 80 * EM; // width of container for linebreaking
// // Create DOM adaptor and register it for HTML documents // const adaptor = liteAdaptor({fontSize: EM}); RegisterHTMLHandler(adaptor);
// // Create input jax and a (blank) document using it // const tex = new TeX({ packages: ['base', 'ams', 'newcommand', 'noundefined'], formatError(jax, err) {console.error(err.message); process.exit(1)}, // // Other TeX configuration goes here // }); const html = mathjax.document('', { InputJax: tex, // // Other document options go here // });
// // Create a MathML serializer // const visitor = new SerializedMmlVisitor(); const toMathML = (node => visitor.visitTree(node, html));
// // Convert the math from the command line // const mml = html.convert(process.argv[2] || '', { display: true, em: EM, ex: EX, containerWidth: WIDTH, end: STATE.CONVERT // stop after conversion to MathML });
// // Set up the speech engine to use English // const locale = process.argv[3] || 'en'; const modality = locale === 'nemeth' || locale === 'euro' ? 'braille' : 'speech'; await setupEngine({locale, modality}).then(() => engineReady());
// // Produce the speech for the converted MathML // console.log(toSpeech(toMathML(mml)));
With the speech generation being performed in a worker, the process is now inherently asynchronous, as the communication between the main thread and the worker thread is mediated by promises. That means that speech generation can't be done synchronously, and you must use the promise-based functions for handling typeset and conversion operations that involve speech, unless you use a technique like the one above.
The speech-generation process now applies the speech attributes to the DOM nodes themselves, rather than to the internal MathML structure (as was done in v3), so serialized versions of the internal MathML will not include the speech as they did in the past.
.. _v4-breaking-names:
Some name changes have occurred within the code to help clarify the
purpose of some objects or methods. In particular, the
:js:meth:Loader.preLoad() method has been renamed
:js:meth:Loader.preLoaded() in order to make it clear that this does
not itself load the given components, but that your code has done that
and you are telling MathJax that they have already been loaded.
Another change involves the objects used to handle CSS styles.
MathJax has two object classes that deal with CSS definitions, one
that specifies CSS styles via object literals (essentially JSON
structures), and one that parses a CSS string into an object structure
that acts like a DOM element's :attr:style attribute. Moreover both
modules declared a :data:StyleList type, and these were not
compatible. That both caused confusion and complicated their use
together in the same module, so the names for these types and objects
have been changed in this release in order to make it clearer which is
which.
To accomplish this, the ts/util/CssStyles.js file was renamed to
ts/util/StyleJson.js, and with that, :data:StyleList is changed
to :data:StyleJson, :data:StyleData to :data:StyleJsonData, and
:data:CssStyles to :data:StyleJsonSheet. This more accurately
describes what this object does (it is the one that takes JSON data),
and what the objects represent, while the ts/util/Style.ts file
implements (a subset of) the DOM object :attr:style attribute.
The move to ESM modules and compiling to ES6 rather than ES5 lead to
an issue with the webpacked versions of some component files that
would cause errors when they are loaded. The source of the problem
was due to the use of a custom :data:Symbol class in MathJax's TeX
input jax that conflicts with the native javascript :data:Symbol
object. This was not an issue in previous versions of MathJax, but
due to differences between how webpack handles CommonJS and ESM
modules, it caused problems with some TeX extension packages that use
the :data:Symbol class. This has lead us to rename the custom
:data:Symbol class to :data:Token, and rename the Symbol.ts
and SymbolMap.ts files to Token.ts and TokenMap.ts. This
is a potential breaking change to those who have created their own TeX
extension packages that load one of these files.
The names of a number of internal objects have been normalized to be
Pascal case (like camel case, but with an initial upper-case letter).
For example, the internal MathML items like CHTMLmath have been
renamed as ChtmlMath. Such changes would only affect those
writing their own extensions, but for those who do, you may need to
adjust the names of classes like this.
Finally, the latest.js file has been removed, as jsdelivr.net
and other CDNs handle providing the latest version automatically, and
with more granularity than this file did.
|-----|