Pavlo Kozlov
Pavlo Kozlov

Reputation: 1101

WP5 Module Federation: remoteEntry.js caching

With Webpack 5 module federation if remote entry is modified, you don't need to redeploy main module/application and the newest version of the module will be loaded when it's requested by the browser.

I'm wondering: since the remote URL remains the same (e.g. http://localhost:8081/remoteEntry.js), the browser probably will cache the file and cached version loaded every time you load the main module. On the other hand, if you add cache busting for remote entries, you will not have caching.

Let's assume that there is an application with micro-frontend architecture using Webpack 5 Module federation. There is a remote micro frontend with a config like:

output: {
  publicPath: "http://localhost:8081/",
},
plugins: [
  new ModuleFederationPlugin({
    name: "app1",
    filename: "remoteEntry.js",
    exposes: {
      "./Component1": "./src/Component1",
      "./someModule1": "./src/someModule1",
    },
  })
]

and then main module config:

output: {
  publicPath: "http://localhost:8080/",
},
plugins: [
  new ModuleFederationPlugin({
    name: "mainApp",
    filename: "remoteEntry.js",
    remotes: {
      app1: "app1@http://localhost:8081/remoteEntry.js"
    }
  })
]

Both modules are deployed on production.

Then I change Component1 from app1 and deploy app1 module.

How to deal with remote modules caching?

UPDATE:

It looks like in my case the browser uses heuristic caching (https://www.rfc-editor.org/rfc/rfc7234#section-4.2.2) for remoteEntry.js since the server doesn't provide explicit expiration times.

Thus, when remoteEntry.js updates, the main application still loads this file from the cache that could be cached for weeks. For chunks, it's not a problem since webpack could be configured to include hash in the file names.

For remoteEntry.js I see 2 options:

Do you think it's a way to go?

Upvotes: 28

Views: 27581

Answers (5)

mg-fix
mg-fix

Reputation: 71

You can use ExternalTemplateRemotesPlugin for changing remoteEntry.js url template. I can fix this issue like code below;

new ModuleFederationPlugin({
    name: 'my-app',
    remotes: {
        'my-remote-1': '[email protected]/remoteEntry.js?v=[Date.now()]',
        ...
    },
    ...
}),
new ExternalTemplateRemotesPlugin(),

https://github.com/module-federation/module-federation-examples/issues/566 https://www.npmjs.com/package/external-remotes-plugin

Upvotes: 7

RobotCharlie
RobotCharlie

Reputation: 1278

In my opinion, you should never cache remoteEntry.js since that's where the chunks mapping are. (Mapping here I mean between component and their chunk url). You always want to make sure you are displaying the latest remote chunk. If the mapping changed (usually just means the remote component updated), the browser should fetch the new chunk.

That said, you should cache busting the chunks using

    output: {
        filename: '[name].[contenthash].js',
    },
    plugins: [
        new container.ModuleFederationPlugin({
            name: "RemoteModule",
            library: { type: "var", name: "RemoteModule" },
            filename: "remoteEntry.js",
            exposes: {
                './SuperButton': "./src/components/SuperButton",
                './SuperButton2': "./src/components/SuperButton2",
            },
            shared: {
                react: { singleton: true, eager: true },
                "react-dom": { singleton: true, eager: true },
            }
        }),
        new HtmlWebpackPlugin({
            template: "./public/index.html"
        })
    ],

in your webpack.config.js recommended here https://webpack.js.org/guides/caching/

This way, again, the host will always try to fetch the remoteEntry.js (a fixed url that do not have hash) and let the browser fetch the new chunk url if the hash are changed.

Upvotes: 0

ebrehault
ebrehault

Reputation: 2601

Cache busting implies to re-build (or, at least, post-process) the main app bundle, and that is one of the problem module federation tries to avoid.

So, considering remoteEntry.js is usually a small file, the best solution is to apply a specific cache control for this file so it never gets cached.

With nginx, it can be done that way:

location ~ .*remoteEntry.js$ {
    expires -1;
    add_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
}

Upvotes: 22

Xiaofeng Xie
Xiaofeng Xie

Reputation: 185

I maybe a bit late to the party but here is one of the solution where you append a random string at the end of your remoteEntry at build time . https://github.com/module-federation/module-federation-examples/issues/566#issue-785273439

Upvotes: -1

Ruben Casas
Ruben Casas

Reputation: 179

I don't think this is a concern since webpack adds cache busting to your application's js files during the build process. Take a look at the HTML code that is returned when you load your app and you will notice that the tags that load your bundle are different after each deployment. remoteEntry.js is the module federation way of allowing your app to be loaded from a remote server, not your actual app code.

Upvotes: -4

Related Questions