Skip to content

Main chunk points to the wrong runtime chunk when using Module Federation #19439

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

Open
gtempesta-pixartprinting opened this issue Apr 18, 2025 · 8 comments
Labels

Comments

@gtempesta-pixartprinting
Copy link

gtempesta-pixartprinting commented Apr 18, 2025

Bug report

What is the current behavior?

When running the watch command, at some point the runtime-app chunk referenced in the app chunk is different from the one referenced in the asset-manifest.json.

Since we load this code in a PHP app, we use the manifest to load the chunks dynamically.

Having the manifest reference a different chunk than the one referenced in the app chunk means that the browser loads two different runtime-app chunks, one requested by the manifest, and the other by the app chunk.

Since the second one is the oldest, the end result is that the watch command is not doing its job, because from a certain moment, I'm not able to see the changes I make to the code reflected in the browser.

If the current behavior is a bug, please provide the steps to reproduce.

Here is a GitHub repository with the code needed to reproduce the issue: https://github.com/gtempesta/webpack-issue-repro/.

How to reproduce:

  1. Clone the repository
  2. Run npm install to install the dependencies
  3. Run npm run watch to start watching for changes
  4. Open the asset-manifest.json file in the public folder, and open the app chunk that is referenced in the entry-points field. Now look for the runtime-app chunk in the app chunk and check that it's the same that is referenced in the asset-manifest.json file: it should be the same (with the same hash)
  5. Make a change to the code in app.js and save it
  6. The issue is still not there
  7. Now make a change to the design-area.js file and save it
  8. The issue should be there now: the runtime-app chunk in the asset-manifest.json file and in the app chunk should have different hashes

The issue happens only when using the watch command, and not when using the build command (which is not implemented in this repo).

What is the expected behavior?

I would expect that the runtime-app chunk referenced in the asset-manifest.json file and in the app chunk are always the same, so that I can use the manifest to load the chunks dynamically without having to worry about which one is loaded.

Other relevant information:
webpack version: 5.99.5
Node.js version: 18.17.1
Operating System: macOS Sequoia 15.3.2
Additional tools:

@gtempesta-pixartprinting
Copy link
Author

