Skip to content

fix: eliminate react-dom/server.edge dual-import Rollup warning in SSR entry#41

Merged
FredKSchott merged 3 commits intocloudflare:mainfrom
nianyi778:fix/ssr-entry-dual-import
Feb 27, 2026
Merged

fix: eliminate react-dom/server.edge dual-import Rollup warning in SSR entry#41
FredKSchott merged 3 commits intocloudflare:mainfrom
nianyi778:fix/ssr-entry-dual-import

Conversation

@nianyi778
Copy link
Copy Markdown
Contributor

Problem

The generated SSR entry module (generateSsrEntry()) imports react-dom/server.edge in two ways:

  1. Static (top-level): import { renderToReadableStream } from "react-dom/server.edge"
  2. Dynamic (inside handleSsr): const { renderToStaticMarkup } = await import("react-dom/server.edge")

Rollup detects this mixed static+dynamic import pattern and emits a warning on every production build:

"react-dom/server.edge" is dynamically imported by "..." but is also statically imported by "...",
dynamic import will not move module into a separate chunk.

This is cosmetic (the build succeeds), but it's noisy — especially for projects that suppress it via onwarn workarounds in their vite.config.ts.

Fix

Add renderToStaticMarkup to the existing static import at the top of the generated SSR entry, and remove the redundant dynamic import(). The module was already loaded — the dynamic import added no lazy-loading benefit since handleSsr() runs unconditionally during SSR and renderToReadableStream from the same module is always available.

-import { renderToReadableStream } from "react-dom/server.edge";
+import { renderToReadableStream, renderToStaticMarkup } from "react-dom/server.edge";
-    const { renderToStaticMarkup } = await import("react-dom/server.edge");
+    // NOTE: renderToStaticMarkup is imported statically at the top to avoid
+    // Rollup warnings about react-dom/server.edge being both statically and
+    // dynamically imported in the same module.

Verification

Tested with a vinext App Router project (Cloudflare Workers):

  • Before: Rollup emits the dual-import warning on every vinext build
  • After: Warning is eliminated, build output is clean
  • tsc compiles without errors

@southpolesteve
Copy link
Copy Markdown
Collaborator

/bigbonk review

Copy link
Copy Markdown
Contributor

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, correct fix. The SSR entry was already statically importing renderToReadableStream from react-dom/server.edge, so adding renderToStaticMarkup to the same import and dropping the redundant dynamic import() is the right call. The dynamic import provided no lazy-loading benefit since the module was already eagerly loaded.

Verified:

  • No other dynamic imports of react-dom/server.edge remain in the file
  • No other server files (prod-server.ts, worker-entry.ts) use renderToStaticMarkup, so there's no parity concern
  • The remaining await import("react") on line 2257 is fine — react has no static import in the SSR entry, so it won't trigger the same Rollup warning

One minor nit below, but not blocking.

@ask-bonk
Copy link
Copy Markdown
Contributor

ask-bonk bot commented Feb 25, 2026

Review submitted. Here's a summary:

Approved — This is a clean, correct fix. The change hoists renderToStaticMarkup into the existing static import from react-dom/server.edge and removes the redundant dynamic import(), eliminating the Rollup dual-import warning with no behavioral change.

Key verification points:

  • No remaining dynamic imports of react-dom/server.edge in the file
  • No parity concerns — renderToStaticMarkup is only used in the SSR entry generated by app-dev-server.ts, not in prod-server.ts or worker-entry.ts
  • The remaining await import("react") at line 2257 doesn't trigger the same warning since react has no static import in the SSR entry

Left one optional nit suggesting the 3-line explanatory comment could be trimmed to a single line.

github run

@nianyi778 nianyi778 force-pushed the fix/ssr-entry-dual-import branch 2 times, most recently from 1ab00bb to a8406ba Compare February 26, 2026 01:48
…ort warning

The generated SSR entry imported renderToReadableStream statically from
react-dom/server.edge at the top level, but later used a dynamic
import() for renderToStaticMarkup from the same module. Rollup detects
this mixed static+dynamic import pattern and emits a warning for every
build:

  "react-dom/server.edge" is imported as both a static and dynamic
  import in the same module

Fix: add renderToStaticMarkup to the existing static import, removing
the redundant dynamic import(). The module was already loaded — the
dynamic import added no lazy-loading benefit since it runs
unconditionally during SSR.
@nianyi778 nianyi778 force-pushed the fix/ssr-entry-dual-import branch from a8406ba to 23417dd Compare February 26, 2026 12:41
Removed comment about static import of renderToStaticMarkup.
@FredKSchott
Copy link
Copy Markdown
Collaborator

LGTM! Thanks @nianyi778

@FredKSchott FredKSchott enabled auto-merge (squash) February 27, 2026 07:09
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Feb 27, 2026

Open in StackBlitz

npm i https://pkg.pr.new/vinext@41

commit: 5dd31ff

@FredKSchott FredKSchott merged commit 3575784 into cloudflare:main Feb 27, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants