esbuild icon indicating copy to clipboard operation
esbuild copied to clipboard

Issue with import { default as Blabla} .. export default async ()...

Open Inqnuam opened this issue 2 years ago • 3 comments

First of all thank you for you wonderful work!

everything is in the title but more explanation just here. Consider this example.js file

import { default as getUserById, list} from "../service/users.js";

export const listUsers = async ()=> {
  const users = await list()
  return users
}

export default async (id)=> {
  const user = getUserById(id)
  return user.data
}

importing example.js after it was bundled by esbuild we will have the following result

const exampleProps = await import("example.js")

console.log(exampleProps) 
// =>
[Module: null prototype] {
  default: { default: [Getter], list: [Getter] },
  listUsers: [AsyncFunction: list2]
}

We except from default to have the content of "export default .." (a function) not the content of "import {default ..." (which is an object)

This causes an issue with imports with dynamic paths and dynamic function names when we need to access the "default" export function an easy workaround is to check if required function name is "default" then check if imported "default" is an object to access the 'real' export default from default.default

const handler = await import(esOutputPath);
let handlerName = "someName"

    let eventHandler
    // workaround
    if (handlerName == "default" && typeof handler.default == "object" && typeof handler.default.default == "function") {
      eventHandler = handler.default.default;
    } else {
      eventHandler = handler[handlerName];
    }

I don't know if this is a bug or an excepted behaviour, just wanted to let you know!

Inqnuam avatar Aug 23 '22 22:08 Inqnuam

Sorry but I'm unable to reproduce this given your description. Please provide instructions for how to reproduce the problematic behavior (including all source files, the esbuild command used for bundling, and the command used to run the code that imports the bundle afterward).

evanw avatar Aug 26 '22 14:08 evanw

esbuildIssue.zip Here's an example project to reproduce the issue yarn install yarn build yarn start:bundled yarn start:original

Inqnuam avatar Aug 27 '22 15:08 Inqnuam

I do not view this as a problem with esbuild. You are running import() on a CommonJS file (the files in dist are considered to be CommonJS because of the echo '{}' > ./dist/package.json command). Node has decided to make import() of a CommonJS file in node always return module.exports regardless of whether or not that CommonJS file was originally an ES module (despite the rest of the JS ecosystem working the other way).

Your options:

  • Just avoid the default export

    • I recommend avoiding default in new code due to compatibility problems like this. There's unfortunately no way to fix this in 100% of cases. Changing something to make one case work will just make other cases break. More info here: https://esbuild.github.io/content-types/#default-interop
  • Use ESM instead of CommonJS:

    • Pass --format=esm to esbuild
    • Change echo '{}' > ./dist/package.json to echo '{"type":"module"}' > ./dist/package.json

evanw avatar Aug 29 '22 03:08 evanw

Closing this issue as I do not consider it to be a problem with esbuild.

evanw avatar Nov 27 '22 16:11 evanw