.mjs and ESM interop with `module` main, and transpiling to CJS

I’ve recently run into a bit of a frustrating situation trying to provide ESM build of libraries along-side commonjs ones. Ideally the ESM code should always be used by webpack, and allow cherry picking modules (as to not have to rely solely on treeshaking).

Currently, with the strictness of importing none mjs files into .mjs we can’t compile the same codebase in a way that works as cjs or esm modules. take the following example:

_MyComponent.mjs

import { polyfill } from 'react-lifecycle-compat';

// use polyfill(Component) etc.

react-lifecycle-compat exposes both a esm build (.js) and a cjs file here (compiled esm -> cjs)

What I want to do is compile MyComponent.mjs with babel to MyComponent.js and ship both files, relying on webpack to resolve the .mjs file before the .js one. However this won’t work.

  • react-lifecycle-compat is not .mjs so webpack considers it not an esm file and requires i write the import as: import ReactLifeCycleCompat from 'react-lifecycle-compat';,
  • Compiling this to cjs will also break, because of react-lifecycle-compat‘s __esmodule flag, so I can’t import that as a default because babel sees taht it’s only named exports.

TL: DR;

Consuming compiled, __esmodule flagged, modules with name exports cannot be written in a way that satisfies both cjs and mjs consumers.

I realize I can configure webpack to treat mjs as javascript/auto but that’s not ideal, because I’m interested in providing libraries that can be consumed by webpack and node witthout requiring users to configure something, while also wanting to move towards future standards and take advantage of esm optimizations

Author: Fantashit

1 thought on “.mjs and ESM interop with `module` main, and transpiling to CJS

  1. Ah, so this is because of third-party deps which use .mjs. They really shouldn’t be jumping on board that soon either. However, you can override the webpack config for this…

    {
      type: 'javascript/auto',
      test: /\.mjs$/,
      use: [ ...loaders ]
    }
    

Comments are closed.