question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ES Module externals are treated as CommonJS modules by webpack

See original GitHub issue

Webpack treats all modules as CommonJS by default, and only treats them as ESM when they have the __esModule property defined on them (link to webpack code). This is a problem when using external native ES modules, since native ES modules intentionally do not have the __esModule property defined on them. I believe that webpack 5 will solve this problem when they implement ESM externals, but the last time I checked that was not yet implemented.

The effect of treating the module as CommonJS is that the difference between default / named exports is not captured, so you have to change the way you import the library to be incorrect in order for it to work with webpack.

The obvious solution to this problem would be to add __esModule properties to all the imported externals. However, ES Module objects are not extensible, so that option is not possible. So as a workaround I created this package which will deep clone the module and add the __esModule property. I also created this branch on my fork of esm-webpack-plugin that inlines that code into the plugin, and have confirmed that it solves the problem. Here’s the diff of what I changed.

Admittedly, having to inline that much code into the bundle is not ideal, and one could argue that the implementation approach is a bit of a workaround. However, it works well in my testing so far. Could you comment @purtuga, on what you think would be a good implementation approach for solving this? Now that externals can be imported with ESM, I think it’s important to make sure webpack treats the externals properly.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
joeldenningcommented, Nov 9, 2020

Thanks for the response - I’ll try to put together a PR for this.

This change would apply only when the modulesExternal option is used, correct? in that it creates a new Object for the module that was import’d into the ESM being generated right?

Yes

Should this behavior be placed behind a plugin option in the spirit of giving devs the option? (i’m ok defaulting it to “include” the __esModule property)

Sure - am happy to do that.

Any unwanted side affects from re-exporting the imported module?

That’s a good question - I hadn’t thought about that. Live bindings should still work because my implementation use getters to the original module namespace object. However, referential equality checks would be broken:

// This code is in a NodeJS project that is not compiled / bundled by webpack

import * as foo from '/some/foo';
import { reexportedFoo } from './webpack-bundle-that-reexports-foo';

// Should be true, but will log false.
console.log(reexportedFoo === foo)
1reaction
purtugacommented, Sep 21, 2020

Hey. Sorry, I have not yet found some time to review/study this. Will try to get to it soon.

Paul T. – Sent from Mobile

Read more comments on GitHub >

github_iconTop Results From Across the Web

Externals - webpack
The externals configuration option provides a way of excluding dependencies from the output bundles. Instead, the created bundle relies on that dependency ...
Read more >
Add support for ES modules in the externals configuration option
Webpack currently supports the concept of externals but it only allows the forms: root, commonjs, commonjs2, and amd. This is a problem if ......
Read more >
How to transpile ES modules with webpack and Node.js
Learn how webpack interacts with and supports ES modules in this deep dive tutorial on transpilation in Node.js.
Read more >
Use Webpack 5 to build an ES module bundle, and consume ...
Since you use type: "module" , Node.js will treat this module as ESM. From the doc esm_no_require_exports_or_module_exports, ...
Read more >
CommonJS vs. ES Modules: Modules and Imports in NodeJS
In NodeJS each .js file is handled as a separate CommonJS module. This means that variables, functions, classes, etc. are not accessible to ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found