Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module Federation requests to wrong url to load remotes. #3070

Open
5 tasks done
oytuncoban opened this issue Oct 14, 2024 · 11 comments
Open
5 tasks done

Module Federation requests to wrong url to load remotes. #3070

oytuncoban opened this issue Oct 14, 2024 · 11 comments
Labels
resolved Question where solution was of community use

Comments

@oytuncoban
Copy link

oytuncoban commented Oct 14, 2024

Describe the bug

I have this rsbuild.config.js for my shell app which is migrated from Vite to use MF 2.0

import { pluginModuleFederation } from "@module-federation/rsbuild-plugin";
import { defineConfig, loadEnv } from "@rsbuild/core";
import { pluginReact } from "@rsbuild/plugin-react";
import { pluginSass } from "@rsbuild/plugin-sass";
import { dependencies } from "./package.json";

const { publicVars } = loadEnv({ prefixes: ["VITE_"] });

export default defineConfig({
	server: {
		port: 5173,
	},
	html: {
		template: "./index.html",
	},
	source: {
		define: publicVars,
		entry: {
			index: "./src/main.js",
		},
	},
	plugins: [
		pluginSass(),
		pluginReact(),
		pluginModuleFederation({
			name: "shell",
			remotes: {
				remote: "remote@http://localhost:3000/mf-manifest.json",
			},
			shared: {
				...dependencies,
				react: {
					eager: true,
					singleton: true,
					requiredVersion: dependencies.react,
				},
				"react-dom": {
					eager: true,
					singleton: true,
					requiredVersion: dependencies["react-dom"],
				},
				"react-router-dom": {
					eager: true,
					singleton: true,
					requiredVersion: dependencies["react-router-dom"],
				},
			},
		}),
	],
});

and result of requesting to http://localhost:3000/mf-manifest.json (shell app requests to the correct url and gets the correct response which I do when I request via browser):

{
  "id": "remote",
  "name": "remote",
  "metaData": {
    "name": "remote",
    "type": "app",
    "buildInfo": {
      "buildVersion": "0.0.0",
      "buildName": "remote-ui"
    },
    "remoteEntry": {
      "name": "static/js/remote.js",
      "path": "",
      "type": "global"
    },
    "types": {
      "path": "",
      "name": "",
      "zip": "@mf-types.zip",
      "api": "@mf-types.d.ts"
    },
    "globalName": "remote",
    "pluginVersion": "0.6.9",
    "publicPath": "/",
    "prefetchInterface": false
  },
  "shared": [
    {
      "id": "remote:react-dom",
      "name": "react-dom",
      "version": "18.3.1",
      "singleton": true,
      "requiredVersion": "^18.3.1",
      "assets": {
        "js": {
          "async": [
            "static/js/async/src_App_tsx.js",
            "static/js/async/src_bootstrap_tsx-webpack_sharing_consume_default_react-dom_react-dom-src_App_css.js",
            "static/js/lib-react.js"
          ],
          "sync": [
            "static/js/lib-react.js",
            "static/js/vendors-_module-federation_runtime_rspack_js_data_text_javascript_import___module_federation_-84fe95.js",
            "static/js/index.js",
            "static/js/remote.js"
          ]
        },
        "css": {
          "async": [
            "static/css/async/src_bootstrap_tsx-webpack_sharing_consume_default_react-dom_react-dom-src_App_css.css",
            "static/css/async/__federation_expose_RemoteApp.css"
          ],
          "sync": []
        }
      }
    },
    {
      "id": "remote:react",
      "name": "react",
      "version": "18.3.1",
      "singleton": true,
      "requiredVersion": "^18.3.1",
      "assets": {
        "js": {
          "async": [
            "static/js/async/src_App_tsx.js",
            "static/js/async/src_bootstrap_tsx-webpack_sharing_consume_default_react-dom_react-dom-src_App_css.js",
            "static/js/lib-react.js"
          ],
          "sync": [
            "static/js/lib-react.js",
            "static/js/vendors-_module-federation_runtime_rspack_js_data_text_javascript_import___module_federation_-84fe95.js",
            "static/js/index.js",
            "static/js/remote.js"
          ]
        },
        "css": {
          "async": [
            "static/css/async/src_bootstrap_tsx-webpack_sharing_consume_default_react-dom_react-dom-src_App_css.css",
            "static/css/async/__federation_expose_RemoteApp.css"
          ],
          "sync": []
        }
      }
    }
  ],
  "remotes": [],
  "exposes": [
    {
      "id": "remote:RemoteApp",
      "name": "RemoteApp",
      "assets": {
        "js": {
          "sync": [
            "static/js/lib-react.js",
            "static/js/async/src_App_tsx.js"
          ],
          "async": []
        },
        "css": {
          "sync": [
            "static/css/async/__federation_expose_RemoteApp.css"
          ],
          "async": []
        }
      },
      "path": "./RemoteApp"
    }
  ]
}

