Skip to content

fix(modernjs-v3): compute Content-Length in bytes for served bundles - #4982

Open
scplay wants to merge 1 commit into
module-federation:mainfrom
scplay:fix/modernjs-v3-content-length-bytes
Open

fix(modernjs-v3): compute Content-Length in bytes for served bundles#4982
scplay wants to merge 1 commit into
module-federation:mainfrom
scplay:fix/modernjs-v3-content-length-bytes

Conversation

@scplay

@scplay scplay commented Aug 11, 2026

Copy link
Copy Markdown

fix(modernjs-v3): compute Content-Length in bytes for served bundles

Summary

createStaticMiddleware serves node-side federated chunks from /bundles. The file is read as a UTF-8 string by fileCache.getFile, but Content-Length is set from content.length, which is the number of characters:

// packages/modernjs-v3/src/server/staticMiddleware.ts
c.header('Content-Length', String(fileResult.content.length));

For any chunk containing non-ASCII characters (comments, string literals), the byte length exceeds the character length, so the response is truncated by exactly that difference. An SSR consumer then evaluates an incomplete chunk and throws.

Fixed by using Buffer.byteLength(fileResult.content).

Impact

Only affects production (modern serve) with SSR enabled — the middleware returns early when NODE_ENV === 'development', and it is only registered when server.ssr is set. Chunks that are pure ASCII are unaffected because byte length equals character length, which is why this went unnoticed.

Deployments that serve remote assets via CDN or nginx do not hit this middleware at all.

Reproduction

A Modern.js producer with SSR enabled that exposes a module whose chunk contains non-ASCII characters, consumed by a Modern.js SSR host.

SyntaxError: Unexpected token '}'
Federated chunk execution failed.
chunk: __federation_expose_marketing_dataops-<hash>.js
source: remote-url
location: http://127.0.0.1:3052/bundles/__federation_expose_marketing_dataops-<hash>.js

The chunk on disk is valid; the served copy is not:

# valid
node --check dist/bundles/__federation_expose_marketing_data<hash>.js

# truncated
curl -s http://127.0.0.1:3052/bundles/__federation_expose_marketing_data<hash>.js > /tmp/c.js
node --check /tmp/c.js
# SyntaxError: Unexpected end of input

Byte/character mismatch matches the truncation exactly:

file on disk : 1207 bytes / 1103 characters
response     : content-length: 1103  ->  104 bytes short

A minimal probe shows the same off-by-multibyte for any file, not just federated chunks — a 46-byte file with non-ASCII content is served as 38 bytes.

Changes

  • packages/modernjs-v3/src/server/staticMiddleware.ts — use Buffer.byteLength for Content-Length
  • packages/modernjs-v3/src/server/staticMiddleware.spec.ts — cover non-ASCII and ASCII content

Notes

fileCache.ts has a related fallback, size: stat.size || content.length, which mixes the same two units. It is only reached when stat.size is falsy, so it is left alone here to keep this PR to a single issue. Happy to fix it separately if you'd prefer.

Test plan

pnpm --filter @module-federation/modern-js-v3 run test

The added non-ASCII test fails before the fix and passes after. Verified end to end against a Modern.js SSR host consuming a producer whose chunks contain non-ASCII characters: the served chunk now passes node --check and the remote module renders on the server.

@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: ef59c66

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 48 packages
Name Type
@module-federation/modern-js-v3 Patch
shared-tree-shaking-with-server-host Patch
shared-tree-shaking-with-server-provider Patch
@module-federation/runtime Patch
@module-federation/enhanced Patch
@module-federation/rspack Patch
@module-federation/webpack-bundler-runtime Patch
@module-federation/sdk Patch
@module-federation/runtime-tools Patch
@module-federation/managers Patch
@module-federation/manifest Patch
@module-federation/dts-plugin Patch
@module-federation/third-party-dts-extractor Patch
@module-federation/devtools Patch
@module-federation/bridge-react Patch
@module-federation/bridge-vue3 Patch
@module-federation/bridge-shared Patch
@module-federation/bridge-react-webpack-plugin Patch
@module-federation/modern-js Patch
@module-federation/retry-plugin Patch
@module-federation/rsbuild-plugin Patch
@module-federation/rstest Patch
@module-federation/error-codes Patch
@module-federation/inject-external-runtime-core-plugin Patch
@module-federation/runtime-core Patch
create-module-federation Patch
@module-federation/cli Patch
@module-federation/rspress-plugin Patch
@module-federation/treeshake-server Patch
@module-federation/treeshake-frontend Patch
@module-federation/metro Patch
@module-federation/metro-plugin-rnef Patch
@module-federation/metro-plugin-rock Patch
@module-federation/metro-plugin-rnc-cli Patch
@module-federation/esbuild Patch
@module-federation/nextjs-mf Patch
@module-federation/node Patch
@module-federation/observability-plugin Patch
@module-federation/playground Patch
website-new Patch
@module-federation/storybook-addon Patch
shared-tree-shaking-no-server-host Patch
shared-tree-shaking-no-server-provider Patch
@module-federation/utilities Patch
remote5 Patch
remote6 Patch
node-dynamic-remote-new-version Patch
node-dynamic-remote Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@tonoizer

Copy link
Copy Markdown
Contributor

Overlap with #4983

#4983 includes the same Content-Length byte-length fix for @module-federation/modern-js-v3 /bundles serving, and additionally:

  • the same Content-Length fix for @module-federation/modern-js
  • path-traversal confinement for /bundles static middleware
  • path-traversal confinement for the SSR JSON middleware under dist/
  • file-cache size accounting in UTF-8 bytes

Once #4983 is merged, this PR can be closed as superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants