Skip to content

Compare esModuleInterop flag set to true, and set to false

Notifications You must be signed in to change notification settings

Zombiefruit/es-module-interop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

esModuleInterop

It's confusing. It's weird.

Maybe this will make it simpler.

See it in action

Run yarn. Then run yarn esm-true, and yarn esm-false. Check the console.

What's the difference? It's just a function that typescript creates. You can see it in the compiled esm.js files that are created by running the above commands.

With esModuleInterop: false:

Source

import thing from './commonjs/old-esm';
import thing2 from './commonjs/commonjs';

console.log('"esModuleInterop": false \n');
console.log(`The default export of a commonjs file that used to be esm: "${thing}".\n It works! \n`);
console.log(`The default export of a commonjs file: "${thing2}".\n It doesn't work :(. The original commonjs file never had the concept of a default export.\n`);

Compiled

// Typescript marks the file with "__esModule" to indicate that the file used to be esm
Object.defineProperty(exports, "__esModule", { value: true });
var old_esm_1 = require("./commonjs/old-esm");
var commonjs_1 = require("./commonjs/commonjs");
console.log('"esModuleInterop": false \n');
console.log("The default export of a commonjs file that used to be esm: \"" + old_esm_1.default + "\".\n It works! \n");
console.log("The default import of a commonjs file: \"" + commonjs_1.default + "\".\n It doesn't work :(\n");

All Typescript knows is that, in the source (.ts) file, we're asking for the default export. So it naively adds .default at the end of the imports, not knowing that the commonjs file doesn't have a default export.

With esModuleInterop: true:

Source

Same code as before:

import thing from './commonjs/old-esm';
import thing2 from './commonjs/commonjs';

console.log('"esModuleInterop": true \n');
console.log(`The default export of a commonjs file that used to be esm: "${thing}".\n It works! \n`);
console.log(`The default export of a commonjs file: "${thing2}".\n It works!\n`);

Compiled

var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var old_esm_1 = __importDefault(require("./commonjs/old-esm"));
var commonjs_1 = __importDefault(require("./commonjs/commonjs"));
console.log('"esModuleInterop": true \n');
console.log("The default export of a commonjs file that used to be esm: \"" + old_esm_1.default + "\".\n It works! \n");
console.log("The default import of a commonjs file: \"" + commonjs_1.default + "\".\n It works!\n");

The big difference: __importDefault. Typescript creates this simple method, which simply checks whether the module used to be an __esModule. If it was, it simply returns the module. But if the file was originally commonjs (wasn't an __esModule), typescript takes the module and wraps it with: { "default": mod }.

So now we can be sure that module.default is defined no matter what.

Simplified a little:

const importDefault = function (module) {
  if (module.__esModule) {
    return module;
  } else {
    return { 'default': module }
  }
};

const myImportedModule = importDefault(require("./some-module"));
// myImportedModule = { default: module_code }

About

Compare esModuleInterop flag set to true, and set to false

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published