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

v14 esm does not support named import from modules with cjs dot exports #33795

Closed
dkebler opened this issue Jun 8, 2020 · 2 comments
Closed

Comments

@dkebler
Copy link

dkebler commented Jun 8, 2020

  • Version: v14.2.0
  • Platform: linux, amd64,aarch64, unbuntu 18.04, kernel 4.15.0-101-generic

What steps will reproduce the bug?

First off for a year+ I've written all my code using esm and with the std/esm package I am able to seamlessly use dependent packages that contain cjs dot exports with no issues without the need of babel.

https://github.com/standard-things/esm

In nodejs V14 mixed esm/cjs support is now included without need of a flag and the std/esm project seems to be winding down so I thought I should attempt to migrate to see what the issues may be. Well I found one.

I'm following the docs here https://nodejs.org/api/esm.html#esm_ecmascript_modules

The issue I am having is that unlike std/esm the esm support now included with V14 core is breaking the named imports from commonjs modules that use dot exports that should be consider named exports when importing in a esm based pacakge. This all works fine running under std/esm.

Take for example https://github.com/sindresorhus/make-dir/blob/978bee9186bf0c41640ed21567921daf8c303225/index.js#L106

this package/module uses cjs. Here is the export statement

module.exports.sync = (input, options) => {
	checkPath(input);
	options = processOptions(options);

To reproduce the issue make a new project and enter
"type":"module" in package.json. Now add an esm named import import { sync as mkdir } from 'make-dir'. Run the code and it will throw this error

import { sync as mkdir } from 'make-dir'
         ^^^^
SyntaxError: The requested module 'make-dir' does not provide an export named 'sync'

To make this easy to reproduce/demonstrate I have created a repo can you can clone and follow the instructions in the readme to quickly observe the issue using core esm in V14 and how it is not an issue using the std/esm package instead.

https://github.com/dkebler/core-esm-named-import-error

How often does it reproduce? Is there a required condition?

always, see example repo

What is the expected behavior?

don't throw this error. Treat cjs dot exports like they were named exports so when doing named import in esm package it works just like it does in std/esm.

Additional information

I can make the error go way by accommodating the cjs by using a default import and then getting the "named" import via a dot (yuck!)

import mk from 'make-dir'
const mkdir = mk.sync

I would have to go through all my esm code doing that (why when I don't with std/esm) and I don't know a priori which modules are cjs and which are esm. This should be seamless like it is with std/esm.

Either I am not implementing this correctly, this is bug which I find hard to believe given std/esm works fine, @jdalton probably has worked on this part of the core and std/esm was probably incorporated wholly or partly in this code, or this is by design (I sincerely hope not).

Anyway I assumed that esm support in v14 was going to be a drop in replacement for using std/esm. Apparently not :(.

I have a stack overflow post for this but it is not getting any traction.

https://stackoverflow.com/questions/62088912/migrating-from-std-esm-to-esm-support-in-node-v14-cant-find-named-import-wo?noredirect=1#comment109841095_62088912

@aduh95
Copy link
Contributor

aduh95 commented Jun 9, 2020

FWIW you don't have to use a dot 😉

import mk from 'make-dir'
const {sync: mkdir} = mk

There are discussion for allowing named imports of CJS from ESM (see nodejs/modules#509), but so far there is no solution to this problem.
The technical reason Node.js only supports default exports for CJS scripts is because ESM import is static (it is parsed prior to module execution) and CJS module.exports is dynamic (you can do something crazy like module.exports[Date.now()] = 0 and get away with it). The only way be know for sure what "names" a CJS module exports is to parse and execute it, that seems to be incompatible with ES6 specs.

The reason bundlers or std/esm are able to get away with it is usually by transpliling ES6 modules to CJS or UMD, or another loading standard that allows dynamic import.
EDIT: that seems to be incorrect, at least for std/esm and Rollup commonjs plugin. I replied with more accurate description on the stackoverflow linked in the OP.

So what can be done? Here's what I have been doing when I encounter this issue:

@dkebler
Copy link
Author

dkebler commented Jun 11, 2020

Thanks @aduh95 finally someone with clear understanding of the issue and some good advice!

esm gurus would prefer us to move away from default exports/imports. They encourage us to not even supply a default export in esm so to now go around converting a named import to default is ironic.

Also ironic that packages transpile esm to cjs for distribution and then std/esm "transpiles" back. Kinda like using an ac charger phone charger on an inverter when you could use the DC direct.

So I'll just stick with std/esm for time being being as I don't have to change a thing and it takes zero time/effort. I'm going to wait until V16 to revisit this since esm is still technically experimental. Maybe by then devs will supply both if they write in es6+/esm or typescript already. If not I have your excellent suggestions. For me I've decided there is no looking back. All my package repositories are only published as esm and whatever JS is supported in latest even node. If folks want to use them with cjs or older versions of node let them be the ones to transpile :-).

@aduh95 would you be willing to copy your post as the answer to my stack exchange question or give me blessing to do so.

https://stackoverflow.com/questions/62088912/migrating-from-std-esm-to-esm-support-in-node-v14-cant-find-named-import-wo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants