jspm / project

Roadmap and management repo for the jspm project
161 stars 8 forks source link

Named exports are not found with react-dnd #89

Closed antoineol closed 3 years ago

antoineol commented 3 years ago

Before all, thanks for your amazing work on this project! I'm working on a browser preview of an app, and it works quite well on a sample React app.

I've tried to include the react-dnd library, and I'm facing an issue: it seems that named exports are not found.

Reproduced on your sandbox here

The import syntax I use:

import { DndProvider } from 'https://jspm.dev/react-dnd';

And the browser gives me

The requested module 'https://jspm.dev/react-dnd' does not provide an export named 'DndProvider'

This syntax works well in a create-react-app sample (import { DndProvider } from 'react-dnd';).

A workaround is to use the default import instead:

import reactDnd from 'https://jspm.dev/react-dnd';
const { DndProvider } = reactDnd;

But it's not ideal, especially in my case where I'm not owner of the code, so I need to alter it as few as possible. In addition to the extra constraint: I'd need to auto-detect with import needs this workaround and which doesn't. Or apply it to all imports.

I have no idea about what the issue is, what else could be done to make it work a work around the issue. I've tried to alter the tsconfig settings (target and module), but I haven't found any working combination. The best case was a white screen with no error.

Any idea on this please?

Thanks a lot!

guybedford commented 3 years ago

Named exports are supported using the cjs-module-lexer project, see https://github.com/guybedford/cjs-module-lexer.

This is also the same approach Node.js itself now uses to detect named exports when importing a CommonJS module in Node.js.

So the short answer is - if it works in Node.js it will work in jspm.

If you look at the source code of react-dnd you can see why it can't statically detect the exports - https://unpkg.com/react-dnd@11.1.3/dist/cjs/index.js due to the use of loops which can't be analyzed by the detection process.

As for the details as to why this detection is necessary over bundlers like webpack, it's a problem of real ES module support versus "fake ES module support". And the details are long winded. There's a good blog post about it here - https://redfin.engineering/node-modules-at-war-why-commonjs-and-es-modules-cant-get-along-9617135eeca1#eb64 which was posted before the issues got resolved with cjs-module-lexer.

antoineol commented 3 years ago

Thanks for your quick reply! Interesting article.

So if I understand well, as of now, dynamic CJS named exports are handled by webpack (I guess dynamically), but not by node and jspm (and there is no agreement yet on this topic), so we can't expect an identical behavior, i.e. an app that works with webpack may need some changes on imports to fully work with jspm.

Does it look right?

If yes, in my case, it seems I have to go for my workaround and replace all named imports with a default import + destructuring :)

guybedford commented 3 years ago

Yes exactly, tools are still differing on the exact semantics, but jspm takes the stance of using the Node.js semantics as the model to follow, as that is something tools can align on in theory due to its stability, wide use, and clear spec.

This upgrade path has been referred to "faux esm to real esm", and yes these are exactly the sorts of steps that are involved. There will still be some friction between tools for a while, but the default form should be a safe bet I believe.

antoineol commented 3 years ago

Very clear, thanks a lot!