evanw / esbuild

An extremely fast bundler for the web
https://esbuild.github.io/
MIT License
38.01k stars 1.14k forks source link

feat: check __esModule in dynamic import #2253

Open privatenumber opened 2 years ago

privatenumber commented 2 years ago

Feature request

Wondering if dynamic imports (eg. import(specifier)) can be transformed to check for the __esModule property on the imported module in case it's ESM to CJS transformed.

Before

import('./esm.js').then(m => console.log(JSON.stringify(m)));

After

import('./esm.js').then((mod) => {
    const exports = Object.keys(mod);
    if (
        exports.length === 1
        && exports[0] === 'default'
        && mod.default.__esModule
    ) {
        return mod.default;
    }

    return mod;
}).then(m => console.log(JSON.stringify(m)));

Problem

Currently, when transforming a ESM file to CJS via Transform API, import statements are transformed to use require() and wrapped in __toESM. However, dynamic imports are not transformed.

This leads to a discrepancy in what's exported by the module.

esm.js

export default 'default value';
export const dirname = __dirname;

index.js

import defaultValue, { dirname } from './esm.js';
console.log(defaultValue, dirname);
// default value ~/Desktop/test

import('./esm.js').then(m => console.log(JSON.stringify(m)));
// {"default":{"default":"default value","dirname":"~/Desktop/test"}}

Expected behavior

Since import statements are transformed to interop with CJS-transformed ESM files, I would also expect the dynamic imports to as well:

import defaultValue, { dirname } from './esm.js';
console.log(defaultValue, dirname);
// default value ~/Desktop/test

import('./esm.js').then(m => console.log(JSON.stringify(m)));
// {"default":"default value","dirname":"~/Desktop/test"}
hanayashiki commented 11 months ago

How is it going?