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

Hooks error on React library compiled with Rollup.js #14721

Closed
davegomez opened this issue Jan 29, 2019 · 29 comments
Closed

Hooks error on React library compiled with Rollup.js #14721

davegomez opened this issue Jan 29, 2019 · 29 comments

Comments

@davegomez
Copy link

Disclaimer: I'm not sure if this is an specific bug from React's Hooks or it is something I'm missing in my Rollup.js configuration but I've been trying a lot of different things and always end up in the same error.

Hooks can only be called inside the body of a function component.

I'm building a React Component library using the alpha version of React and Hooks, and using Rollup.js v1.1.2 as a bundler with the next configuration:

import { readdirSync } from 'fs';
import path from 'path';
import babel from 'rollup-plugin-babel';
import commonjs from 'rollup-plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import replace from 'rollup-plugin-replace';
import resolve from 'rollup-plugin-node-resolve';
import { terser } from 'rollup-plugin-terser';

const CODES = [
  'THIS_IS_UNDEFINED',
  'MISSING_GLOBAL_NAME',
  'CIRCULAR_DEPENDENCY',
];

const getChunks = URI =>
  readdirSync(path.resolve(URI))
    .filter(x => x.includes('.js'))
    .reduce((a, c) => ({ ...a, [c.replace('.js', '')]: `src/${c}` }), {});

const discardWarning = warning => {
  if (CODES.includes(warning.code)) {
    return;
  }

  console.error(warning);
};

const env = process.env.NODE_ENV;

const plugins = [
  external(),
  babel({
    exclude: 'node_modules/**',
  }),
  resolve(),
  replace({ 'process.env.NODE_ENV': JSON.stringify(env) }),
  commonjs(),
  env === 'production' && terser(),
];

export default [
  {
    onwarn: discardWarning,
    input: 'src/index.js',
    output: {
      esModule: false,
      file: 'umd/library-name.js',
      format: 'umd',
      name: 'libraryName',
    },
    plugins,
  },
  {
    onwarn: discardWarning,
    input: getChunks('src'),
    output: [
      { dir: 'esm', format: 'esm', sourcemap: true },
      { dir: 'cjs', format: 'cjs', sourcemap: true },
    ],
    plugins,
  },
];

For the examples page I created an internal project using create-react-app and I'm importing the library in the package.json using link:..

The page breaks as soon as it gets to the first Hooks call var svgRef = useRef(); with the error mentioned above, but this only happens when I'm using the bundled code from the ESM file not when I'm using the library code directly. That's why I'm not sure if it is a Rollup misconfiguration or a React Hooks bug.

I appreciate any help or guidance on this.

React v16.8.0-alpha.1
React DOM v16.8.0-alpha.1
OS: macOS
Browser: Chrome
Node.js v11.8.0

I did test it with a previous alpha version of React and it happens the same.

@alexandernanberg
Copy link

I think this is the same issue I ran into in styled-components/styled-components#2349

@gaearon
Copy link
Collaborator

gaearon commented Jan 29, 2019

You probably have two Reacts.

@gaearon
Copy link
Collaborator

gaearon commented Jan 29, 2019

Specifically I think you’re mistakenly bundling React itself into your library. It should be an external instead.

@gaearon gaearon closed this as completed Jan 29, 2019
@davegomez
Copy link
Author

davegomez commented Jan 29, 2019

I don't think this is the case @gaearon so I would like to provide a little bit more context to see if might be something else.

I have React, React DOM, and Styled Components as peer dependencies of my library:

  "dependencies": {
    "color": "^3.1.0",
    "d3-array": "^2.0.3",
    "d3-axis": "^1.0.12",
    "d3-format": "^1.3.2",
    "d3-scale": "^2.1.2",
    "d3-selection": "^1.4.0",
    "d3-shape": "^1.3.3",
    "d3-time-format": "^2.1.3",
    "d3-transition": "^1.2.0",
    "date-fns": "^2.0.0-alpha.27",
    "ramda": "^0.26.1"
  },
  "devDependencies": {
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "cross-env": "^5.2.0",
    "flow-bin": "^0.91.0",
    "jest-styled-components": "^6.3.1",
    "react-scripts": "^2.1.3",
    "react-test-renderer": "^16.8.0-alpha.1",
    "rollup": "^1.1.2",
    "rollup-plugin-babel": "^4.3.2",
    "rollup-plugin-commonjs": "^9.2.0",
    "rollup-plugin-node-resolve": "^4.0.0",
    "rollup-plugin-peer-deps-external": "^2.2.0",
    "rollup-plugin-replace": "^2.1.0",
    "rollup-plugin-terser": "^4.0.3"
  },
  "peerDependencies": {
    "react": "^16.8.0-alpha.1",
    "react-dom": "^16.8.0-alpha.1",
    "styled-components": "^4.1.3"
  }

