streamich / react-use

React Hooks — 👍
http://streamich.github.io/react-use
The Unlicense
41.64k stars 3.14k forks source link

react-use cannot be imported in Node.js #2353

Open ocavue opened 2 years ago

ocavue commented 2 years ago

What is the current behavior?

I can't use ESM syntax to import react-use in Node.js. I found this issue when I try to run some unit tests on Node.js.

The reason for this issue is that the following package.json is not supported by Node.js. There is a detailed explanation https://github.com/sheremet-va/dual-packaging

{
  "name": "react-use",
  "main": "lib/index.js",
  "module": "esm/index.js",
  ...
}

There are some simple methods to fix this issue. More explanation in the link above.

  1. Put a package.json under esm/, with the content {"type": "module"};
  2. Or, rename all .js file under esm/ to .mjs;
  3. Or. rename all .js file under lib/ to .cjs.

Steps to reproduce it and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have extra dependencies other than react-use. Paste the link to your JSFiddle or CodeSandbox example below:

bash-3.2$ pnpm add react-use
dependencies:
+ react-use 17.4.0
bash-3.2$
bash-3.2$ echo 'import {useDefault} from "react-use"' > a.mjs
bash-3.2$
bash-3.2$ node a.mjs
file:///private/tmp/a.mjs:1
import {useDefault} from "react-use"
        ^^^^^^^^^^
SyntaxError: Named export 'useDefault' not found. The requested module 'react-use' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'react-use';
const {useDefault} = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:128:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:194:5)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

What is the expected behavior?

react-use can be imported in a .mjs file with ESM syntax.

A little about versions:

aamree commented 2 years ago

bash-3.2$ pnpm add react-use dependencies:

  • react-use 17.4.0 bash-3.2$ bash-3.2$ echo 'import {useDefault} from "react-use"' > a.mjs bash-3.2$ bash-3.2$ node a.mjs file:///private/tmp/a.mjs:1 import {useDefault} from "react-use" ^^^^^^^^^^ SyntaxError: Named export 'useDefault' not found. The requested module 'react-use' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using:

import pkg from 'react-use'; const {useDefault} = pkg;

at ModuleJob._instantiate (node:internal/modules/esm/module_job:128:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:194:5)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
at async loadESM (node:internal/process/esm_loader:88:5)
at async handleMainPromise (node:internal/modules/run_main:61:12)

I also faced this problem. Is there a temporary solution?

nemanja-tosic commented 1 year ago

I use a setup where react-use is imported by both a node module (node 16) and nextjs - node cannot use named exports reliably for CJS and if i use the default export format, then nextjs' build fails saying that there isn't a default export (because there isn't, seeing how it's node's interop that adds it). Using a namespace import leads to Node not recognizing all default re-exports.

Direct file import such as

import useUpdateEffect from 'react-use/lib/useUpdateEffect.js';

leads to

{ default: [Function: useUpdateEffect] }

Needless to say, ESM CJS interop is a mess...

kaisermann commented 1 year ago

I'm getting the same issue. I'm updating my app to react@18 and next@13, which automatically supports properly-packaged esm packages. However, as stated by the OP, a .mjs file can't import a .js file even though its contents are ESM. Is it possible to export the esm version as .mjs files?

edit: It seems that it's possible to add a package.json with { type: module } in the dist/esm/ directory, but I'm not sure how that would affect existing projects that are using the current esm exports.

Mange commented 11 months ago

This seems to happen to me to using Remix. Everything should be ESM, but I still get server-side errors trying to import the library.

I'll have to move over to some other hooks library.

msurdi commented 10 months ago

Just found this issue. In case it helps somebody else, here's my workaround until the underlying problem is resolved:

import useKeyLib from "react-use/lib/useKey.js";
const useKey = useKeyLib.default;
ThibautMarechal commented 6 months ago

I have the same issue. I made a quick reproduction with remix, using the create-remix, then I added react-use. Any recommended import is failing to compile. (repro: https://github.com/ThibautMarechal/react-use-in-remix)

folushooladipo commented 6 months ago

I am also experiencing the issue when using Remix. This import error is a real downside to using this awesome library. I hope there will be a fix soon.

folushooladipo commented 6 months ago

Also, for anyone using TypeScript and Remix, here's another possible workaround that extends @msurdi 's own:

real34 commented 5 months ago

For Vite-based projects (& Remix), this configuration should also solve the issue:

// vite.config.ts
import { defineConfig } from "vite";

export default defineConfig((env) => {
  return {
    // […]
    ssr: {
      noExternal: ["react-use"],
    },
    optimizeDeps: {
      include: ["react-use"],
    },
  };
});
tizmagik commented 4 months ago

For reference: https://publint.dev/react-use@17.5.0