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.

External imports in ESM output are two layers of "default" deep

See original GitHub issue

Bug report

What is the current behavior?

Relevant parts of config:

  experiments: { "outputModule": true },
  externalsType: "module",
  externals: {
    "fela-plugin-named-keys": "fela-plugin-named-keys"
  },

When I have set my Webpack config to output ESM modules for use in a Node.js project, and I have made a certain module an “external” module to be imported by Node.js during runtime, the code Webpack has generated is causing this import to be of this structure:

{
  "default": {
    "default: () => {
         // This function is an example of whatever is the value of the default
         // export of this module, 'module.exports = ...' OR 'export default ...'
      }
  }
}

If I have used an import in my code like so (which worked perfectly fine before when I was using commonjs as a target):

import namedKeys from "fela-plugin-named-keys";

const namedKeysPlugin = namedKeys();

The code being generated from this, seems perfectly fine on first glance:

var namedKeysPlugin = (0,external_fela_plugin_named_keys_namespaceObject.default)();

But we end up having an error thrown that looks like this:

TypeError: fela_plugin_named_keys__WEBPACK_IMPORTED_MODULE_5__.default is not a function

If I put in a console.log(namedKeys), it reveals to us that the problem seems to be that the code for some reason is making this import a module structure that’s two layers deep:

console.log(external_fela_plugin_named_keys_namespaceObject.default);

// Output in console:
// { default: [Function: namedKeys] }

If the current behavior is a bug, please provide the steps to reproduce.

I’ve created a github repo with a replication of this happening: https://github.com/lostpebble/webpack-esm-import-problem

There are steps to reproduce in the Readme.

What is the expected behavior?

Default exports are imported correctly only a single layer deep in the structure of:

{
  default: () => {
    // Example of default export value
  }
}

Other relevant information: webpack version: ^5.51.1 Node.js version: 16.7.0 Operating System: Windows 10 Additional tools:

Observations

When I manually edited the output file, from this:

import * as __WEBPACK_EXTERNAL_MODULE_null__ from "fela-plugin-named-keys";

to this:

import __WEBPACK_EXTERNAL_MODULE_null__ from "fela-plugin-named-keys";

It worked. I see that pretty much all imports are done in this way * as WHATEVER from "whatever" when we make use of externalsType: "module" externals. So perhaps this is where the problem lies?

Issue Analytics

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

github_iconTop GitHub Comments

1reaction
lostpebblecommented, Aug 31, 2021

@sokra - but most modules these days still don’t expose an ESM entry point as they are still commonjs in their output. But on the flip side the modules that are pure ESM are not compatible without having your project use ESM (because require does not work for them)… 🤔 So, I’ve decided to try and move my project over to ESM because clearly certain large modules are heading this way now. (There is a very intense discussion about this over here: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).

I have no control over fela-plugin-named-keys and the 100s of other modules like it in my dependency graph (I just used it here as an example because it was the first one to cause issues for me).

This is a bit of a jarring experience- as I would expect Webpack to figure out a way to use these modules correctly, as they worked just fine before when our project made use of commonjs.

Also- for this module fela-plugin-named-keys, Webpack is actually using its ESM file as the source (/es/index.js) because this has been set in package.json ("module": "es/index.js", "jsnext:main": "es/index.js")- which clearly defines the default export that is expected… So surely this should be working just fine then?


Another thing which perhaps warrants a different issue, but I noticed as I was playing with this and trying to get it to work, is that when I change my Webpack config from mode: "development" to mode: "production", Webpack does not output external module imports correctly anymore- they all become a single:

import * as __WEBPACK_EXTERNAL_MODULE_null__ from "fela-plugin-named-keys"

instead of

import * as __WEBPACK_EXTERNAL_MODULE_rehype_parse__ from "rehype-parse";
import * as __WEBPACK_EXTERNAL_MODULE_unified__ from "unified";
import * as __WEBPACK_EXTERNAL_MODULE_fela_plugin_named_keys__ from "fela-plugin-named-keys"

And hence only the last imported module “wins” and becomes the WEBPACK_EXTERNAL_MODULE_null import which is then used (incorrectly) everywhere.

0reactions
webpack-botcommented, Dec 16, 2021

Issue was closed because of inactivity.

If you think this is still a valid issue, please file a new issue with additional information.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Modules • JavaScript for impatient programmers (ES2022 ...
A module can have both named exports and a default export, but it's usually better to stick to one export style per module....
Read more >
Documentation - ECMAScript Modules in Node.js - TypeScript
When a file is considered an ES module, a few different rules come into play compared to CommonJS: import / export statements and...
Read more >
What the heck are CJS, AMD, UMD, and ESM in Javascript?
ESM waits to execute any code in a module until all of it's imports have been loaded and parsed, then does the binding/side-effects...
Read more >
rollup.js
Importing CommonJS · Publishing ES Modules ... rollup.config.js // can be an array (for multiple inputs) export default { // core input options...
Read more >
How to Create a Hybrid NPM Module for ESM and CommonJS.
Author your code in ES6, ES-Next or Typescript using import and export. From this base, you can import either ES modules or CommonJS...
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