We expect shell app to request for "http://localhost:3000/static/js/async/src_App_tsx.js" but instead it requests for "http://localhost:5173/static/js/async/src_App_tsx.js" and this results in the index.html content for shell app which is not a js. And http://localhost:3000/static/js/async/src_App_tsx.js correctly returns the remote component.

This is thrown as error on console:
Uncaught (in promise) Error: [ Federation Runtime ]:
Unable to use the muhaberat's '/static/js/remote.js' URL with remote's globalName to get remoteEntry exports.
Possible reasons could be:

  1. '/static/js/remote.js' is not the correct URL, or the remoteEntry resource or name is incorrect.

  2. remote cannot be used to get remoteEntry exports in the window object.

while loading "./RemoteApp" from webpack/container/reference/remote

Notes:
Remote Component is rendered under a dynamic route handled by react-router-dom:
{BASE_URL}/:id/remote

Reproduction

.

Used Package Manager

pnpm

System Info

System:
    OS: macOS 15.0.1
    CPU: (8) arm64 Apple M3
    Memory: 312.14 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.18.0 - ~/.nvm/versions/node/v20.18.0/bin/node
    Yarn: 4.0.2 - /opt/homebrew/bin/yarn
    npm: 10.8.2 - ~/.nvm/versions/node/v20.18.0/bin/npm
    pnpm: 9.7.0 - /opt/homebrew/bin/pnpm
  Browsers:
    Brave Browser: 108.1.46.144
    Chrome: 129.0.6668.91
    Edge: 129.0.2792.89
    Safari: 18.0.1

Validations

@oytuncoban
Copy link
Author

oytuncoban commented Oct 14, 2024

UPDATE

In order to make it work, I had to re-configure publicPath for rspack:

// rsbuild.config.js (shell)
        ...
	tools: {
		rspack: {
			output: {
				uniqueName: "shell",
				publicPath: "/",
			},
		},
	},
	...
// rsbuild.config.js (remote)
        ...
	tools: {
		rspack: {
			output: {
				uniqueName: "remote",
				publicPath: "auto",
			},
		},
	},
	...

@ScriptedAlchemy
Copy link
Member

yep, setting public path resolves it.

@ScriptedAlchemy
Copy link
Member

@chenjiahan we should make "auto" the default when MF is detected.

@ScriptedAlchemy ScriptedAlchemy added the resolved Question where solution was of community use label Oct 14, 2024
@chenjiahan
Copy link
Contributor

The @module-federation/rsbuild-plugin already set auto by default, see:

https://github.com/module-federation/core/blob/main/packages/rsbuild-plugin/src/cli/index.ts#L151-L156

@nyqykk can you help to check this issue?

@oytuncoban
Copy link
Author

The @module-federation/rsbuild-plugin already set auto by default, see:

https://github.com/module-federation/core/blob/main/packages/rsbuild-plugin/src/cli/index.ts#L151-L156

@nyqykk can you help to check this issue?

This still doesn't explain why we have to set it to "/" on shell apps. Can you help me to understand that behaviour?

@ScriptedAlchemy
Copy link
Member

If you provide a repo we can take a look

@nyqykk
Copy link
Contributor

nyqykk commented Oct 15, 2024

