-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't use mathjs without package bundler #1928
Comments
Thanks Lee! It would be great to get mathjs working directly as ES module without need for bundlers! There are a lot of ways the library can be used, so we should thoroughly test all these options. Help getting this sorted out would be very welcome! I wasn't aware of the conditional I can think of:
I think we should think through a "real" solution and not go for workarounds, I'm afraid workarounds will come back to bite us. It makes sense to me to give all files the correct, explicit extension: Your help would be very welcome! |
Thanks for your response! I only came across conditional exports recently myself, as I'm planning on implementing it in my own library, to solve a similar issue. I'm definitely interested in getting this sorted. Are you able to clarify for me if my understanding of the uses of each file?
I'm not entirely certain what the difference with the Are there Any relevant files / uses that I've missed? I think people using Rollup / Webpack / etc. isn't too important, as I think they'll grab whatever node is told to. So, if we add the My thoughts on adding That being said, I've not much experience with using Grunt, and I'm not sure how to change the file extension that it generates. |
Thought it worth mentioning that I've just implemented "exports": {
".": {
"import": "./lib/esm/bundle.js",
"require": "./lib/umd/bundle.js"
},
"./lib/umd/bundle.js": {
"require": "./lib/umd/bundle.js"
}
}, And it seems to be working nicely. The "." entry is the root, so it handles importing the base package like: import('package-name'); The next bit; "./lib/umd/bundle.js": {
"require": "./lib/umd/bundle.js"
} Allows CommonJS access to the UMD bundle, but will actually throw an error that the import is invalid, if you try and use ESM // this works
const value = require('package-name//lib/umd/bundle.js');
// this doesn't
import value from 'package-name//lib/umd/bundle.js'; So it should definitely be possible to set up mathJS to export both the {
"main": "./main/es5",
"module": "./main/esm",
"exports": {
".": {
"import": "./main/esm/index.js",
"require": "./main/es5/index.js"
},
"./number": {
"import": "./main/esm/number.js",
"require": "./main/es5/number.js"
}
},
"type": "module"
} This should allow you to import both: // using ESM
import { sqrt } from 'mathjs';
import { sqrt } from 'mathjs/number';
// using CommonJS
const { sqrt } = require('mathjs');
const { sqrt } = require('mathjs/number'); And that should work with package bundlers and without. |
Your explanation of the folders dist, es, lib, and src is correct. The idea of the main folder was indeed to offer one place with all the relevant index files. I'm not sure if it's actually helpful though.
The number.js files contain the mathjs functions but with number support only, making it lightweight. No matrix, unit, bignumber, fraction, complex, etc support. About renaming files: I assume in the future everything will become ES modules with the
That sounds promising! So this will work for node.js for sure. Will it also work with Webpack/Rollup? |
In terms of the I'm not sure what's best with filenames either. I think bundlers will still work exactly as they currently do; look at the I'll start working on a PR for the Out of interest, is the const result = evaluate('4+1'); // result === 5 |
Makes sense, fine with me 👍 (though a breaking change so we need to publish as a new major version) About the file naming: maybe we should search a bit on internet for best practices in this regard. We could say that The build script of mathjs outputs a number of different things: a bundle, a minified bundle, a directory with ES modules code, and a directory with commonjs code.
Thanks!
The |
Ah, not sure how I missed the evaluate method in the numbers file. Must have misspelt it or something. Serves me right for working on it so late. I've started having a play around with this, but have hit an initial issue; For the I'm still looking into it, and trying to find the best way of handling it all, but thought I'd give an update on progress. |
I've created PR #1941 with some changes to fix this. The description on it is pretty lengthy, but it hopefully describes everything that I've done. Feel free to pick it apart and let me know your thoughts. |
Thanks for your your PR Lee! I'll look into it asap but I have little time these weeks unfortunately. Just for reference: I recently came across this article which is about this exact issue: https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1 |
No worries, I know it can be difficult to find time for stuff. Just take a look when you get the chance 😄 Thanks for the link! It's a really interesting read. It does sound like if the source was written in CommonJS, rather than ESM, you may be able to get the generated ESM code to be smaller, by "wrapping" the CommonJS files, rather than duplicating the code. Which is really interesting! |
Also, feel free to be ruthless with your review. I'm happy to change things, or scrap it, if it's not what you're after. |
Thanks for your patience, appreciated! Just for reference, more background information about cjs/esm I came across recently: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_dual_commonjs_es_module_packages |
Was this fixed by #1941, or is it still an issue? |
I'd also love to know if anyone has figured out how to use math-js in the browser without a package bundler. Trying to do that myself and running into the same issues as OP. Note: Using |
The problem
I'm trying to use mathjs inside node, using ES modules, but without a package bundler (e.g. Webpack, Rollup).
When I do:
It throws:
From what I can see, the
module
entry inpackage.json
is only used for package bundlers. Without bundlers, node will look at themain
entry, so it tries to load the CommonJS / UMD script.Node does support mixing ES and CommonJS modules, but expects a single, default export.
Changing the import to this works, because it correctly loads the CommonJS module:
So that's a kind of workaround, but it does mean that it's not using ES modules in an ES module project.
But the bigger issue is that it's now incompatible if I choose to use to use a bundler because the bundler will use the ES module version, which has no default import.
In particular, this causes my Jest tests to fail. In my test I have something like:
I think that conditional exports may be a solution. It seems to allow you to tell node which files to use for CommonJS
require
and which to use for ESimport
.Potential solution
I've not had a proper play with it, this seemed to work for me:
Change the
package.json
to this, to tell node to use theesm
files forimport
statements, andes5
files forrequire
:But because the
type
is nowmodule
, node will now complain when trying to use CommonJS.To sort that, you can either rename all of the CommonJS files to have the
.cjs
extension, or to add apackage.json
in the root directories containing the CommonJS files (e.g.main/es5/
,lib/
), with just the following:I'm not sure if doing this has any adverse affects on other parts of the library though, but I'm happy to get a PR in for those changes.
I thought it seemed similar to #1766. Not quite the same issue, but possibly the same resolution, perhaps used with Subpath Exports.
The text was updated successfully, but these errors were encountered: