Trouble with Bidirectional Module Federation Between Angular and React Applications

13 Views Asked by At

I am experiencing issues setting up bidirectional module federation between my Angular and React applications. My React app is unable to load an exposed service from my running Angular app, and I'm receiving a rror fetching token: ScriptExternalLoadError: Loading script failed. (missing: http://localhost:4200/remoteEntry.js) indicating that remoteEntry.js is missing, despite it being accessible in the browser.

The angular webpack configuration is this:

const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const mf = require("@angular-architects/module-federation/webpack");
const path = require("path");
const share = mf.share;
const deps = require('./package.json').dependencies;


const sharedMappings = new mf.SharedMappings();
sharedMappings.register(
  path.join(__dirname, 'tsconfig.json'),
  [/* mapped paths to share */]);

module.exports = {
  output: {
    uniqueName: "angular",
    publicPath: "http://localhost:4200/",
    scriptType: 'text/javascript',
  },
  optimization: {
    runtimeChunk: false
  },
  resolve: {
    alias: {
      ...sharedMappings.getAliases(),
    }
  },
  experiments: {
    outputModule: true
  },
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
    },
    hot: true,
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'angular',
      library: {type: "module"},
      filename: 'remoteEntry.js',

      remotes: {
        "host": "http://localhost:2836/remoteEntry.js",
        "react_remote": "http://localhost:3000/remoteEntry.js",

      },
      exposes: {
        './AuthService': './src/app/react-wrapper/auth-service.service.ts',
      },
      shared: share({
        "@angular/core": {singleton: true, strictVersion: true, requiredVersion: 'auto'},
        "@angular/common": {singleton: true, strictVersion: true, requiredVersion: 'auto'},
        "@angular/common/http": {singleton: true, strictVersion: true, requiredVersion: 'auto'},
        "@angular/router": {singleton: true, strictVersion: true, requiredVersion: 'auto'},
        "angular-oauth2-oidc": {singleton: true, strictVersion: true, requiredVersion: 'auto'},
        react: {
          singleton: true,
          eager: false,
          requiredVersion: deps.react, // Removed eager: true
        },
        'react-dom': { // Use 'react-dom' instead of 'react-dom/client'
          singleton: true,
          eager: false,
          requiredVersion: deps['react-dom'], // Removed eager: true
        },
        ...sharedMappings.getDescriptors()
      })

    }),
    sharedMappings.getPlugin()
  ],
};

The react webpack configuration is this:

// React Microfrontend Webpack Configuration
const {ModuleFederationPlugin} = require("webpack").container;
const packageJson = require("./package.json");

module.exports = {
    resolve: {
        extensions: ['.js', '.tsx', '.ts'],
    },
    output: {
        publicPath: 'auto',
    },
    module: {
        rules: [
            {
                test: /\.(js|ts)x?$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                options: {
                    presets: ['@babel/preset-react', '@babel/preset-typescript'],
                },
            },
            {
                test: /\.png$/,
                use: {
                    loader: 'url-loader',
                    options: {limit: 8192},
                },
            },
            {
                test: /\.css$/i,
                use: ['style-loader',
                    'css-loader'],
            },
        ],
    },
    optimization: {
        splitChunks: false,
        minimize: false

    },
    webpack: {
        configure: (webpackConfig, {env, paths}) => {

            webpackConfig.plugins = [
                ...webpackConfig.plugins,
                new ModuleFederationPlugin({
                    name: 'react_remote',
                    filename: 'remoteEntry.js',
                    exposes: {
                        './Button': './src/Button',
                    },
                    remotes: {
                        angular: 'angular@http://localhost:4200/remoteEntry.js',
                    },
                    shared: {
                        ...packageJson.dependencies,
                        react: {singleton: true, eager: false, requiredVersion: packageJson.dependencies.react},
                        "react-dom": {
                            singleton: true,
                            eager: false,
                            requiredVersion: packageJson.dependencies["react-dom"]
                        },
                    },
                }),
            ];

            webpackConfig.output.publicPath = "auto";
            return webpackConfig;
        },
    },
    devServer: {
        port: 3000,
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
};

I try to load the service like this:

// React application's useToken hook
import React, { useState, useEffect } from 'react';

// Define the expected shape of the response
interface TokenResponse {
    access_token: string; // Adjust according to the actual key in the response JSON
}

export function useToken() {
    const [token, setToken] = useState('');

    useEffect(() => {
        async function fetchToken() {
            try {
                const authServiceModule = await import('angular/AuthService');
                // const authService = new authServiceModule.AuthService(); 

            } catch (error) {
                console.error('Error fetching token:', error);
            }
        }

        fetchToken();
    }, []);

    return token;
}
0

There are 0 best solutions below