Can't use mathjs without package bundler
- Dominant language
- JavaScript
- Stars
- 15.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
### 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:
```javascript
import { evaluate } from 'mathjs';
console.log(evaluate('1+2'));
```
It throws:
```
import { evaluate } from 'mathjs';
^^^^^^^^
SyntaxError: The requested module 'mathjs' is expected to be of type CommonJS, which does not support named exports. CommonJS modules can be imported by importing the default export.
For example:
import pkg from 'mathjs';
const { evaluate } = pkg;
```
From what I can see, the `module` entry in `package.json` is only used for package bundlers. Without bundlers, node will look at the `main` 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:
```javascript
import mathjs from 'mathjs';
console.log(mathjs.evaluate('1+2'));
```
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:
> TypeError: Cannot read property 'evaluate' of undefined
I think that [conditional exports](https://nodejs.org/api/esm.html#esm_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 ES `import`.
### 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 the `esm` files for `import` statements, and `es5` files for `require`:
```json
{
"main": "./main/es5",
"module": "./main/esm",
"exports": {
"import": "./main/esm/index.js",
"require": "./main/es5/index.js"
},
// this is required, otherwise the `exports` doesn't work
"type": "module"
}
```
But because the `type` is now `module`, 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 a `package.json` in the root directories containing the CommonJS files (e.g. `main/es5/`, `lib/`), with just the following:
```json
{
"type": "commonjs"
}
```
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](https://nodejs.org/api/esm.html#esm_subpath_exports).
Contributor guide
Assessment
This issue has not been assessed yet.