How to load angularJs V1.8 custom element as web component into Angular V17.1 using @angular-architects/native-federation

81 views Asked by At

I have created one Angular MFA Architecture app which have shell and remote apps which build on top of Angular V17.1. I have to create this below mentioned shell/host app routing to access AngularJS V1.8 with module federation custom element which exposed in "http://localhost:4203/remoteEntry.js" as web component and i can see the js code while hit this remote url. we are using Native federation because of ng v17 use esbuild instead of webpack in angular V17.1.

When we route with angular V17 and native-federation, it was not working and throw below error to access angularjs application http://localhost:4203/remoteEntry.js as mentioned below, but i can see file exposed javascript file while hit this same url in browser. there is no more cors issue and i can find one error while tried to access route through MFA shell app.

enter image description here

enter image description here

This is NG v17 MFA app route to access angularjs remoteEntry.js

{
path: 'angularjs',
loadChildren: () =>
  loadRemoteModule({
    remoteEntry: 'http://localhost:4203/remoteEntry.js',
    remoteName: 'angularjs',
    exposedModule: './web-components',
  }).then((m) => m.helloComponent),
},

app\app.module.mjs // Custom Element in a [email protected]

angular
  .module("app", []).component("helloComponent", {
    controller: function () {
      this.message = "Hi i'm from AngularJS!";
    },
    template: `
          <h1 style="color:#000">
            {{$ctrl.message}}
            <img src="https://angular.io/assets/images/logos/angularjs/AngularJS-Shield.svg" height="30">
          </h1>
        `
  })


export class MfeAngularJs extends HTMLElement {
  connectedCallback() {
    const root = document.createElement("hello-component");
    this.appendChild(root);
    // angular.bootstrap(root, ["app"]);
  }
}

customElements.define("angularjs-element", MfeAngularJs);

//bootstrap the app
angular.element(function () {
  angular.bootstrap(document, ["app"]);
});

webpack.config.js in [email protected]

const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const path = require("path");

module.exports = {
  //create entry point for the application
  entry: "./index.js",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/"
  },
  stats: {
    children: true
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        type: "asset/resource",
        generator: {
          filename: "img/[name][ext]"
        }
      },
      {
        test: /\.(woff(2)?|ttf)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[name].[ext]",
              outputPath: "fonts/",
              publicPath: "/fonts/"
            }
          }
        ]
      },
      {
        test: /\.mjs$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"]
          }
        }
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader",
            options: { minimize: true }
          }
        ]
      }
    ]
  },
  resolve: {
    extensions: [".js", ".mjs", ".json"]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new CopyWebpackPlugin({
      patterns: [
        { from: "app/Content/img", to: "img" },
        { from: "app/fonts", to: "fonts" },
        {
          from: "app/**/*.html",
          to: ({ context, absoluteFilename }) => {
            const relativePath = path.relative(context, absoluteFilename);
            const newPath = path.join(
              path.dirname(relativePath),
              path.basename(absoluteFilename)
            );
            return newPath.startsWith("app") ? newPath.slice(4) : newPath;
          },
          noErrorOnMissing: true,
          globOptions: { ignore: ["**/index.html"] }
        }
      ]
    }),
    new HtmlWebpackPlugin({
      template: "./app/index.html"
    }),
    new ModuleFederationPlugin({
      name: "angularjs",
      library: { type: "var", name: "angularjs" },
      filename: "remoteEntry.js",
      exposes: {
        "./web-components": "./app/app.module.mjs"
      },
      remotes: {
        // For remotes (please adjust)
        angularjs: "http://localhost:4203/remoteEntry.js"
      },
      shared: []
    })
  ],
  devServer: {
    // contentBase: path.join(__dirname, "dist"),
    compress: true,
    historyApiFallback: true, // this is needed for SPA routing
    port: 4203,
    proxy: {
      "/api": {
        target: "https://api-qa.abc.com",
        secure: false,
        changeOrigin: true
      }
    },
    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"
    }
  }
};

index.js // entry point in [email protected]

require("./app/app.module.mjs");
0

There are 0 answers