The @module-federation/rsbuild-plugin already set auto by default, see: @module-federation/rsbuild-plugin 默认情况下已设置为 auto,请参阅:
https://github.com/module-federation/core/blob/main/packages/rsbuild-plugin/src/cli/index.ts#L151-L156
@nyqykk can you help to check this issue?您能帮忙检查这个问题吗?

This still doesn't explain why we have to set it to "/" on shell apps. Can you help me to understand that behaviour?这仍然无法解释为什么我们必须在 shell 应用程序上将其设置为 “/”。您能帮我理解这种行为吗?

can you provide a repo?

@oytuncoban
Copy link
Author

The @module-federation/rsbuild-plugin already set auto by default, see: @module-federation/rsbuild-plugin 默认情况下已设置为 auto,请参阅:
https://github.com/module-federation/core/blob/main/packages/rsbuild-plugin/src/cli/index.ts#L151-L156
@nyqykk can you help to check this issue?您能帮忙检查这个问题吗?

This still doesn't explain why we have to set it to "/" on shell apps. Can you help me to understand that behaviour?这仍然无法解释为什么我们必须在 shell 应用程序上将其设置为 “/”。您能帮我理解这种行为吗?

can you provide a repo?

My apologies folks,
While creating a reproduction repo, I've noticed that setting publicPath to "/" has nothing to do with the issue.

But remotes still should explicitly set publicPath to "auto" in order to work. Since setting it to "auto" also for shell doesn't cause any issues, plugin can ensure publicPath is set to "auto" no matter what. I think this is not the case rn.

@chenjiahan
Copy link
Contributor

We are improving the default value of publicPath / assetPrefix for Rsbuild MF apps, see web-infra-dev/rsbuild#3757

@PezCoder
Copy link

@ScriptedAlchemy Hey, is there a way to configure the publicPath to be anything other than 'auto'. It seems like a hard restriction that module federation files from remote can only be exposed from the root.

Codebase in my company for example has a base framework that controls entry & output fields & hence the output ends up becoming:

"output": {
  "filename": "[name]/page.js",
  "publicPath": "/webpack/"
},

What this means is, if I have a remoteEntry & let's say an exposes like so:

      new ModuleFederationPlugin({
        name: "devportal",
        filename: "remoteEntry.js",
        remotes: {},
        exposes: {
          './Simple': './src/components/Simple.jsx',
        },

This generates files like this:

  • https://localhost:8080/webpack/remoteEntry.js - the file under this content has moduleMap for ./Simple which maps to __webpack_require__.e("src_components_Simple_jsx") which is incorrect & means that module federation assumes dependencies to be hosted at the root & doesn't respect the publicPath provided (in my case /webpack/
  • https://localhost:8080/webpack/src_components_Simple_jsx/page.js - This is how other dependency are generated because of output
Screenshot 2024-11-15 at 5 51 08 PM

I'm looking to see if there is a possibility to configure:

  • Either the root of "all" microfrontends dependencies - such that remoteEntry file content also prefixes with such root before fetching dependencies
  • or have a way to temporarily define / override the paths injected within remoteEntry

What I tried?

I tried the latter - by editing: node_modules/webpack/lib/container/ContainerEntryModule.js
On line 203 just before the following code executes:

// Added this hardcode so that remoteEntry knows where to load dependent assets from
// str variable contains the stringified value of the 
str = str.replace('src_components_Simple_jsx', 'webpack/src_components_Simple_jsx/page');

// this is the code which creates the module map
			getters.push(
				`${JSON.stringify(modules[0].name)}: ${runtimeTemplate.basicFunction(
					"",
					str
				)}`
			);
Screenshot 2024-11-15 at 5 52 27 PM

Although this worked in terms of code being injected has the right path, but unfortunately it didn't work when integrating it within the host.
In network request, it rather now started fetching this dependent assets from host's domain instead of remote's domain.

Looking for a cleaner way to achieve this, as it's sort of a blocker for us to adopt microfrontends via module federation. Appreciate any help / workaround.

@ScriptedAlchemy
Copy link
Member

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
resolved Question where solution was of community use
Projects
None yet
Development

No branches or pull requests

5 participants