Daniel
Daniel

Reputation: 1601

Webpack module federation error: Cannot read properties of undefined (reading 'call')

I am trying to create the most basic webpack module federation proof of concept example.

Webpack config in the host app:

...
  plugins: [
    new ModuleFederationPlugin({
      name: "hostApp",
      remotes: {
        libApp: `libApp@http://localhost:3000/libApp`,
      },
    }),
  ],
...

Webpack config in the dependency app:

...
  plugins: [
    new ModuleFederationPlugin({
      name: "libApp",
      filename: "libApp.js",
      exposes: {
        "./moduleA": "./src/moduleA",
        "./moduleB": "./src/moduleB",
      }
    })
  ],
...

Here is the reproduction repo

What is wrong with this configuration?

Also, is it possible to set up dependency app to export a single js file with all exposed modules included (as a single webpack module)?

Upvotes: 16

Views: 19483

Answers (4)

Naveen Jamdagani
Naveen Jamdagani

Reputation: 11

I fix this issue by adding bootstrap.js

So in both projects create bootstrap.js file and add code of index.js in it. Then in index.js add import("./bootstrap");

Example =>

bootstrap.js

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const root = document.getElementById('app');
const rootElement = (
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

const rootContainer = createRoot(root);
rootContainer.render(rootElement);

index.js

import("./bootstrap");

Upvotes: 1

Aiwin Raj
Aiwin Raj

Reputation: 21

I too started working on micro-frontend recently. This is how mine is working

Project directory : For shell app

Project directory : For child-app

Based on what you have done. Things seems fine, The problem maybe because of the project directory name. I might be wrong here. But when I was working, only after I named the folder name to Test(Which was also the name of the component I was exposing) it started integrating. It seems ridiculous though.

Webpack config for shell :

plugins: [
    new ModuleFederationPlugin({
      name: "shell",
      filename: "remoteEntry.js",
      remotes: {
        Test : 'Test@http://localhost:8081/remoteEntry.js'
      },
      exposes: {},
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
        "@coreui/react": {
          singleton: true,
          requiredVersion: deps["@coreui/react"],
        },
        "@coreui/coreui": {
          singleton: true,
          requiredVersion: deps["@coreui/coreui"],
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
    new Dotenv()
  ],

For child-app :

plugins: [
    new ModuleFederationPlugin({
      name: "Test",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        './Test' : './src/Test'
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        "react-dom": {
          singleton: true,
          requiredVersion: deps["react-dom"],
        },
        "@coreui/react": {
          singleton: true,
          requiredVersion: deps["@coreui/react"],
        },
        "@coreui/coreui": {
          singleton: true,
          requiredVersion: deps["@coreui/coreui"],
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: "./src/index.html",
    }),
    new Dotenv()
  ],

Upvotes: 0

Rob W
Rob W

Reputation: 61

You can fix this creating a new file "bootstrap.js" in hostApp.

// src/bootstrap.js
console.log('host app test')

import moduleA from 'libApp/moduleA'
import moduleB from 'libApp/moduleB'

const el = document.getElementById('hostAppContainer')

el.innerHTML = 'changedContent: ' + moduleA + moduleB

and then change your index.js to

// src/index.js

import("./bootstrap");

This was caused by trying to do module federation in the initial entry point, which webpack doesn't like you doing.

Upvotes: 6

Tony Brasunas
Tony Brasunas

Reputation: 4582

I see several things.

  1. I think the remotes property goes in the dependent apps as a link back to the host application.
  2. Similarly, I think you'll need a filename inside the host application's configuration for remote access.
  3. It looks odd to me to have your dependent apps directly inside the src directory and not inside src/app.

Upvotes: 0

Related Questions