mathjax/MathJax-demos-node

SyntaxError: Unexpected token export

fireflysemantics opened this issue · 6 comments

Hi,

I'm trying out the simple/tex2chtml example. I'm trying to convert this expression:

const latex = `MAD = \frac{\sum_{i=1}^n | x_i - \bar{x} |} n`

I changed the MathJax invocation to look like this:

    MathJax.tex2chtmlPromise(latex, {
        display: !argv.inline,
        em: argv.em,
        ex: argv.ex,
        containerWidth: argv.width
    })

This is the full source:

#! /usr/bin/env -S node -r esm

/*************************************************************************
 *
 *  simple/tex2chtml
 *
 *  Uses MathJax v3 to convert a TeX string to an HTML string.
 *
 * ----------------------------------------------------------------------
 *
 *  Copyright (c) 2019 The MathJax Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

const latex = `MAD = \frac{\sum_{i=1}^n | x_i - \bar{x} |} n`
//
//  The default TeX packages to use
//
const PACKAGES = 'base, autoload, require, ams, newcommand';

//
//  Get the command-line arguments
//
var argv = require('yargs')
    .demand(0).strict()
    .usage('$0 [options] "math" > file.html')
    .options({
        inline: {
            boolean: true,
            describe: "process as inline math"
        },
        em: {
            default: 16,
            describe: 'em-size in pixels'
        },
        ex: {
            default: 8,
            describe: 'ex-size in pixels'
        },
        width: {
            default: 80 * 16,
            describe: 'width of container in pixels'
        },
        packages: {
            default: PACKAGES,
            describe: 'the packages to use, e.g. "base, ams"; use "*" to represent the default packages, e.g, "*, bbox"'
        },
        css: {
            boolean: true,
            describe: 'output the required CSS rather than the HTML itself'
        },
        fontURL: {
            default: 'https://cdn.jsdelivr.net/npm/mathjax@3/es5/output/chtml/fonts/woff-v2',
            describe: 'the URL to use for web fonts'
        },
        assistiveMml: {
            boolean: true,
            default: false,
            describe: 'whether to include assistive MathML output'
        },
        dist: {
            boolean: true,
            default: false,
            describe: 'true to use webpacked version, false to use MathJax source files'
        }
    })
    .argv;

//
// Load MathJax and initialize MathJax and typeset the given math
//
require('mathjax-full').init({
    //
    //  The MathJax configuration
    //
    options: {
        enableAssistiveMml: argv.assistiveMml
    },
    loader: {
        source: (argv.dist ? {} : require('mathjax-full/components/src/source.js').source),
        load: ['adaptors/liteDOM', 'tex-chtml']
    },
    tex: {
        packages: argv.packages.replace('\*', PACKAGES).split(/\s*,\s*/)
    },
    chtml: {
        fontURL: argv.fontURL
    },
    startup: {
        typeset: false
    }
}).then((MathJax) => {
    //
    //  Typeset and display the math
    //
    MathJax.tex2chtmlPromise(latex, {
        display: !argv.inline,
        em: argv.em,
        ex: argv.ex,
        containerWidth: argv.width
    }).then((node) => {
        const adaptor = MathJax.startup.adaptor;
        //
        //  If the --css option was specified, output the CSS,
        //  Otherwise, output the typeset math as HTML
        //
        if (argv.css) {
            console.log(adaptor.textContent(MathJax.chtmlStylesheet()));
        } else {
            console.log(adaptor.outerHTML(node));
        };
    });
}).catch(err => console.log(err));

When I run it it produces this:

ole@mkt:~/Temp/MathJax-demos-node$ node simple/tex2chtml
/home/ole/Temp/MathJax-demos-node/node_modules/mathjax-full/components/src/node-main/node-main.js:70
export {init};
^^^^^^

SyntaxError: Unexpected token export
    at Module._compile (internal/modules/cjs/loader.js:720:23)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:683:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at Object.<anonymous> (/home/ole/Temp/MathJax-demos-node/simple/tex2chtml:83:1)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:643:32)

Any ideas?

dpvc commented

You need to use

node -r esm simple/tex2chtml

Note the #! /usr/bin/env -S node -r esm at the top of the file that indicates node -r esm is what is needed to run it. That is what will enable the ES6 import/export functionality that is being flagged by the error message.

@dpvc Awesome! It worked! Thanks!

I need to wrap this in a utility function that will be called from a commander command. Any ideas how to do this while still enabling the esm part that is needed to perform the import?

So it will be contained in a function like:

function latexToHtml(latex:string):string {
   //Perform conversion and return HTML
}

Also the command produced the Markup in this stackblitz. It looks like I also need to include a MathJax CSS style sheet in order for the element to render. Does MathJax provide a separate style sheet for this scenario?

dpvc commented

I need to wrap this in a utility function that will be called from a commander command. Any ideas how to do this while still enabling the esm part that is needed to perform the import?

I don't know what a "commander command" is, but if you don't have a way to provide options to the command, then one solution would be to name the node script with the extension .mjs, as node will use the esm library automatically when loading a file with that extension.

It looks like I also need to include a MathJax CSS style sheet in order for the element to render. Does MathJax provide a separate style sheet for this scenario?

Yes, there is CSS needed for this. You can get the css by using the --css option for the command:

node -r esm simple/tex2chtml --css '(your math)'

Of course, you can modify the tex2chtml command to give you both the CSS and the HTML together. The CSS for CHTML can be large, and depends on the content of the math you process, so if you want to process multiple equations, you would want to combine the CSS from the two equations.

It might be easier to use SVG output rather than HTML output. The tex2svg commands all include the needed styles in the SVG output themselves (and the CSS doesn't change, so if you include it once, you don't need to change it for different equations).

@dpvc The SVG option is a brilliant idea! Thank you so much again!

I'll try naming the script that contains the latexToSVGTransform function with the esm extension, and hopefully that will be all the love needed. Thanks again for excellent advice!

dpvc commented

You're welcome. I hope it works for you.

I'm closing the issue. You can reopen if you need to.

OK - I'm back again. I finally had some time to try out the SVG and it will generate with this command:

node -r esm tex2svg

So I tried this:

cp tex2svg tex2svg.mjs

And then running it like this ( With error result):

ole@mkt:~/Temp/MathJax-demos-node/simple$ node tex2svg.mjs 
internal/modules/cjs/loader.js:821
  throw new ERR_REQUIRE_ESM(filename);
  ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/ole/Temp/MathJax-demos-node/MathJax-demos-node/simple/tex2svg.mjs
    at Object.Module._extensions..mjs (internal/modules/cjs/loader.js:821:9)
    at Module.load (internal/modules/cjs/loader.js:643:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Function.Module.runMain (internal/modules/cjs/loader.js:839:10)
    at internal/main/run_main_module.js:17:11

I was hoping this would work so that I could wrap the script in a function that takes the latex input and returns the SVG and then I could package that script in an NPM module and publish it so that the script can easily be used in other projects.

Any ideas?