I have the following architecture:
main-frontend
foo-frontend
bar-frontend
baz-frontend
main-frontend, foo-frontend, bar-frontend and baz-frontend are all standard React apps generated using create-react-app.
All of them except main-frontend publish their UI as a React component, wrapped in a Web component. These Web components can be loaded into the main-frontend to weave all 3 sub-frontends into one super-frontend.
The problem I am facing is that in order for this approach to work, all 4 frontends have to externalize react, react-dom, react-router, and any CSS-in-JS frameworks being used.
I am able to modify Webpack configuration for create-react-app generated React apps, using the rewire package and a couple of scripts. I am reproducing these below for others facing a similar problem.
In each of foo-frontend, bar-frontend, and baz-frontend,
package.json
"dependencies": {
...
"rewire": "^6.0.0"
...
},
"scripts": {
"start": "node start.js",
"build": "node build.js",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"webpackConfig": {
"externals": {
"react": "react",
"react-dom": "react-dom",
"@emotion/react": "@emotion/react",
"@emotion/styled": "@emotion/styled"
}
}
build.js
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/build.js');
const {
webpackConfig: {
externals
}
} = require('./package.json');
const config = defaults.__get__('config');
config.externals = externals;
start.js
const rewire = require('rewire');
const defaults = rewire('react-scripts/scripts/start.js');
const webpackConfig = require('react-scripts/config/webpack.config');
const {
webpackConfig: {
externals
}
} = require('./package.json');
defaults.__set__('configFactory', (webpackEnv) => {
const config = webpackConfig(webpackEnv);
config.externals = externals;
return config;
});
public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
...
<title>Atlas Reviews</title>
<script src="https://cdn.jsdelivr.net/npm/react@18.1.0/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@18.1.0/umd/react-dom.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@emotion/react@11.9.0/dist/emotion-react.umd.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@emotion/styled@11.8.1/dist/emotion-styled.umd.min.js"></script>
</head>
<body>
...
</body>
</html>
The problem I am getting is that @emotion/react and @emotion/styled aren't being externalized correctly.
Uncaught ReferenceError: emotion is not defined
at Object.@emotion/react (external var "emotion":1:1)
at Object.options.factory (react refresh:6:1)
at __webpack_require__ (bootstrap:24:1)
at fn (hot module replacement:62:1)
at Module../src/components/App/styles.tsx (index.tsx:25:1)
at Module.options.factory (react refresh:6:1)
at __webpack_require__ (bootstrap:24:1)
at fn (hot module replacement:62:1)
at Module../src/components/App/index.tsx (logo.svg:34:1)
at Module.options.factory (react refresh:6:1)
How do I fix this?