I've done some attempts and I've figured out something more:

  • I've tried working with previous versions of our packages, but the issue was already there, only I hadn't found out

  • I've tried pointing to remotes that are reachable and not reachable, but the issue is always there, so I think that the content of the remote app doesn't impact the issue

  • I wanted to try working without the runtime file, but the app stops working. With runtime set to false, I have to set experiments.outputModule to false to make the rest of the app work, but with those settings the import of the remote app appears without single quotes:

    module.exports = remote@http://localhost:3001/assets/remoteEntry.js;
  • This happens even if I change the library settings in ModuleFederationPlugin to

    library: { type: 'var', name: 'host' }`
  • Setting runtime to single doesn't solve the issue, because Webpack still outputs two runtime-app files

  • Passing a runtime string to the ModuleFederationPlugin settings, or setting the field to false doesn't solve the issue

@alexander-akait
Copy link
Member

@gtempesta-pixartprinting This is expected, because with module federation you have two runtimes - one internal (for loading packages inside federation), the second is for main application (splitting and dynamic chunks)

@alexander-akait
Copy link
Member

I will look deeply soon at this

@gtempesta-pixartprinting
Copy link
Author

gtempesta-pixartprinting commented Apr 29, 2025

@alexander-akait Thanks for taking the time to look into the issue.

I've done some further investigation and I'd like to share what I've found.

Why I don't think it's expected

I don't think the behavior I'm experiencing is expected, because:

  1. The two generated files have the same name, the only thing that changes is the chunk hash
  2. The content of the files is also very similar, sometimes the only thing that changes is the chunk hash of the referenced file(s)
  3. The first output of the watch command and the output of the build command don't have this issue.

To make it easier to reason about it, I've added a new folder to my repository generated-output-example.

In the folder there are two runtime-app files: runtime-app.d0415bae809a613ce32c.js and runtime-app.2f49b02885c5fb16b004.js. The first one is referenced under entrypoints in the asset-manifest.json file, while the second one is referenced by the app.51cd46ce3502605c797c.js file, which is also referenced in the asset-manifest.json file.

What is happening when running the code in the browser

First thing, I've discovered that this doesn't only happen when changing code in the file that loads the micro frontend, it happens with every change to any file that's dynamically loaded by the main file (app.js). Anyway this is what happens:

  1. After we save a change in a file that's dynamically loaded, the changes are saved in a chunk
  2. The correct chunk is referenced by one of the two runtimes that are generated
  3. The browser loads the two runtimes (one is requested by the manifest and the other by the app.js file)
  4. Only the runtime referenced in the manifest holds the reference to the chunk with the changes
  5. The runtime referenced in app.js references a chunk that doesn’t have the changes
  6. The browser only loads the chunk that’s referenced in the runtime that’s loaded by the app file and not the chunk that's references in the runtime that's listed in the manifest
  7. If I look for the changes in the browser (Open the Developers Tools and Search) the change is never loaded by the browser

How to check this in my repository

  1. Checkout the project
  2. Clear the public folder
  3. Run watch
  4. Add a log to design-area.js (for example console.log(’test’);)
  5. Look for the log inside the public folder and mark down the chunk hash. If there are more than one, mark all the chunk hashes of the files you find
  6. Now open asset-manifest.json and open the runtime-app that’s referenced there
  7. Open that file and look for the chunk hash: it should be there
  8. Now go to the app file referenced in asset-manifest.json
  9. Look for the runtime-app referenced there
  10. Open the runtime-app file and look for the chunk hash(es) of the files with the initial log: it’s not there

Let's do the same check inside my generated-output-example folder.

  1. I've added this log to the design-area.js file: console.log('second test log'); (the log is not committed to the project)
  2. The output code is only present in this chunk: resources_js_chunks_design-area_js.6572e66ecc4cdcf33f12.js, so the chunk hash I should look for is 6572e66ecc4cdcf33f12
  3. If I open asset-manifest, I will find this runtime-app under entrypoints: runtime-app.d0415bae809a613ce32c.js
  4. If I look for the chunk hash 6572e66ecc4cdcf33f12 in this runtime, I can find it
  5. Now I open the app that's referenced in the manifest, which is: app.51cd46ce3502605c797c.js
  6. The app references a different runtime: runtime-app.2f49b02885c5fb16b004.js
  7. If I open the file and look for the chunk hash 6572e66ecc4cdcf33f12, it is not there!

I hope this helps debugging.

@alexander-akait
Copy link
Member

Looks like a bug in https://github.com/gtempesta/webpack-issue-repro/blob/main/webpack/webpack.dev.config.js#L62 or your should use other logic for generations, because in our files we have the valid value and code is working

@gtempesta-pixartprinting
Copy link
Author

gtempesta-pixartprinting commented Apr 29, 2025

Looks like a bug in https://github.com/gtempesta/webpack-issue-repro/blob/main/webpack/webpack.dev.config.js#L62 or your should use other logic for generations, because in our files we have the valid value and code is working

But the chunk referenced in app is the one without the changes, so in my opinion there is an issue even without considering the asset-manifest generation.

So
app.51cd46ce3502605c797c.js
-> runtime-app.2f49b02885c5fb16b004.js
-> resources_js_chunks_design-area_js.2876b31bdeb0b3a137d5.js
-> no log here

The changes are in
resources_js_chunks_design-area_js.6572e66ecc4cdcf33f12.js
which is only referenced by runtime-app.d0415bae809a613ce32c.js which in turn is referenced in the manifest file.

@alexander-akait
Copy link
Member

If we will have wrong values for runtimes we will generate wrong runtime code and it will be broken, but your code works...

@gtempesta-pixartprinting
Copy link
Author

If we will have wrong values for runtimes we will generate wrong runtime code and it will be broken, but your code works...

I wouldn't say that my code works, because the app.js chunk references the wrong runtime, so I'm not able to see the correct changes in the browser when running watch.

I've done a couple more attempts to prove my point.

1. Overwrite the generated app file

With the current setup, I've looked for the linked runtime in the generated app file, let's say the line:

import __webpack_require__ from "./runtime-app.2f49b02885c5fb16b004.js";

And replaced it with the correct runtime, let's say:

import __webpack_require__ from "./runtime-app.d0415bae809a613ce32c.js";

In this case the code works.

2. Remove the Module Federation plugin

I've removed the Module Federation plugin from the Webpack configuration and replaced the import of the remote application with an empty object.

const { default: remoteMountMethod } = {};

Instead of:

const { default: remoteMountMethod } = await import(
  'remote_bucket/remoteMountMethod'
);

Now the app chunk doesn't even reference a runtime, and everything works as expected.

3. Configure a different plugin

I've configured webpack-assets-manifest instead of webpack-manifest-plugin: the two manifests generate files with the same issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants