'Use the same port in Module Federated React Application

I've 3 applications which are embedded on the same spring service (built by yarn maven plugin) with the following configuration:

App Shell

module.exports = {
  mode: 'production',
  entry: './src/index',
  cache: false,
  devtool: false,
  optimization: {
    minimize: true,
  },
  output: {
    publicPath: 'http://localhost:8000/gui/shell/',
    clean: true,
    pathinfo: false,
    path: path.resolve(__dirname, 'build/'),
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.css$/i,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              modules: true,
            },
          },
        ],
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.svg$/,
        use: [
          {
            loader: 'svg-url-loader',
            options: {
              limit: 10000,
            },
          },
        ],
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      },
      {
        test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[ext]',
              outputPath: 'fonts/',
            },
          },
        ],
      },
    ],
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'frontend_shell',
      filename: 'remoteEntry.js',
      remotes: {
        store: 'store@http://localhost:8000/store/remoteEntry.js',
        appOneRemote: 'appOneRemote@http://localhost:8000/appOneRemote/remoteEntry.js',
      },
      exposes: {
        './translate': './src/utility/i18n/translate.js',
        './useAllUserInfo': './src/hooks/useAllUserInfo.js',
        './useDarkMode': './src/hooks/useDarkMode.js',
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
          eager: true,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom'],
          eager: true,
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: './public/index.html',
      inject: 'body',
      hash: true,
      minify: true,
    }),
    new ESLintPlugin({
      extensions: ['js', 'jsx'],
    }),
  ],
};

App remote 1

module.exports = {
  mode: 'production',
  entry: './src/index',
  cache: false,
  devtool: false,
  optimization: {
    minimize: true,
  },
  output: {
    publicPath: 'http://localhost:8000/appOneRemote/',
    clean: true,
    pathinfo: false,
    path: path.resolve(__dirname, 'build/'),
  },
  resolve: {
    extensions: ['.js', '.mjs', '.jsx', '.css'],
    alias: {
      events: 'events',
    },
  },
  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.css$/i,
        use: [
          'style-loader', 'css-loader',
        ],
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
    ],
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'appOneRemote',
      filename: 'remoteEntry.js',
      remotes: {
        store: 'store@http://localhost:8000/store/remoteEntry.js',
        shell: 'frontend_shell@http://localhost:8000/gui/shell/remoteEntry.js',
      },
      exposes: {
        './ManageUser': './src/pages/ManageUser/ManageUser.jsx',
      },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
          eager: true,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom'],
          eager: true,
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: './public/index.html',
    }),
    new ESLintPlugin({
      extensions: ['js', 'jsx'],
    }),
  ],
};

App remote 2

module.exports = {
  mode: 'production',
  entry: './src/index',
  cache: false,
  devtool: false,
  optimization: {
    minimize: true,
  },
  output: {
    publicPath: 'http://localhost:8000/store/',
    clean: true,
    pathinfo: false,
    path: path.resolve(__dirname, 'build/'),
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
  },
  module: {
    rules: [
      {
        test: /\.m?js/,
        type: 'javascript/auto',
        resolve: {
          fullySpecified: false,
        },
      },
      {
        test: /\.(css|s[ac]ss)$/i,
        use: ['style-loader', 'css-loader', 'postcss-loader'],
      },
      {
        test: /\.(ts|tsx|js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
    ],
  },

  plugins: [
    new ModuleFederationPlugin({
      name: 'store',
      filename: 'remoteEntry.js',
      remotes: {},
      exposes: { './store': './src/store' },
      shared: {
        ...deps,
        react: {
          singleton: true,
          requiredVersion: deps.react,
        },
        'react-dom': {
          singleton: true,
          requiredVersion: deps['react-dom'],
        },
        'react-redux': {
          singleton: true,
        },
      },
    }),
    new HtmlWebPackPlugin({
      template: './public/index.html',
    }),
    new ESLintPlugin({
      extensions: ['js', 'jsx'],
    }),
  ],
};

This is exactly what I get in the console: Warning:

Initialization of sharing external failed: ScriptExternalLoadError: Loading script failed.
(error: http://localhost:8000/appOneRemote/remoteEntry.js)

Warning:

Initialization of sharing external failed: ScriptExternalLoadError: Loading script failed.
(error: http://localhost:8000/store/remoteEntry.js)

Error:

Uncaught (in promise) ScriptExternalLoadError: Loading script failed.
(error: http://localhost:8000/store/remoteEntry.js)
while loading "./store" from 83878
at Object.83878 (main.js?1154643655f4125db28e:2:130241)

Also I can retrieve my shell remote entry here: http://localhost:8000/gui/shell/remoteEntry.js, but I got a 404 in the following: http://localhost:8000/store/remoteEntry.js http://localhost:8000/appOneRemote/remoteEntry.js

Any ideas?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source