Skip to content

NxModuleFederationDevServerPlugin serves static remotes with a 1h cache, causing ChunkLoadError after a remote is rebuilt #36278

Description

@ilanwei1

Current Behavior

NxModuleFederationDevServerPlugin serves static remotes through a raw http-server fork with no cache flag:

const httpServerProcess = fork(
pathToHttpServer,
[
commonOutputDirectory!,
`-p=${staticRemotesPort}`,
`-a=localhost`,
`--cors`,
],

http-server's default Cache-Control is max-age=3600 (1 hour). With the exact binary and args the plugin forks (http-server@14.1.1, -a=localhost --cors, no -c):

$ curl -sI http://localhost:<staticRemotesPort>/index.html | grep -i -E '^HTTP|cache-control'
HTTP/1.1 200 OK
cache-control: max-age=3600

So every static remote asset — including remoteEntry.js — is cached by the browser for an hour. When a static remote is rebuilt (each nx serve of the host rebuilds them), a normal reload keeps using the cached remoteEntry.js, which points at chunk hashes that no longer exist on the file server → ChunkLoadError for that remote until the cache expires or is cleared manually.

Expected Behavior

Dev-time static remotes are served uncached. This is exactly what #27005 fixed for the executor-based dev-server, and the executor path still has it (cacheSeconds: -1):

The flag was never ported when the plugin path reimplemented the file server as a direct http-server fork.

Steps to Reproduce

  1. React Module Federation workspace (host + remotes) using NxModuleFederationDevServerPlugin; nx serve <host> so the remotes are served statically.
  2. curl -sI http://localhost:<staticRemotesPort>/<remote>/remoteEntry.js | grep -i cache-controlmax-age=3600.
  3. Change a static remote, re-run the serve, reload the app (devtools closed) → the browser reuses the cached remoteEntry.jsChunkLoadError on chunks whose hashes changed.

We hit this in a 17-remote production monorepo. We have been running the one-line fix — -c-1 on the forked http-server, matching #27005 — via a pnpm patch since Nx 23. PR follows.

Context: the plugin path is the v24 migration target

The executor-based module-federation-dev-server — the path that still has the cacheSeconds: -1 fix — is deprecated with removal in Nx v24, and now warns at runtime directing users to the @nx/react:consumer / NxModuleFederationDevServerPlugin model:

"x-deprecated": "The `@nx/rspack:module-federation-dev-server` executor is deprecated. Dynamic federation in `@nx/react:consumer` removes the need for host-orchestrated remote serving. Removed in Nx v24.",

We migrated our workspace to the plugin model following that guidance, which is how we hit this. Once the executors are removed in v24 the plugin path is the only dev-serving path, so this is a parity gap on the migration target rather than an edge case — everyone following the deprecation warning inherits it.

Nx Report

Node   : 24.17.0
pnpm   : 11.8.0
nx (and all @nx/* plugins) : 23.0.0
@nx/module-federation      : 23.0.0
typescript                 : 5.9.3

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions