ReactJS and Webpack Module Federation Application contains urls with undefined when deployed to cloudfront

Viewed 1827

I have a micro-frontends app that consists of a container application with several remote applications. It is using ReactJS with Webpack 5 module federation and works fine on my local environment. However, when I deploy it to AWS CloudFront it doesn't work as expected.

It seems that the container app loads on the correct path but 'undefined' is added to the url of the remoteEntry.js file of the remotes.

Please see screenshot below:

CloudFront Error

The container projects webpack production config is as follows:

const prodConfig = {
  mode: "production",
  output: {
    filename: "[name].[contenthash].js",
    publicPath: "/container/latest/",
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "container",
      remotes: {
        auth: `auth@${domain}/auth/latest/remoteEntry.js`,
        marketing: `marketing@${domain}/marketing/latest/remoteEntry.js`,
        dashboard: `dashboard@${domain}/dashboard/latest/remoteEntry.js`,
      },
      shared: packageJson.dependencies,
    }),
  ],
};

The remote projects webpack production config is as follows:

const prodConfig = {
  mode: "production",
  output: {
    filename: "[name].[contenthash].js",
    publicPath: "/marketing/latest/",
  },
  plugins: [
    new ModuleFederationPlugin({
      name: "marketing",
      filename: "remoteEntry.js",
      exposes: {
        "./MarketingApp": "./src/bootstrap",
      },
      shared: packageJson.dependencies,
    }),
  ],
};

The container projects App.js is as follows:

import React, { lazy, Suspense, useState, useEffect } from "react";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import {
  StylesProvider,
  createGenerateClassName,
} from "@material-ui/core/styles";
import { createBrowserHistory } from "history";

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",
});

const history = createBrowserHistory();

export default () => {
  const [isSignedIn, setIsSignedIn] = useState(false);

  useEffect(() => {
    if (isSignedIn) {
      history.push("/dashboard");
    }
  }, [isSignedIn]);

  return (
    <Router history={history}>
      <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">
                {!isSignedIn && <Redirect to="/" />}
                <DashboardLazy />
              </Route>
              <Route path="/" component={MarketingLazy} />
            </Switch>
          </Suspense>
        </div>
      </StylesProvider>
    </Router>
  );
};

I am struggling to figure out where the error is. I am not sure if its an error with:

  • React
  • React Router
  • Webpack Module Federation
  • AWS CloudFront

Any help would be appreciated

2 Answers

If you look carefully at your browser logs.

There is a undefined/marketing/latest/remoteEntry.js in your url loading the module federated remote urls.

It is likely you need to setup your domain variable to be the cloudfront endpoint.

A little late,

Problem:

The problem is maybe you are just deploying the marketing app alone and the container app is not aware of marketing app changes until it is redeployed.

Solution;

All you need to do is just make changes to both Marketing and container app and commit to git to trigger a workflow for both apps.

hope this may help someone with same issue.

Related