mathjs
mathjs copied to clipboard
Load mathjs in a browser module (ES import)
Currently it looks like it's not possible to use mathjs in a browser module like:
<script type="module">
import { create, all } from 'mathjs'
</script>
I think the existing bundles in dist
do not have the right exports to be consumed as an ES module.
What should work (but doesn't) is loading like:
import { create, all} from 'mathjs/main/es/index.js'
I think the reason is that many import paths in the code are missing the explicit "*.js" extension, which is the normal way to go in nodejs and webpack environments, but not in browser ES environments which require a real path to a file.
this is not worked for me when import mathjs in vite
I have read https://nodejs.org/api/esm.html#esm_dual_commonjs_es_module_packages a couple of times to try and work out what we should do. Not yet grokked it completely though.
@josdejong what is your take on the duel package hazard. Does it apply to mathjs? I cannot remember if we still have global state?
It's quite complicated :S
mathjs has no global state, you have to create your own mathjs instance with for example create(all, config)
, and in this instance there is state like the config. It may be possible that some difficulties arise because we integrate for example Complex
and BigNumber
, I'm not entirely true if mathjs adds methods to these libraries.
I think you're correct about the lack of file extension; browser environments expect the full path and filename.
Is there a way you could tell Gulp to add the .js
to imports when it created the files?
I found a related issue at https://github.com/i18next/i18next/issues/1667#issuecomment-930087226. Since math uses babel to compile ESM through gulp, I think this will be helpful. (Also, the error message explicitly mentioned that it failed to resolve @babel/runtime/helpers/extends
.)
To mention their solution, they include a bundled ESM file for babel. However, I'm not sure how to do that using gulp and if it will work.
Thanks Hanchai for your input, an ESM bundle would indeed solve that because there are no imports without .js
extension, it is just a single file.
I had anther look to see if a non-bundle ESM code could work:
-
there are some files without file extension. These are files generated by the Babel plugins
@babel/plugin-transform-object-assign
and@babel/plugin-transform-runtime
-
Then, we need to specify an import map for all the Node.js modules:
<script type="importmap"> { "imports": { "typed-function": "../../node_modules/typed-function/lib/esm/typed-function.mjs", "decimal.js": "../../node_modules/decimal.js/decimal.mjs", "complex.js": "../../node_modules/complex.js/complex.js", "fraction.js": "../../node_modules/fraction.js/fraction.js", "javascript-natural-sort": "../../node_modules/javascript-natural-sort/naturalSort.js", "escape-latex": "../../node_modules/escape-latex/dist/index.js", "seedrandom": "../../node_modules/seedrandom/seedrandom.js", "tiny-emitter": "../../node_modules/tiny-emitter/dist/tinyemitter.min.js" } } </script> <script type="module"> import * as math from '../../lib/esm/index.js' // ... </script>
-
But then we still have the issue that some of the dependencies are not ESM, so trying to run mathjs fails. That is not solvable on our side.
So all in all, I think generating a single ESM bundle makes a lot of sense (it is also way faster then loading many tiny files). We should make sure though that tree-shaking still works on this bundle. Anyone interested trying this out?