mathjax/MathJax-demos-node

Using MathJax node in an ES module

rnwst opened this issue · 2 comments

rnwst commented

I have a node project which is an ES module (package.json contains "type": "module"). I'm trying to use MathJax to typeset an HTML page server-side. The demos use the shebang #! /usr/bin/env -S node -r esm, which preloads esm. This allows mixing CJS module (require() and module.exports) and ESM (import and export) syntax. If I use the same shebang, I get the following error:

Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/project/file.js not supported.
Instead change the require of file.js in null to a dynamic import() which is available in all CommonJS modules.] {
  code: 'ERR_REQUIRE_ESM'
}

If I change the shebang to #!/usr/bin/env node, mixed CJSM and ESM syntax no longer works:

(node:23193) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use `node --trace-warnings ...` to show where the warning was created)
/path/to/project/node_modules/mathjax-full/components/src/node-main/node-main.js:83
export {init};
^^^^^^

SyntaxError: Unexpected token 'export'

Using esm isn't really an acceptable option for me in the first place, as it hasn't seen any commits since 2019 and doesn't support modern Javascript features like optional chaining. Therefore, the real issue it seems to me is that MathJax is mixing CJSM and ESM syntax.

Is there any way I can use MathJax in an ES module?

Version info:
node v19.2.0
mathjax-full@3.2.2
└esm@3.2.25

dpvc commented

MathJax's typescript source is compiled into ES5 .js files, and since ES5 predates import/export, those .js files use require(). So the first thing you would ned to do is modify the tsconfig file to output ES6 my changing

    "target": "ES5",

to

    "target": "ES6",

and also probably also change the exclude to list es6.

Then recompile MathJax using

npm run -s compile

Then if you are using components rather than direct calls to the MathJax modules, you will need to rebuild the components. You may want to adjust the components/webpack.common.js file to change the es5 references to es6 (so that it builds the components into an es6 directory rather than the current es5 one). There are a couple of copy.json files that you might want to direct to the es6 directory as well. Use

grep -r es5 components/

to find them and see if they are for components that you will be using.

Then rebuild the components

npm run -s make-components

Then you should be able to import the components from the es6 directory, or the .js files from the js directory.

The examples in this demo repository are just samples, not part of MathJax proper, and you should be able to convert the require() commands to import commands easily enough, other than the ones in the simple directory, as those use the components/src/node-main/node-main.js file, which uses require and would need to be modified to avoid that. Your best bet is probably the examples in the components directory (or the direct directory if you don't want to use the mathJax components architecture).

rnwst commented

Many thanks for the detailed instructions!