Reputation: 15413
I have a React microfrontend application. I have put together two sub apps so far that are rendered via the container/
project. In isolation, on localhost:8083 I can see the sub app rendering just nicely, but unlike the other sub apps, when I need to view it via localhost:8080/dashboard, I get nothing but a white screen and worse, no error in terminal, no error in console, no error in network requests.
This is my webpack.dev.js
file in container/
:
const { merge } = require("webpack-merge");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const commonConfig = require("./webpack.common");
const packageJson = require("../package.json");
const devConfig = {
mode: "development",
output: {
publicPath: "http://localhost:8080/",
},
devServer: {
port: 8080,
historyApiFallback: true,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
remotes: {
marketing: "marketing@http://localhost:8081/remoteEntry.js",
auth: "auth@http://localhost:8082/remoteEntry.js",
dashboard: "dashboard@http://localhost:8083/remoteEntry.js",
},
shared: packageJson.dependencies,
}),
],
};
module.exports = merge(commonConfig, devConfig);
I have looked at this repeatedly, don't see anything wrong there.
This is the webpack.common.js
file I have in that container/
folder:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react', '@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
},
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html'
}),
]
}
I have looked at that and don't see anything wrong there.
Here is my components/DashboardApp.js
file inside of container/
:
import { mount } from "dashboard/DashboardApp";
import React, { useRef, useEffect } from "react";
import { useHistory } from "react-router-dom";
export default ({ onSignIn }) => {
const ref = useRef(null);
const history = useHistory();
useEffect(() => {
const { onParentNavigate } = mount(ref.current, {
initialPath: history.location.pathname,
onNavigate: ({ pathname: nextPathname }) => {
const { pathname } = history.location;
if (pathname !== nextPathname) {
history.push(nextPathname);
}
},
onSignIn,
});
history.listen(onParentNavigate);
}, []);
return <div ref={ref} />;
};
My container/src/App.js
file:
import React, { lazy, Suspense, useState } from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
StylesProvider,
createGenerateClassName,
} from "@material-ui/core/styles";
import Progress from "./components/Progress";
import Header from "./components/Header";
const MarketingLazy = lazy(() => import("./components/MarketingApp"));
const AuthLazy = lazy(() => import("./components/AuthApp"));
const DashboardLazy = lazy(() => import("./components/DashboardApp"));
const generateClassName = createGenerateClassName({
productionPrefix: "co",
});
export default () => {
const [isSignedIn, setIsSignedIn] = useState(false);
return (
<BrowserRouter>
<StylesProvider generateClassName={generateClassName}>
<div>
<Header
onSignOut={() => setIsSignedIn(false)}
isSignedIn={isSignedIn}
/>
<Suspense fallback={<Progress />}>
<Switch>
<Route path='/auth'>
<AuthLazy onSignIn={() => setIsSignedIn(true)} />
</Route>
<Route path='/dashboard' component={DashboardLazy} />
<Route path='/' component={MarketingLazy} />
</Switch>
</Suspense>
</div>
</StylesProvider>
</BrowserRouter>
);
};
Can anyone see anything I may have missed? Why would this component not render through the container/
whereas the other sub apps built exactly the same can.
Upvotes: 1
Views: 898
Reputation: 15413
When an application starts to grow in complexity, it's the smallest detail. While my container/src/App.js
file had a path="/dashboard"
, my dashboard/src/App.js
file did not, it looked like this:
import React from "react";
import { Switch, Route, Router } from "react-router-dom";
import {
StylesProvider,
createGenerateClassName,
} from "@material-ui/core/styles";
import Dashboard from "./components/Dashboard";
const generateClassName = createGenerateClassName({
productionPrefix: "da",
});
export default ({ history }) => {
return (
<div>
<StylesProvider generateClassName={generateClassName}>
<Router history={history}>
<Switch>
<Route exact path='/' component={Dashboard} />
</Switch>
</Router>
</StylesProvider>
</div>
);
};
Once I changed it to this:
import React from "react";
import { Switch, Route, Router } from "react-router-dom";
import {
StylesProvider,
createGenerateClassName,
} from "@material-ui/core/styles";
import Dashboard from "./components/Dashboard";
const generateClassName = createGenerateClassName({
productionPrefix: "da",
});
export default ({ history }) => {
return (
<div>
<StylesProvider generateClassName={generateClassName}>
<Router history={history}>
<Switch>
<Route exact path='/dashboard' component={Dashboard} />
</Switch>
</Router>
</StylesProvider>
</div>
);
};
Now it displays inside parent container.
Upvotes: 1
Reputation: 1239
You are missing contentBase.
devServer: {
contentBase: path.join(__dirname, "dist"),
port: 3002,
},
output: {
publicPath: "http://localhost:3002/",
},
Upvotes: 0