In an existing web app written in Vue and PHP, we are trying to add a Micro Frontend using Module Federation.
After we configured the app, I found out that the watch
command wasn't working correctly. If I start editing one of the files that import the remote application, at some point the runtime-app
chunk referenced in the app
chunk is different from the one referenced in the asset-manifest.json
.
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 less recent, 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.
I have created a GitHub repository to reproduce the issue: https://github.com/gtempesta/webpack-issue-repro/.
Here is the relevant parts of the Webpack configuration:
// [...]
optimization: {
splitChunks: {
chunks: 'all',
},
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`,
},
},
// [...]
experiments: {
outputModule: true,
},
// [...]
plugins: [
// this part is taken from another project created with Create React App
// the files listed in the entrypoints are then loaded in a Blade partial in Laravel
// using a dedicated helper function
new WebpackManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: '/',
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints['app'].filter(
fileName => !fileName.endsWith('.map')
);
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
new ModuleFederationPlugin({
name: 'host',
library: { type: 'module' },
filename: 'remoteEntry.js',
remotes: {
remote: 'http://localhost:3001/assets/remoteEntry.js',
},
}),
]
And this is how we use the remote:
const designArea = await import('remote/mountMyDesignArea');
const { default: remoteMountMethod, eventBus } = designArea;
// ...
When I build everything for production the issue disappears (production settings not included in the repo, but there are no major differences).
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 (with the same chunk hash), so that I can use the manifest to load the chunks dynamically without having to worry about which one is loaded.
I already had the suspicion that this was caused by the internal cache, but I figured out that by setting cache
to false
in development, the issue was fixed.
// [...]
cache: false,
// [...]
The problem is that for a large application this is not sustainable (now changes take about 30s instead of the usual 3-4s). Does anyone know of a more targeted way of forcing the main chunk to update the cache without clearing all of it?
The issue has been solved in Webpack v5.100.0
, as you can see in their GitHub page: https://github.com/webpack/webpack/releases/tag/v5.100.0.
I've removed the workaround described in my other answer and everything is now working as expected, so the solution is to upgrade to that version or higher.