Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use conditional exports in @babel/runtime for CJS/ESM #12632

Merged

Conversation

nicolo-ribaudo
Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Jan 14, 2021

Q                       A
Fixed Issues? Closes #12295
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature? Yes
Tests Added + Pass? Yes
Documentation PR Link babel/website#2441
Any Dependency Changes?
License MIT

This is #12295, but without breaking changes:

  • When the runtime version is old or unknown, we still don't emit .default in the generated CJS output. This can cause problems with bundlers (webpack 5 I think?), but it's problems that people already have now. Users can fix it by setting the "version" option.
  • I kept the @babel/runtime/helpers/esm folder, which just proxies to the .mjs files.

Using Node.js' exports mappings, we can get rid of the "useESModules": true option: it will automatically pick up the preferred version based on how the helper is requried/imported.

exports are also supported by webpack and rollup, but I have structured the files in a way that, even if exports isn't supported by some tool, it will load the CJS version because the file is named index.js.

In order to avoid loading both the CommonJS and the ESM version, which can lead to duplicated state, I structured exports so that:

  • Node.js always loads the CommonJS version. When using require it "just works", when using import it will get the value of module.exports. (The node export condition)
  • Old Node.js versions ignore exports, and they load the CJS helper (index.js file)
  • When using Webpack/Rollup, it will always load the .mjs version. Webpack requires that the CJS and ESM files have the same interface, so the CJS helpers also export their function as module.exports.default. (The module condition)
  • For other targets that don't support the module/node conditions, it will always load the .mjs version. (The default condition)

In Babel 8 we'll remove the useESModules option, and for now we can warn if it's used with a @babel/runtime version that supports dual modules.

When reviewing this PR, please read #12295 (comment) for how this works.

cc @Andarist

@nicolo-ribaudo nicolo-ribaudo added PR: New Feature 🚀 A type of pull request used for our changelog categories area: helpers labels Jan 14, 2021
@@ -1,4 +1,4 @@
var _createForOfIteratorHelper = require("@babel/runtime-corejs3/helpers/createForOfIteratorHelper");
var _createForOfIteratorHelper = require("@babel/runtime-corejs3/helpers/createForOfIteratorHelper").default;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the output changed and it's incompatible with old @babel/runtime versions, but it's because we are specifying "version": "7.100.0" in the test options.

@babel-bot
Copy link
Collaborator

babel-bot commented Jan 14, 2021

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/41414/

@codesandbox-ci
Copy link

codesandbox-ci bot commented Jan 14, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 380db06:

Sandbox Source
babel-repl-custom-plugin Configuration
babel-plugin-multi-config Configuration

@JLHwung JLHwung self-requested a review January 14, 2021 17:17
@nicolo-ribaudo
Copy link
Member Author

The e2e error caused by rebasing is a real error.

@nicolo-ribaudo
Copy link
Member Author

@Andarist Do you happen to know if rollup with @rollup/plugin-commonjs will load the CJS or ESM version when doing this, based on the exports defined in this PR?

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var utils = _interopRequireWildcard(utils);

@nicolo-ribaudo
Copy link
Member Author

nicolo-ribaudo commented Feb 10, 2021

I'm confused. Even if all the entry points point to the CJS helper:

    "./helpers/interopRequireWildcard": {
      "node": "./helpers/interopRequireWildcard/index.js",
      "require": "./helpers/interopRequireWildcard/index.js",
      "default": "./helpers/interopRequireWildcard/index.js"
    },

wheb bundling @babel/standalone Rollup still transforms the code in #12632 (comment) to

  var interopRequireWildcard = /*#__PURE__*/Object.freeze({
    __proto__: null,
    'default': _interopRequireWildcard
  });

  // ...

  var _interopRequireWildcard$1 = /*@__PURE__*/getAugmentedNamespace(interopRequireWildcard);

  var util$4 = _interopRequireWildcard$1(util$3);

@nicolo-ribaudo
Copy link
Member Author

I think I figured it out. For some reason rollup is completely ignoring "exports" (maybe we are using an old version?) and we wrongly configured it to load .mjs before .js.

Imho this is just a bug in our config and not a breaking change, since the convention everywhere is that .js has priority over .mjs.

@Andarist
Copy link
Member

Andarist commented Feb 11, 2021

@Andarist Do you happen to know if rollup with @rollup/plugin-commonjs will load the CJS or ESM version when doing this, based on the exports defined in this PR?

This is actually the responsibility of the @rollup/plugin-node-resolve package.

For some reason rollup is completely ignoring "exports" (maybe we are using an old version?)

Yep, you are on v9 - I'm not super sure when support for exports has been added to this plugin but I would assume that in its current version (v11). I haven't actually tested this much with Rollup yet - but here are interesting source lines:

This was referenced Mar 15, 2021
@kevinwgutierrez
Copy link

Has this issue been consistently solved? This bug is keeping me from building on Netlify and is not reproducing locally.
Screen Shot 2021-05-12 at 8 12 27 AM

@nicolo-ribaudo
Copy link
Member Author

That seems something unrelated: for some reason Webpack is configured to read that file as JSON 🤔

@github-actions github-actions bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Aug 12, 2021
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 12, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: helpers outdated A closed issue/PR that is archived due to age. Recommended to make a new issue PR: New Feature 🚀 A type of pull request used for our changelog categories PR: Ready to be Merged A pull request with already two approvals, but waiting for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants