theKashey / react-focus-lock

It is a trap! A lock for a Focus. πŸ”“
MIT License
1.27k stars 67 forks source link

Fix module resolution issues in dual CJS/ESM setup #264

Closed wojtekmaj closed 4 months ago

wojtekmaj commented 10 months ago

This PR:

arethetypeswrong CLI shows a clear improvement:

Before:

react-focus-lock % attw react-focus-lock-v2.11.3.tgz

react-focus-lock v2.11.3

🀨 CommonJS module simulates a default export with exports.default and exports.__esModule, but does not also set module.exports for compatibility with Node. Node, and some bundlers under certain conditions, do not respect the __esModule marker, so accessing the intended default export will require a .default property access on the default import. https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/CJSOnlyExportsDefault.md

"react-focus-lock"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🀨 CJS default export
bundler: 🀨 CJS default export

***********************************

"react-focus-lock/UI"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🀨 CJS default export
bundler: 🀨 CJS default export

***********************************

"react-focus-lock/sidecar"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🀨 CJS default export
bundler: 🀨 CJS default export

***********************************

After:

react-focus-lock % attw react-focus-lock-v2.11.3.tgz

react-focus-lock v2.11.3

 No problems found 🌟

"react-focus-lock"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🟒 (ESM)
bundler: 🟒 

***********************************

"react-focus-lock/sidecar"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🟒 (ESM)
bundler: 🟒 

***********************************

"react-focus-lock/UI"

node10: 🟒 
node16 (from CJS): 🟒 (CJS)
node16 (from ESM): 🟒 (ESM)
bundler: 🟒 

***********************************

Fixes #257

theKashey commented 10 months ago

Give me some time to test integratons.

wojtekmaj commented 10 months ago

One improvement that comes to my mind is that .d.ts files sitting in pseudorepo /sidecar and /UI directories could reexport type definitions from /dist/cjs instead.

theKashey commented 10 months ago

I would really like to rewrite focus-lock in TS and don't worry about manual type declarations. So, don't worry about them πŸ˜‰

theKashey commented 8 months ago

Oh, time flies and I am still buried in work. Sorry, should become more free closer to the new year.

wojtekmaj commented 8 months ago

Don't worry mate. No one has the right to expect anything from you for $0.

stale[bot] commented 6 months ago

This issue has been marked as "stale" because there has been no activity for 2 months. If you have any new information or would like to continue the discussion, please feel free to do so. If this issue got buried among other tasks, maybe this message will reignite the conversation. Otherwise, this issue will be closed in 7 days. Thank you for your contributions so far.

stale[bot] commented 4 months ago

This issue has been marked as "stale" because there has been no activity for 2 months. If you have any new information or would like to continue the discussion, please feel free to do so. If this issue got buried among other tasks, maybe this message will reignite the conversation. Otherwise, this issue will be closed in 7 days. Thank you for your contributions so far.

wojtekmaj commented 4 months ago

Bad bot!

theKashey commented 4 months ago

I am a little hesitant to move forward due to the problem highlighted at https://github.com/gregberge/loadable-components/pull/1003

This moves change from "just here" to "all consumers".

The "safe" way forward lies in refactoring of react-clientside-effect in order to make it "duplication aware", for example via tracking singletons via stable(string) keys.


The question I dont have an answer for - what is required from downstream packages in order to make this one ESM-compatible. Ie, do I need to esm react-clientside-effect, potentially causing the same "duplication" to it, or can keep it as is, making it easier to track references.

@wojtekmaj - I really hope you have some answers for the questions above, well the one question - managing "singleton" in ESM packages.

wojtekmaj commented 4 months ago

@theKashey - The approach I took with dual ESM/CJS config presented here was battle tested in React-PDF, React-Calendar, React-Date-Picker and many other packages I maintain.

I do understand your concerns though.

react-clientside-effect looks like a fairly simple module ESM should have no issues with. It might be converted to dual CJS/ESM, but doesn't need to be. I confirmed this by running an ESM version of react-focus-lock from this PR in pure Node.js, and checked that withSideEffect is still a function and not e.g. { default: [Function: withSideEffect] }.

wojtekmaj commented 4 months ago

I rebased the PR off latest master, and edited the first comment, since now the PR is making everything green, not just ESM module resolution!

theKashey commented 4 months ago

and checked that withSideEffect is still a function

More about there is a possibility to reach withSideEffect via require path and then via import path, resulting in two different worlds, not one singlenton.

Could affect only cases with multiple modals being open using different ways to open them. Not sure how "real" this case is, but it's the only moment that separates this package from others.

wojtekmaj commented 4 months ago

Not sure how "real" this case is

Most bundlers will probably use ESM, because they are capable of resolving ESM. Even if the modules are CJS, they are "wrapped" so that they could all talk to each other seamlessly. If you don't use any bundler at all, you're forced to use ESM, because CJS doesn't work outside of Node. I may be missing something here, but I don't see how you'd end up with two versions of react-focus-lock. Perhaps in a Node.js-only application, where you could actually use both import in ESM and require in CJS, but that's not a realistic scenario for a front-end package, and also, if you write both ESM and CJS in one Node.js project, you really should reconsider your life choices.

theKashey commented 4 months ago

I tend to agree - the problem with loadable-components happened at the server side and FocusLock is a purely front-end component, including the "dangerous part" being named as react-CLIENTSIDE-effect

theKashey commented 4 months ago

It will take a few days to test it as deeply as I possibly could...

@wojtekmaj+++ and πŸ™‡ for all your effort and impact.