question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ESM runtime helper files should have the .mjs extension

See original GitHub issue

Bug Report

Current behavior

Config

{
  presets: [
    [
      '@babel/env',
      {
        targets: {
          node: '6.10',
          browsers: '>1%'
        },
        modules: false,
        shippedProposals: true,
        loose: true
      }
    ]
  ],
  plugins: [
    ['@babel/transform-runtime', { useESModules: true }]
  ]
}

Input code

import React from 'react'

class Demo extends React.Component {}

Outputs:

import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose'
import React from 'react'

var Demo = (function(_React$Component) {
  _inheritsLoose(Demo, _React$Component)

  function Demo() {
    return _React$Component.apply(this, arguments) || this
  }

  return Demo
})(React.Component)

When run as native ESM in Node.js with --experimental-modules enabled:

node --experimental-modules lib/demo.mjs

@babel/runtime/helpers/esm/inheritsLoose resolves to node_modules/@babel/runtime/helpers/esm/inheritsLoose.js. Because Node.js can only run native ESM in files with the .mjs extension, this results in a runtime error:

$ node --experimental-modules lib/demo.mjs
(node:97782) ExperimentalWarning: The ESM module loader is experimental.
/Users/jaydenseric/Sites/demo/node_modules/@babel/runtime/helpers/esm/inheritsLoose.js:1
(function (exports, require, module, __filename, __dirname) { export default function _inheritsLoose(subClass, superClass) {
                                                              ^^^^^^

SyntaxError: Unexpected token export
    at new Script (vm.js:74:7)
    at createScript (vm.js:246:10)
    at Proxy.runInThisContext (vm.js:298:10)
    at Module._compile (internal/modules/cjs/loader.js:657:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at createDynamicModule (internal/modules/esm/translators.js:56:15)
    at setExecutor (internal/modules/esm/create_dynamic_module.js:50:23)

Expected behavior/code

The ESM helper import should resolve a helper file with a .mjs extension.

Environment

  • Babel version(s): v7.0.0-rc.1
  • Node/npm version: Node.js v10.8.0 / npm v6.3.0
  • OS: macOS v10.13.6
  • Monorepo: No
  • How you are using Babel: CLI

Possible Solution

Allow Babel helpers to be consumed in native CJS or ESM Node.js environments by publishing sibling .js (CJS) and .mjs (ESM) files. They should be imported using the same path so the Node.js import resolution algorithm will select the appropriate file for the environment:

- import _inheritsLoose from '@babel/runtime/helpers/esm/inheritsLoose'
+ import _inheritsLoose from '@babel/runtime/helpers/inheritsLoose'

Webpack and other tools have adopted the same resolution algorithm; Webpack actually prefers .mjs files for ESM.

Additional context/Screenshots

I would like to be able to generate an ESM build, that imports ESM helpers, that can run as native ESM in Node.js with --experimental-modules enabled.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:1
  • Comments:10 (4 by maintainers)

github_iconTop GitHub Comments

5reactions
jaydensericcommented, Apr 6, 2020

To workaround this issue I’ve published babel-plugin-transform-runtime-file-extensions, a Babel plugin that adds file extensions to Babel runtime import specifiers and require paths for Node.js ESM compatibility.

3reactions
JLHwungcommented, Oct 14, 2020

Fixed in @babel/runtime@7.12.0.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Using ECMAScript modules (ESM) with Node.js
A brief introduction to using ES modules ... The mjs extension can lead to some confusion when we compare its use against js...
Read more >
Using ESM (ECMAScript Modules) - Architect documentation
The simplest way to start using ESM is to create JavaScript files with a .mjs extension. For example, no configuration is needed for...
Read more >
Explicit ESM in Node.js with .mjs - DEV Community ‍ ‍
The straightforward answer to this is that having different file extensions allows you to be explicit in how you want to run your...
Read more >
Documentation - ECMAScript Modules in Node.js - TypeScript
Node.js supports two extensions to help with this: .mjs and .cjs . .mjs files are always ES modules, and .cjs files are always...
Read more >
Importing in Node.js: error "Must use import to load ES Module"
If your file does not have a file extension .mjs , there is a whole set of rules for what you have to...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found