Skip to content

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

Closed

Description

@lostpebble

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?

Activity

  1. sokra commented on Aug 31, 2021

    @sokra
    Member

    The problem is in fela-plugin-named-keys. It doesn't expose an ESM entry point for node.js. node.js will import lib/index.js and uses these exports as default export (ignoring the __esModule flag). Either use static analyse-able named exports or better expose ESM via exports field in package.json

  2. lostpebble commented on Aug 31, 2021

    @lostpebble
    Author

    @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.

  3. lostpebble commented on Aug 31, 2021

    @lostpebble
    Author

    To show the development to production issue, I've updated the github repo and added a few more dependencies. All you have to do is run build using either mode and look at the output file (lib/index.js) to see the problem.

  4. webpack-bot commented on Dec 1, 2021

    @webpack-bot
    Contributor

    This issue had no activity for at least three months.

    It's subject to automatic issue closing if there is no activity in the next 15 days.

  5. added
    status: staleNo author response after a needs: request; close candidate
    on Dec 1, 2021
  6. webpack-bot commented on Dec 16, 2021

    @webpack-bot
    Contributor

    Issue was closed because of inactivity.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: staleNo author response after a needs: request; close candidatewebpack-5Concerns the webpack 5 line

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions