[PR #41] [MERGED] fix: eliminate react-dom/server.edge dual-import Rollup warning in SSR entry #263

Closed
opened 2026-05-06 12:38:50 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/41
Author: @nianyi778
Created: 2/25/2026
Status: Merged
Merged: 2/27/2026
Merged by: @FredKSchott

Base: mainHead: fix/ssr-entry-dual-import


📝 Commits (3)

  • 23417dd fix: use static import for renderToStaticMarkup to eliminate dual-import warning
  • b1abe1c Remove comment on renderToStaticMarkup import
  • be43fc8 Remove unneccesary test

📊 Changes

2 files changed (+2 additions, -2 deletions)

View changed files

📝 packages/vinext/src/server/app-dev-server.ts (+1 -2)
📝 tests/app-router.test.ts (+1 -0)

📄 Description

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

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/41 **Author:** [@nianyi778](https://github.com/nianyi778) **Created:** 2/25/2026 **Status:** ✅ Merged **Merged:** 2/27/2026 **Merged by:** [@FredKSchott](https://github.com/FredKSchott) **Base:** `main` ← **Head:** `fix/ssr-entry-dual-import` --- ### 📝 Commits (3) - [`23417dd`](https://github.com/cloudflare/vinext/commit/23417dda0495d7b1c6d779e0021996a8906983eb) fix: use static import for renderToStaticMarkup to eliminate dual-import warning - [`b1abe1c`](https://github.com/cloudflare/vinext/commit/b1abe1c17baad48e3e8b8bf95b1f5d6a2a2ae4c8) Remove comment on renderToStaticMarkup import - [`be43fc8`](https://github.com/cloudflare/vinext/commit/be43fc811c0c7934d8be6dd557f231c29fb37799) Remove unneccesary test ### 📊 Changes **2 files changed** (+2 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/app-dev-server.ts` (+1 -2) 📝 `tests/app-router.test.ts` (+1 -0) </details> ### 📄 Description ## 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. ```diff -import { renderToReadableStream } from "react-dom/server.edge"; +import { renderToReadableStream, renderToStaticMarkup } from "react-dom/server.edge"; ``` ```diff - 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 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 12:38:50 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#263
No description provided.