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

Add esModuleInterop? #8

Closed
voxpelli opened this issue Mar 28, 2021 · 14 comments
Closed

Add esModuleInterop? #8

voxpelli opened this issue Mar 28, 2021 · 14 comments

Comments

@voxpelli
Copy link

See microsoft/TypeScript#41139

As stated in https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#support-for-import-d-from-cjs-from-commonjs-modules-with---esmoduleinterop:

We highly recommend applying it both to new and existing projects.

Should make TS and ESM work better together.

@sindresorhus
Copy link
Owner

Is it really needed when the TS package is native ESM? I remember using that flag in the past and it caused a lot of problems.

@voxpelli
Copy link
Author

It’s probably primarily needed when importing a CJS module or exporting as a CJS module, but overall it seems like it’s the ESM setup that the TS team intends to be its default but for extreme backwards compatibility reasons doesn’t dare to change into the default

@EdJoPaTo
Copy link
Contributor

Taking a look on the tsconfig recommended bases is interesting here.

The baseline and NodeJS 12 version both include esModuleInterop. (Interestingly the NodeJS 12 version has some libs included which are not included in this one. But thats a different topic)

When taking a look on the deno base esModuleInterop is not enabled. I am curious why.

Personally: As soon as one module has esModuleInterop enabled all the packages that depend on that also have to enable that. As I do not want to force that decision on the users I do not enable that in my modules.

@voxpelli
Copy link
Author

Does anyone know the TypeScript teams intention here? I’ve tried to figure it out at it all pointed me to esModuleInterop being the option they promote

@voxpelli
Copy link
Author

voxpelli commented Mar 29, 2021

An example from read-pkg:

ESM-code:

Skärmavbild 2021-03-29 kl  09 28 07

TS-code:

Skärmavbild 2021-03-29 kl  09 28 15

They should both really be the same, but yeah, that would probably require all users of the types to also adopt esModuleInterop 🤔

@fregante
Copy link
Contributor

fregante commented Jul 21, 2021

esModuleInterop breaks exports node usage when importing your module. In short it lets you import a CJS package but once you publish that code on npm then you get code that doesn't run.

The flag should probably only be used in projects that are not meant to be imported or uploaded to npm.

Unfortunately I don't have an alternative solution, you'll have to look in TypeScript's repo to find how they're dealing with it.

Webpack for example recently added support for the createRequire pattern, so tools are slowly catching up.

@voxpelli
Copy link
Author

By default (with esModuleInterop false or not set) TypeScript treats CommonJS/AMD/UMD modules similar to ES6 modules. In doing this, there are two parts in particular which turned out to be flawed assumptions:

From: https://www.typescriptlang.org/tsconfig#esModuleInterop

@fregante It's still the recommended option by the TypeScript team and its still as far as I can tell their intended fix for becoming more interoperable with the ESM landscape.

Is there a bug tracking the behavior you are mentioning? If not, can you mentioning it in microsoft/TypeScript#41139 and/or a dedicated issue?

The current limbo situation of esModuleInterop is really undesireable :/

@fregante
Copy link
Contributor

fregante commented Aug 25, 2021

Since this is still open, I want to reiterated that this is likely still a bad idea as a default.

TypeScript here is telling you this doesn't work, because it doesn't work. […]

Picture your future self, trying to run on a neato native ES6 module implementation and finding that you've set yourself up for major failure by trying to use ES6 syntax to do something that ES6 explicitly doesn't do.

My rule for this:

  • esModuleInterop: true for apps (final user)
  • esModuleInterop: false by libraries/modules (npm users)

true is useful in apps (webpack) because it simplifies usage of any package. The problem is that it breaks the output of libraries because it lets you import modules the wrong way. That wrong import will appear in tsc’s output as well, making it too easy to create non-importable npm packages, even if they pass the local tests.

I think more context can be found in:

@voxpelli
Copy link
Author

To make things even more interesting, TypeScript 4.5 looks likely to add two new 'module' types: node12 and nodenext. See microsoft/TypeScript#44501

Purpose of those are to eg. ensure that await import() doesn't get transpiled into require() when TypeScript is transpiled to CJS, thus enabling CJS-based TS projects to actually use ESM modules.

And most relevant to this thread:

both options imply esModuleInterop

@fregante
Copy link
Contributor

fregante commented Aug 25, 2021

ensure that await import() doesn't get transpiled into require()

🎉

And most relevant to this thread:

both options imply esModuleInterop

😰 That seems to contradict the first part.

Does that mean that the information I posted is outdated? I think node was exactly the problem back then. Maybe the issue was CJS transpilation, which isn't the default in this configuration anymore 🤔

@voxpelli
Copy link
Author

I know that @bmeck asked a possibly relevant question over there (microsoft/TypeScript#44501 (comment)) referencing a comment he made to my very issue that I started our thread here with

@bmeck
Copy link

bmeck commented Aug 27, 2021

esModuleInterop won't solve all the relevant concerns and would cause potentially more confusion unless well documented. Lots of docs around how default behaves different from native Node ESM would be desirable.

@voxpelli
Copy link
Author

To make things even more interesting, TypeScript 4.5 looks likely to add two new 'module' types: node12 and nodenext. See microsoft/TypeScript#44501

both options imply esModuleInterop

This shipped and since this config now uses "module": "node16" that means that esModuleInterop is now on in this config, see: microsoft/TypeScript#41139 (comment)

Actual code in TS for it: https://github.com/microsoft/TypeScript/blob/2bcfed01f3458996e71ce37af43e3495cb7e4950/src/compiler/utilities.ts#L6428-L6438

@fregante
Copy link
Contributor

I think this is fine because the "node16" config I think is annoyingly strict so this kind of interop doesn't really cause issues. 👍

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

6 participants
@voxpelli @sindresorhus @bmeck @fregante @EdJoPaTo and others