I am encountering the dreaded 'You might have more than one copy of React in the same app' error when I try to use a local React component library (bundled with rollup) in my host app (note: this only happens when I use hooks). It seems damn near impossible NOT to bundle 'react' and 'react-dom' into my library if it's included in devDependencies (necessary for testing/storybook), despite the fact that it's listed in peerDependencies in my package.json and externals in my rollup.config.js (and, to be clear, it is NOT under 'dependencies').
I've seen many solutions online that suggest linking the library to the copy of React in the host app (whether through aliases or resolving the modules directly from the host app's node_modules folder), but that doesn't work for me because the library is used in different apps. It NEEDS to be bundled as a peerDependency, which, in my mind, should not be this difficult. We previously bundled the code from the library directly into those apps with webpack, but figured it would be easier to maintain if we externalized it to a separate module.
Anyway, here are my configs. Please, God, tell me what I'm doing wrong.
Node v12.16.3 NPM 6.14.4
(Including because, from what I understand, npm@7 automatically bundles peerDependencies, but it would be a hassle to update on production, and I don't think it should be necessary for what I'm trying to do)
rollup.config.js
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import babel from '@rollup/plugin-babel';
import json from '@rollup/plugin-json';
import postCssModules from 'postcss-modules';
import svg from 'rollup-plugin-svg-import';
const packageJson = require('./package.json');
export default {
input: 'src/index.js',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true,
exports: 'auto',
globals: {
react: 'React',
'react-dom': 'ReactDOM',
'styled-components': 'styled'
}
}
],
external: ['react', 'react-dom', 'styled-component'],
plugins: [
peerDepsExternal({
includeDependencies: true
}),
babel({
babelHelpers: 'bundled',
exclude: ['node_modules/**', 'public/**'],
extensions: ['.js', '.jsx'],
plugins: [
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-transform-destructuring',
'babel-plugin-styled-components'
],
inputSourceMap: true
}),
commonjs({
include: /node_modules/
}),
svg(),
postcss({
plugins: [
postCssModules({
globalModulePaths: [
/node_modules\/rc-slider\/assets\/index.css/
]
})
]
}),
json(),
resolve({ preferBuiltins: true, browser: true })
]
};
package.json
{
"name": "MY_PACKAGE",
"version": "1.0.0",
"description": "package description",
"main": "public/index.js",
"files": [
"public"
],
"scripts": {
"unit-tests": "jest --config jest.config.json --testRegex ./.*\\.test\\.js$",
"unit-tests-watch": "jest --config jest.config.json --watch",
"generate-docs": "node ./docs_generator/generate.js",
"storybook": "start-storybook -p 6006 -s stories",
"storybook-debug": "start-storybook -p 6006 -s stories --debug-webpack",
"build-storybook": "build-storybook",
"build": "rollup -c"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^0.21.1",
"clone": "^2.1.2",
"core-js": "^3.6.5",
"prop-types": "^15.7.2",
"rc-slider": "^9.3.1",
"react-toggle": "^4.1.1"
},
"peerDependencies": {
"react-dom": "^16.13.1",
"react-is": "^16.13.1",
"styled-components": "^5.2.1",
"react": "^16.13.1"
},
"devDependencies": {
"@babel/core": "^7.11.1",
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
"@babel/plugin-transform-destructuring": "^7.10.4",
"@babel/polyfill": "^7.10.4",
"@babel/preset-env": "^7.11.0",
"@babel/preset-react": "^7.10.4",
"@babel/runtime": "^7.11.2",
"@rollup/plugin-babel": "^5.2.3",
"@rollup/plugin-commonjs": "^17.1.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^11.1.1",
"@storybook/addon-actions": "^6.1.14",
"@storybook/addon-essentials": "^6.0.16",
"@storybook/addon-knobs": "^6.0.16",
"@storybook/addon-links": "^6.0.16",
"@storybook/addon-options": "^5.3.19",
"@storybook/addon-storysource": "^6.0.16",
"@storybook/addons": "^6.0.16",
"@storybook/preset-scss": "^1.0.2",
"@storybook/react": "^6.0.16",
"@storybook/source-loader": "^6.0.16",
"animejs": "^2.2.0",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^26.3.0",
"babel-plugin-styled-components": "^1.11.1",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.3",
"enzyme-to-json": "^3.5.0",
"eslint": "^7.7.0",
"eslint-config-airbnb": "^18.2.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-jsx-a11y": "^6.3.1",
"eslint-plugin-react": "^7.20.6",
"eslint-plugin-react-hooks": "^4.2.0",
"jest": "^26.4.0",
"jest-junit": "^11.1.0",
"jest-styled-components": "^7.0.3",
"node-sass": "^4.14.1",
"postcss": "^8.2.5",
"postcss-modules": "^4.0.0",
"react-docgen": "^5.3.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-is": "^16.13.1",
"regenerator-runtime": "^0.13.7",
"rollup": "^2.38.5",
"rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-svg-import": "^1.5.1",
"sass-loader": "10.1.1",
"styled-components": "^5.2.1",
"typescript": "^4.1.5"
},
"private": "true"
}