Delay using a federated module
Posted 9 August 2024
Since moving to a microfrontend shell architecture we've started to look at sharing some modules outside of the shell for older web applications. When sharing our React header component one of the teams ran into a Webpack error.
When attempting to render the component from a federated module instead of an npm package the app crashes with this error:
TypeError: __webpack_modules__[moduleId] is not a function
The issue was that the application was trying to render the React component before Webpack had loaded the remoteEntry.js
file. There's a couple of ways to deal with this.
Add a bootstrap file
Add a new entrypoint to your bundle that uses a dynamic import to include the rest of the application.
For example if you were previously loading src/index.js
as the main entrypoint add a new src/bootstrap.js
file with:
import("./index");
And then update Webpack entry to point to src/bootstrap.js
. You can then immediately render federated React components within src/index.js
as they will have loaded in time.
Note: If you're using Babel <7.8.0 if you'll need to load a plugin to support this syntax. You should also look at upgrading!
Lazy loading and Suspense
Alternatively you can use React.lazy
to delay rendering a React component until it's loaded. This also uses the dynamic import syntax:
const RemoteComponent = React.lazy(
() => import("remote-module/RemoteComponent")
);
const App = () => (
<React.Suspense fallback={<span>Loading...</span>}>
<RemoteComponent />
</React.Suspsense>
);
The fallback span will render until the remote has loaded and is available. With this approach you can also delay loading the remoteEntry.js
until it's required, as covered in my other post.