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

Exports in package.json don't work as expected in ESM #1

Closed
darksabrefr opened this issue Jan 23, 2025 · 13 comments
Closed

Exports in package.json don't work as expected in ESM #1

darksabrefr opened this issue Jan 23, 2025 · 13 comments

Comments

@darksabrefr
Copy link

Hello,

In an ESM and node context, this lib causes this warning. It's indirectly imported from traverse > typedarray.prototype.slice > typed-array-byte-offset > reflect.getprototypeof > which-builtin-type > is-async-function in our setup.

ExperimentalWarning: CommonJS module /project/node_modules/is-async-function/index.js is loading ES Module /project/node_modules/async-function/require.mjs using require().
Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
ExperimentalWarning: CommonJS module /project/node_modules/is-async-function/index.js is loading ES Module /project/node_modules/async-function/require.mjs using require().
Support for loading ES Module in require() is an experimental feature and might change at any time
     at require (node:internal/modules/helpers:136:16)
     at Object.<anonymous> (/project/node_modules/is-async-function/index.js:13:20)
     at Module._compile (node:internal/modules/cjs/loader:1546:14)
     at Object..js (node:internal/modules/cjs/loader:1698:10)
     at Module.load (node:internal/modules/cjs/loader:1303:32)
     at Function._load (node:internal/modules/cjs/loader:1117:12)
     at TracingChannel.traceSync (node:diagnostics_channel:322:14)
     at wrapModuleLoad (node:internal/modules/cjs/loader:218:24)
     at Module.require (node:internal/modules/cjs/loader:1325:12)
     at require (node:internal/modules/helpers:136:16)

The exports field of the package.json is weird too :

	"exports": {
		".": [
			{
				"module-sync": "./require.mjs",
				"import": "./index.mjs",
				"default": "./index.js"
			},
			"./index.js"
		],
		"./package.json": "./package.json"
	},
@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

What node version are you using?

That's just a warning, and I would expect the latest versions of node, if not now then very soon, to stop producing this warning.

@darksabrefr
Copy link
Author

Node 23.6.1, current. This warning is problematic as it may crash mocha in some situations.
The exports is very weird, and it's not normal that node loads the CommonJS entry point (./index.js). It should resolve to the ESM entry point (./index.mjs), but as you can see in the stack trace, it's not the case.

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

Using the module-sync exports condition is expected here, because when you require('async-function') in a version of node that supports requiring ESM, you'll get module-sync if it exists (ie, require.mjs).

I'm confused why it would crash mocha - node issues experimental warnings all the time, especially using a non-LTS version of node. Either way, it can be suppressed with a number of methods, discussed in nodejs/node#55417

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

Actually, in node 23.6.1 running node -pe "require('async-function')" in a project with the package installed, i don't see any warning. Are you using experimental flags, or do you have NODE_OPTIONS set?

@darksabrefr
Copy link
Author

No experimental flag, no NODE_OPTIONS, just the raw node executable.
We are using ES import, not CommonJS require.

In fact, this problem has appeared with the 2.1.1 version of is-async-function, linking this packet. The 2.1.0 doesn't present this problem (as it's doesn't depend on this packet).
Mocha is just a consequence that we have seen, it's not the real problem here (it seems to get this warning message at this beginning of a source file it load, so it's not a valid JS file).
Node nearly never emits experimental warnings with published npm packet!

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

hmm, i can't reproduce it using import either. Are you using native import, or transpiling? What version of mocha?

(v2.1.1 of is-async-function is the first version using the async-function package, so it's expected that this behavior wouldn't occur with an older version - as for "nearly never", you can see from the linked issue that it happens quite a lot with this particular warning)

@darksabrefr
Copy link
Author

darksabrefr commented Jan 23, 2025

I had made a small version confusion for node between my local and my docker env. In fact, in 23.6.1, the problem doesn't exist. But my docker env is still 23.3.0, and under that version, the warning is present.
Loading ECMAScript modules using require() is not experimental since the 23.5.0 version (in fact, it doesn't display the warning message by default anymore but is still experimental), that's not so old : https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

aha - so the warning disappears if you upgrade to the latest (a supported) version of node 23 :-) glad to hear it.

@darksabrefr
Copy link
Author

Thank you for your time and your the help !

@darksabrefr
Copy link
Author

darksabrefr commented Jan 23, 2025

If you want more information about the context of the error in mocha, that's sill occurring even with node 23.6.1:
We have mocha tests using the tsx loader, to run Typescript files, and tsx crashes when loading ./require.mjs of async-function through the is-async-function module.
The minimal reproducible exemple is, file test.ts:

import isAsyncFunction from 'is-async-function';

then tsx test.ts
At this point, the underlying error will be:

/project/node_modules/async-function/require.mjs:2
var __create=Object.create;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __getProtoOf=Object.getPrototypeOf;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toESM=(mod,isNodeMode,target)=>(target=mod!=null?__create(__getProtoOf(mod)):{},__copyProps(isNodeMode||!mod||!mod.__esModule?__defProp(target,"default",{value:mod,enumerable:true}):target,mod));var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var require_exports={};__export(require_exports,{default:()=>require_default,"module.exports":()=>import_index.default});module.exports=__toCommonJS(require_exports);var import_index=__toESM(require("./index.js"));var require_default=import_index.default;0&&(module.exports={"module.exports"});
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            

SyntaxError: Unexpected string
    at wrapSafe (node:internal/modules/cjs/loader:1670:18)
    at Module._compile (node:internal/modules/cjs/loader:1713:20)
    at Object.transformer (/project/node_modules/tsx/dist/register-DCnOAxY2.cjs:2:1186)
    at Module.load (node:internal/modules/cjs/loader:1473:32)
    at Function._load (node:internal/modules/cjs/loader:1285:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:234:24)
    at Module.require (node:internal/modules/cjs/loader:1495:12)
    at require (node:internal/modules/helpers:135:16)
    at Object.<anonymous> (/project/node_modules/is-async-function/index.js:15:20)

Node.js v23.6.1

Interestingly, if I force the module to load index.mjs instead of require.mjs, everything is fine.
Any idea about that? Maybe the strange export { getAsyncFunction as 'module.exports' }; in require.mjs?

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

That seems like an issue with tsx - require.mjs works natively and shouldn't need to be transpiled at all (it's showing as transpiled in that stack trace).

That as 'module.exports' is a standard string named export, but that specific name is something node uses for require(esm).

I suggest filing an issue on tsx about it.

@darksabrefr
Copy link
Author

Thank you again for your help!
I also hope you can make an ESM version soon of is-async-function, all these layers of compatibility between ESM and CommonJS in the JS eco-system can't run fine every time. In my company, we precisely abandoned CommonJS in favor of ESM for these reasons.
And now, I will try to find something in the tsx's github!

@ljharb
Copy link
Owner

ljharb commented Jan 23, 2025

CJS isn't ever going away, so I don't expect that will ever happen.

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