Open lispmachine opened 3 years ago
This is not related to an import starting with @. It is due to webpack externals and what's called whitelisting in electron-webpack.
You can read a lot about it if you search he issues here. There is also documentation at https://webpack.electron.build/configuration#white-listing-externals
My recommendation: In your renderer webpack config, export a function instead of an object. It's the only way to have 100% control of the config and avoid merging with the defaults. In that function, you receive the current config with defaults and return the final config after mutation. Before you return, set externals to empty array.
module.exports = function (config) {
config.externals = [];
return config;
}
Furthermore, the problem at its core is that you need to have exactly one copy of react in your project. Otherwise you run into exactly your problem. However, when your dependencies are all specified as webpack externals, which is the default behavior with electron-webpack, then material-ui will bring its own copy of its react dependency. You have two copies of react and it goes boom. Same happens with most other libraries that have a dependency on react.
This is not related to an import starting with @. It is due to webpack externals and what's called whitelisting in electron-webpack.
You can read a lot about it if you search he issues here. There is also documentation at https://webpack.electron.build/configuration#white-listing-externals
My recommendation: In your renderer webpack config, export a function instead of an object. It's the only way to have 100% control of the config and avoid merging with the defaults. In that function, you receive the current config with defaults and return the final config after mutation. Before you return, set externals to empty array.
module.exports = function (config) { config.externals = []; return config; }
Yes this fixes this issue, as well as
module.exports = function (config) { config.externals.push('react'); return config; }
or the other way around
"electronWebpack": {
"whiteListedModules": ["@material-ui/core"],
}
in package.json
.
Is there a reason for react to be whitelisted by default?
Hehe. Well... It's complicated, and needlessly so :)
Electron-webpack has a hard-coded feature that puts all package names found in the package.json dependencies
(not devDependencies
!) to the webpack externals. I guess because doing that seemed to be a recommended best practice when working with webpack and electron. You can read up on webpack externals in their docs, there's a lot info online regarding externals and electron too.
"Whitelisting" in electron-webpack basically means "do not automatically put this package to the webpack externals". React, for obvious reasons as you too found out, cannot be treated as an external in electron apps when using webpack, instead it does need to be managed by webpack and placed into the final bundle, and deduplicated too. Any lib that needs it should load the same react and react-dom.
So at some point, one collaborator added react as default, because that too seemed to make sense (else you always had to whitelist it).
My stance on this is: bollocks! Let's make a major update with a breaking change and remove the externals/whitelisting feature altogether. It was a good intention to have some magic that leads users down the right path, but ultimately it takes away important responsibility from users. Plus it locks us into this very situation (there's literally dozens of issues about this, and to users it's never obvious what the problem is. It's always "lib xy doesn't work" but the same core issue/feature.)
The only stuff I actually ever needed to be treated as external was stuff I needed in the main process. Never ever had it been anything from the renderer process. And that makes sense - why shouldn't the renderer just run any bundle as if it was an actual web page. No externals needed, put it all in the bundle.
On main process, using stuff like sqlite or some native modules etc, there it makes sense to not try squeeze it into a bundle the same way as with a website. But users who need that will find it out and manually add lib xy to webpack externals. I mean, if you'd run into this problem, you'd be doing sophisticated stuff already and would probably understand a bit about coding, webpack, electron etc. It would be much better than e.g. newcomers (or veterans) who just wanna do a hello world or todo app run into this kind of issue right away.
This is not related to an import starting with @. It is due to webpack externals and what's called whitelisting in electron-webpack.
You can read a lot about it if you search he issues here. There is also documentation at https://webpack.electron.build/configuration#white-listing-externals
My recommendation: In your renderer webpack config, export a function instead of an object. It's the only way to have 100% control of the config and avoid merging with the defaults. In that function, you receive the current config with defaults and return the final config after mutation. Before you return, set externals to empty array.
module.exports = function (config) { config.externals = []; return config; }
I have the same problem, this works for me, thank you very much!
Steps to reproduce
git clone https://github.com/electron-userland/electron-webpack-quick-start.git
cd electron-webpack-quick-start
yarn add react react-dom @material-ui/core
src/index/renderer.js
const useStyles = makeStyles({ root: { background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)', height: '100vh', width: '100%', }, });
function Test() { const classes = useStyles(); return React.createElement('div', {className: classes.root}); }
ReactDOM.render(React.createElement(Test, null), document.getElementById('app'));
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
As you may see in a stack trace React is first loaded via webpack dev server (webpack-internal://), but @material-ui and its dependencies are loaded via direct file access (file://). This leads to 2 copies of React being used in the same app (case 3 in error message).
I suspect it is caused by alias from
@
to sourceDir.Workaround
So far I have managed to circumvent this issue by using webpack alias without
@
in the name.package.json
renderer.webpack.js
src/rendered/index.js