0

I am trying to implement Micro Frontends using Angular 13 and React, using Webpack 5 and the Module Federation plugin. I have a remote Angular application that I am trying to import into my host React application. I have followed the documentation and guides, but I am getting an error ScriptExternalLoadError: Loading script failed. when trying to load the remote Angular application.

Here are the details of my implementation:

  • I have two separate applications, one Angular and one React.
  • In my Angular application, I have added the @module-federation/client package to my dependencies and configured the webpack.config.js file to expose the required modules.

webpack-config Angular Application

const path = require('path');
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  entry: './src/bootstrap.ts',
  optimization: {
    splitChunks: false,
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js',
    chunkFilename: '[id].chunk.js',
    scriptType: 'text/javascript'
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        use: [
          {
            loader: 'ts-loader',
            options: {
              transpileOnly: true,
            },
          },
        ],
      },
      {
        test: /\.html$/,
        loader: 'html-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  devServer: {
    static: {
      directory: path.join(__dirname, 'dist'),
    },
    compress: true,
    port: 8082,
    hot: true,
    historyApiFallback: true,
  },
  plugins : [
    new ModuleFederationPlugin({
      name : 'cubs', 
      library: { type: 'var', name: 'profile' },
      filename : 'remoteEntry.js',
      exposes : {
        './angular' : './src/bootstrap'
      }
    }),
  ]
};

package-json

{
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular-builders/custom-webpack": "^13.1.0",
    "@angular/animations": "~13.3.0",
    "@angular/common": "~13.3.0",
    "@angular/compiler": "~13.3.0",
    "@angular/core": "~13.3.0",
    "@angular/forms": "~13.3.0",
    "@angular/platform-browser": "~13.3.0",
    "@angular/platform-browser-dynamic": "~13.3.0",
    "@angular/router": "~13.3.0",
    "clean-webpack-plugin": "^4.0.0",
    "html-webpack-plugin": "^5.5.1",
    "i": "^0.3.7",
    "npm": "^9.6.6",
    "rxjs": "~7.5.0",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~13.3.11",
    "@angular/cli": "~13.3.11",
    "@angular/compiler-cli": "~13.3.0",
    "@types/jasmine": "~3.10.0",
    "@types/node": "^12.11.1",
    "jasmine-core": "~4.0.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.1.0",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "~1.7.0",
    "style-loader": "^3.3.2",
    "ts-loader": "^9.4.2",
    "typescript": "~4.6.2"
  }
}

angular.json

{
    "builder": "@angular-builders/custom-webpack:browser",
    "options": {
    "customWebpackConfig": {
      "path": "./custom-webpack.config.js"
},

bootstrap.ts

import 'zone.js';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { AppComponent } from './app/app.component';

export function mount(container: HTMLElement, props: any) {
  const appComponent = new AppComponent();
  const element = appComponent.getElement();
  container.appendChild(element);
  console.log("Component mounted")
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err));

In my React host Application webpack-dev.config

const { merge } = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const commonConfig = require('./webpack.common')
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')

const devConfig = {
    mode : 'development', 
    devServer : {
        port : 8080,
        historyApiFallback : {
            index : 'index.html'
        }
    },
    plugins : [
        new ModuleFederationPlugin({
            name : 'container', 
            remotes : {
                reactapp : 'reactapp@http://localhost:8081/remoteEntry.js',
                angular : "angular@http://localhost:8082/remoteEntry.js"
            }
        }), 
        new HtmlWebpackPlugin({
            template : '/public/index.html'
        })
    ]
}

module.exports = merge(commonConfig, devConfig)

React Component thats imported in the App.js

import React, { useRef, useEffect } from 'react';
import 'angular/angular'

const AngularAppWrapper = () => {

  const appRef = useRef(null);
    console.log("Making an attempt")
    console.log(mount);
  useEffect(() => {
    if (appRef.current) {
      mount(appRef.current, {});
    }
  }, []);

  return <div ref={appRef} />;
};

export default AngularAppWrapper;

Host react Bootstrap

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);


reportWebVitals();
  • I have verified that the remoteEntry.js file is being served from the Angular application at the correct URL (http://localhost:8082/remoteEntry.js).
  • I have tried several solutions suggested online, such as clearing the cache, using incognito mode, checking the network logs, and checking the path of the imported modules.
  • Despite all this, I am still getting the error. I am not sure what else to try. Can someone please help me diagnose and fix this issue?

2 Answers 2

1

I encountered a similar issue with ScriptExternalLoadError when using Module Federation with Webpack. The solution that worked for me was to set optimization.minimize to false in the Webpack configuration. This essentially disables the code minimization step during the build process.

Here's how to do it:

// webpack.config.js

module.exports = {
  // ...other configurations
  optimization: {
    minimize: false
  }
};

By doing this, you might notice that the bundle size will increase because the code isn't being minified. However, it should resolve the ScriptExternalLoadError you're experiencing. Keep in mind that you should ideally only do this for debugging, and find a more permanent solution for production.

Sign up to request clarification or add additional context in comments.

Comments

0

The following code fixed the script error for me:

optimization: {
  runtimeChunk: false
},

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.