Besides having React as a peerDependency I have to install it as a devDependency otherwise I'm getting this error (but I think this is a different issue):

Failed to compile.

../esm/index.js
Module not found: Can't resolve 'react' in '/Users/user/library/esm'

The internal examples page has the following package.json file:

{
  "name": "examples",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "normalize.css": "^8.0.1",
    "react": "^16.8.0-alpha.1",
    "react-dom": "^16.8.0-alpha.1",
    "react-scripts": "2.1.3",
    "library-name": "link:..",
    "styled-components": "^4.1.3"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

And if I check the node_modules directory only one version of React is installed.

Please let me know if I can provide mode information on this? I would code a pen or something trying to replicate what is happening but I'm not sure if I can do a pen to replicate the Rollup part.

I'm gonna try to publish the code soon in case it might be of some help.

Update

I just try to use the library using npm link from an external create-react-app project using the same configuration and I got the same result. I still need to add React as a devDependency and now I'm getting a different error if I use the production build (a Webpack related error) I guess from create-react-app.

@gaearon
Copy link
Collaborator

gaearon commented Jan 30, 2019

I can’t guess what’s wrong in your particular setup but I’ve described the issue: you’ll see it when you have two Reacts in the resulting bundle. Check the bundle contents. I can’t help you with setting up Rollup, what its errors mean, or how Node resolutions works — just the React part which is definitely related to that.

Npm link is known for causing this because webpack would “see” React both in your lib folder and in your app folder, and would include both of them in the bundle. A common workaround is to npm link back from your lib’s node_modules/react into your app’s React copy.

@eduardosanzbBCG
Copy link

eduardosanzbBCG commented Feb 12, 2019

@davegomez do you have any update on the issue? Did you solved it?

(Currently having the same issue, plus I'm also using typescript)
Thanks!

Update
I solved it following this comment

@davegomez
Copy link
Author

Hello @eduardosanzbBCG I did solve it. Check out the configuration file I have for Rollup. Is working great!

@eduardosanzbBCG
Copy link

@davegomez Thank you!

@lukeivie
Copy link

@davegomez I see your configuration file and I'm glad it's working, but can you point me to what the change was specifically that got this working for you?

@davegomez
Copy link
Author

@lukeivie the problem was exactly what @gaearon mentioned in the comment above.

#14721 (comment)

@agusterodin
Copy link

If I exclude react and react-dom as devDependencies in my library source, I do not get the hooks error when attempting to use my component in a web app. Unfortunately not having react as a devDependency means I get issues like:

Error while loading rule 'react/no-direct-mutation-state': Cannot find module 'react'

when attempting to use eslint-config-react-app. Naturally, installing react as a devDependency makes the linter work with zero issues but then I am back to the problem of hooks not working. I have set up react and react-dom as external and global in my rollup config but that doesn't fix anything. 2 days of my life gone trying to figure this out :(

@yugandhar-pathi
Copy link

@gaearon .. I think this issue is not just happening because of two versions of react, When we use hooks in a component library and bundle it as ES6 distribution, hooks are pushed inside conditions (like if) and we are getting this error. I am including library as file:../ Can you please tell how to overcome this.

@lcfd
Copy link

lcfd commented Oct 10, 2019

I'm facing the same

Hooks can only be called inside the body of a function component.

problem.

Is this problem closed and solved for real? Are we doing something wrong with rollup?

@kelvinlouis
Copy link

@fedriz maybe this thread helps: #13991

@ghostjzf
Copy link

I'm facing the same problem. who can help me or tell me how to solve it

@adrian-marcelo-gallardo

@ghostjzf if your problem is because of linking the package locally (and not installing from npm repository), then #13991 (comment) solves the problem.

If not that, then the problem is that you should add react as an external dependency in your rollup config, e.g:


  external: [
    'react',
    'react-dom',
  ],

@ghostjzf
Copy link

@ghostjzf if your problem is because of linking the package locally (and not installing from npm repository), then #13991 (comment) solves the problem.

If not that, then the problem is that you should add react as an external dependency in your rollup config, e.g:


  external: [
    'react',
    'react-dom',
  ],

thank you for your help, but when I use the “npm link” to test it, it’s also facing the same problem

@maciekgrzybek
Copy link

Not sure if that will help anyone, but what worked for me was:

  • in rollup.config.js setting up externals, just like @adraeth mentioned before, so:
  external: [
    'react',
    'react-dom',
  ],
  • remove react and react-dom from the dependencies and move them to peerDependencies
  • and (I can't stress this enough) remove and reinstall node_modules

Hope that helps 🤞

@soorajshankar
Copy link

I was struggling with this problem for quite sometime later realized that this happens only when you use this locally with npm link
and for that #13991 (comment) this works fine.
but make sure you apply this to the example project.

I prefer using storybookJS to test the components:)

@michaelbayday
Copy link

I can get this to work by deleting the react and react-dom node modules within my shared components library, but i can't figure out how to bundle my rollup so that it doesnt include these

@fcastillo90
Copy link

@michaelbayday im having the exact same error, how did u solved this? thanks!

@michaelbayday
Copy link

If you're adding the library locally via npm link you just need to add an alias to the resolve key of webpack config

@fcastillo90
Copy link

but add the alias in your final app or in your library? @michaelbayday

@michaelbayday
Copy link

Final app

@Dissolutio
Copy link

Dissolutio commented Apr 8, 2021

This was rough, and I learned a lot, but in the end what worked for me was manually editing (in MyLib that's sym-linked into MyProject) the build output dist/index.esm.js file, and changing the import of React:

// change this
import React from 'react';
// to this
import React from '../../../MyProject/node_modules/react';

It's annoying, and I changed the build script in my lib to do this for me, but it was so sweet when it WORKED:

// in package.json scripts field
  "build": "npx rollup -c && npm run fixreact",
  "fixreact": "sed -i 's+react+../../../bgio/battlescape/node_modules/react+' ./dist/index.esm.js",

Hope this helps any other stuck folks, I'm on linux so your sed command might be different.

@sipatieff
Copy link

@ghostjzf if your problem is because of linking the package locally (and not installing from npm repository), then #13991 (comment) solves the problem.

If not that, then the problem is that you should add react as an external dependency in your rollup config, e.g:


  external: [
    'react',
    'react-dom',
  ],

Work for me, you're the best!

@willleahy
Copy link

This was rough, and I learned a lot, but in the end what worked for me was manually editing (in MyLib that's sym-linked into MyProject) the build output dist/index.esm.js file, and changing the import of React:

// change this
import React from 'react';
// to this
import React from '../../../MyProject/node_modules/react';

It's annoying, and I changed the build script in my lib to do this for me, but it was so sweet when it WORKED:

// in package.json scripts field
  "build": "npx rollup -c && npm run fixreact",
  "fixreact": "sed -i 's+react+../../../bgio/battlescape/node_modules/react+' ./dist/index.esm.js",

Hope this helps any other stuck folks, I'm on linux so your sed command might be different.

Wow I was losing my mind all day and this was the only thing that worked for me, thank you!

@Babailan
Copy link

@willleahy same as i do thanks to this thread i fixed it

@cyrfer
Copy link

cyrfer commented Mar 13, 2023

I needed to add this:

import packageJson from "./package.json" assert { type: "json" };
...
// after output property
external: [...Object.keys(packageJson.peerDependencies || {})],

To properly avoid exporting my many peerDependencies:

"peerDependencies": {
    "@emotion/react": "^11.10.6",
    "@emotion/styled": "^11.10.6",
    "@mui/material": "^5.11.12",
    "@types/react": "^18.0.28",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
}

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