I'm opening this as a bug report because the behavior is unexpected, but I'm not sure what "correct" behavior is. There is some dialog here: https://github.com/MikeMcl/bignumber.js/issues/217 and there is a very minimal setup here: https://github.com/quorumcontrol/minimal-fail-bignumber/tree/master/bignumber-alone which produces the output in the current behavior section.
bignumber.js specifies a module file which is an ES6 module. It has the following code: https://github.com/MikeMcl/bignumber.js/blob/master/bignumber.mjs#L2832
When compiled into the dist.js the es6 module is compiled and the module.exports contains a "default" key instead of module.exports equaling Bignumber - which breaks packages which use bignumber.js
have no .bablerc - but the setup is linked above: https://github.com/quorumcontrol/minimal-fail-bignumber/tree/master/bignumber-alone
It's a simple compile so it should "just work"
/Users/tobowers/code/minimal-fail-bignumber/bignumber-alone/dist/index.js:2727
let x = new BigNumber(123.4567);
^
TypeError: BigNumber is not a constructor
at Object.parcelRequire.Focm.bignumber.js (/Users/tobowers/code/minimal-fail-bignumber/bignumber-alone/dist/index.js:2727:9)
at newRequire (/Users/tobowers/code/minimal-fail-bignumber/bignumber-alone/dist/index.js:49:24)
at parcelRequire.xi/C (/Users/tobowers/code/minimal-fail-bignumber/bignumber-alone/dist/index.js:81:5)
at Object.<anonymous> (/Users/tobowers/code/minimal-fail-bignumber/bignumber-alone/dist/index.js:107:3)
at Module._compile (internal/modules/cjs/loader.js:689:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:742:12)
+ popd
~/code/minimal-fail-bignumber/bignumber-alone
I'm actually unclear what the expected behavior from an es6 module compiled should be... but "default" key doesn't work the same as just "require" when using it in a node project.
I'm trying to bundle ipld-dag-cbor and ran into this error.
https://github.com/quorumcontrol/minimal-fail-bignumber/tree/master/bignumber-alone
| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.11.0 |
| Node | v10.11.0 |
| npm/Yarn | npm 6.7.0 |
| Operating System | ox |
This is how es6 modules work.
Node鈥檚 commonjs require !== es6 imports
es6 imports use default
Sent with GitHawk
But what鈥檚 happening is that packages using require are getting the es6 module from big number which doesn鈥檛 work. Happens in the bundling process, works without parcel in the middle.
I think Parcel might follow a different version than node does, as node only looks for the main field in pkg.json and Parcel looks at the most correct version to use for the selected target (would have to double check some of Parcel's code to be able to detail how it works though).
As far as I can tell from the source of bignumber, using
const {BigNumber} = require('bignumber.js');
should work in both cases
However, bignumber is a dependency for a variety of other packages and they haven鈥檛 all switched over to that syntax. See the other directories in my minimal repro.
Parcel looks at the most correct version to use for the selected target
Parcel looks for the browser field if it is bundling for the browser, otherwise it seems to always give precedence to the module field over the main field irrespective of whether consumers are using require or import.
thanks @MikeMcl
Is it not an implementation detail that a default export is implemented as a named export, i.e. that
export default BigNumber
is implemented as
export { default: BigNumber }
and
import BigNumber from 'bignumber.js';
is sugar for
import {default as BigNumber} from 'bignumber.js';
Surely, consumers using require
const BigNumber = require('bignumber.js');
should reasonably expect to get the default export.
Edit:
Considering this further, a module can of course have named exports as well as a default export, so require can't just return the default export if there is one.
CommonJS and ES modules just don't mix very well, which is why it is problematic for parcel to always grab pkg.module even when a package is consuming a dependency with require. I think webpack and rollup can be configured to not use or give precedence to pkg.module per package.
How about that if parcel determines that a module only has a default export and no named exports, a consumer's require returns the default export directly, rather than an object with a named export, default?
I just ran into this too. As another data point, here's what I'm running:
const forEach = require('callbag-for-each')
const interval = require('callbag-interval')
forEach(console.log)(interval(1000))
This works if I run it with node, but fails if I use parceljs. I think this should work consistently in both environments since it's common to share code between node and the browser
Using node v11.4.0
staltz/callbag-interval#7
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.
Most helpful comment
Is it not an implementation detail that a default export is implemented as a named export, i.e. that
is implemented as
and
is sugar for
Surely, consumers using
requireshould reasonably expect to get the default export.
Edit:
Considering this further, a module can of course have named exports as well as a default export, so
requirecan't just return the default export if there is one.CommonJS and ES modules just don't mix very well, which is why it is problematic for parcel to always grab pkg.module even when a package is consuming a dependency with
require. I think webpack and rollup can be configured to not use or give precedence to pkg.module per package.How about that if parcel determines that a module only has a default export and no named exports, a consumer's
requirereturns the default export directly, rather than an object with a named export,default?