Skip to content
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

export * from './foo.js' doesn’t work if foo.js references module #159

Closed
iamakulov opened this issue May 30, 2020 · 1 comment
Closed

Comments

@iamakulov
Copy link

iamakulov commented May 30, 2020

Hey!

I’ve encountered this bug with @sentry/browser + @sentry/utils and isolated it into the following.

Bug

If esbuild encounters the combination of export * from 'some-module' + some-module using the Node.js’ module object, it fails to bundle the code. E.g.:

// index.js
import { getEventDescription } from './b.js';
console.log(getEventDescription);

// b.js
export * from './c';

// c.js
export function getEventDescription() {}

console.log(module);

produces the following error:

$ esbuild index.js --bundle --outfile=bundle.js
index.js:1:9: error: No matching export for import "getEventDescription"
import { getEventDescription } from './b.js';
         ~~~~~~~~~~~~~~~~~~~
1 error

If you replace export * with export { getEventDescription }, the build completes successfully:

// index.js
import { getEventDescription } from './b.js';
console.log(getEventDescription);

// b.js
- export * from './c';
+ export { getEventDescription } from './c';

// c.js
export function getEventDescription() {}

console.log(module);

If you remove the module reference, the build completes successfully as well:

// index.js
import { getEventDescription } from './b.js';
console.log(getEventDescription);

// b.js
export * from './c';

// c.js
export function getEventDescription() {}

- console.log(module);

The module reference doesn’t have to live at the top level – e.g., in @sentry/utils, it’s used inside an IIFE.

Environment

Reproduced with the latest esbuild built from master.

Repro

https://github.com/iamakulov/esbuild-module-import-repro

To run the build:

esbuild index.js --bundle --outfile=bundle.js
@evanw
Copy link
Owner

evanw commented Jun 8, 2020

The reason for this is that referencing module causes the file to become a CommonJS module, and the list of exports in a CommonJS module are not generally statically analyzable at bundle time. For example, you might have code that does this:

let name = Math.random() < 0.5 ? 'foo' : 'bar'
module.exports[name] = function() {}

It's impossible to know at bundle time whether foo is exported or not because it depends on run time behavior.

I think this should be possible to fix, at least in most cases. The fix I'm thinking of is to have an export * from ... statement cause the file containing that statement to also become a CommonJS module if the exports come from a CommonJS module.

The only case where this might not be what you expect is if the export * from ... statement is in an entry point file and the format is esm. It should still work but it will cause the entry point to emit a single default export for the CommonJS export object instead of individual named exports, since the entry point will become a CommonJS module.

@evanw evanw closed this as completed in da6b958 Jun 9, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants