single-spa / single-spa-angular

Helpers for building single-spa applications which use Angular
Apache License 2.0
201 stars 78 forks source link

ScriptExternalLoadError: Loading script failed while using Module Federation #457

Open krish-dev opened 2 years ago

krish-dev commented 2 years ago

Context and Demonstration

I'm trying out all kinds of mixes and matches of Microfrontend. So, I created 4 apps, details are here. name Type JS Framework/Lib Port Repo link
host root-config Vanila JS 3000 https://github.com/krish-dev/poc-ss-root-config
microapp application Angular 4201 https://github.com/krish-dev/poc-ss-microapp
parcel parcel Angular 4202 https://github.com/krish-dev/poc-ss-parcel
parcel-react parcel React 4203 not ready yet

Test Cases

Case No Import Chain SystemJS Module Federation
1 host -> microapp working working
2 host -> parcel working working
3 host -> microapp -> parcel working Not Working
4 host -> microapp -> parcel-react Not tried Not Working

Problem statement

I have simple and pretty much the default webpack configuration and just added Module Federation. Cases 3 & 4 are not working with Module Federation. its throwing following error

ScriptExternalLoadError: Loading script failed.
(missing: http://localhost:4202/remoteEntry.js)
while loading "." from 499
    at 499 (remoteEntry.js":1:1)
    at __webpack_require__ (bootstrap:19:1)
    at initExternal (sharing:27:1)
    at __webpack_require__.I (sharing:38:1)
    at Object.init (container-entry:24:1)
    at initFn (sharing:29:1)
    at async Promise.all (:3000/index 0)

host webpack config

module.exports = (webpackConfigEnv, argv) => {
  const orgName = "pwc";
  const defaultConfig = singleSpaDefaults({
    orgName,
    projectName: "root-config",
    webpackConfigEnv,
    argv,
    disableHtmlGeneration: true,
  });

  const mergedConfig = merge(defaultConfig, {
    // modify the webpack config however you'd like to by adding to this object
    plugins: [
      new HtmlWebpackPlugin({
        inject: false,
        template: "src/index.ejs",
        templateParameters: {
          isLocal: webpackConfigEnv && webpackConfigEnv.isLocal,
          orgName,
        },
      }),
      new ModuleFederationPlugin({
        remotes: {
          'microapp': 'microapp@http://localhost:4201/remoteEntry.js'
        }
      })
    ],
  });
  return mergedConfig;
};

microapp webpack config

module.exports = (config, options) => {
  const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options);

  const mergeConfig = merge(singleSpaWebpackConfig, {
    optimization: {
      runtimeChunk: false,
      splitChunks: false
    },
    plugins: [
      new ModuleFederationPlugin({
        name: 'microapp',
        filename: 'remoteEntry.js',
        exposes: {
          '.': './src/main.single-spa.ts'
        },
        remotes: {
          'parcel': 'parcel@http://localhost:4202/remoteEntry.js'
        }
      })
    ]
  });
  return mergeConfig;
};

parcel webpack config

module.exports = (config, options) => {
  const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options);

  const mergeConfig = merge(singleSpaWebpackConfig, {
    optimization: {
      runtimeChunk: false,
      splitChunks: false
    },
    plugins: [
      new ModuleFederationPlugin({
        name: 'parcel',
        filename: 'remoteEntry.js',
        exposes: {
          '.': './src/main.single-spa.ts'
        }
      })
    ]
  });
  return mergeConfig;
};
filoxo commented 2 years ago

We haven't made any plans to provide support for Module Federation, but if you figure this out please consider documenting and contributing this to the single-spa community! Thanks!

krish-dev commented 2 years ago

We are using Single SPA with Module Federation from last 1.5 year in our app, Similar like use case 3 in react (host-> react->react) working very well which is in production. Only one use case(3) it's not working. If that solved I'm happy to contribute to this community. I'm only 1 step ahead, if someone has extensive Module Federation knowledge can help here.