Skip to content

fix(runtime): start each SSR stream pipeline only once - #8872

Open
2heal1 wants to merge 1 commit into
feat/mf-ssr-clear-cachefrom
fix/ssr-stream-ready-once
Open

2heal1 wants to merge 1 commit into
feat/mf-ssr-clear-cachefrom
fix/ssr-stream-ready-once

Conversation

@2heal1

@2heal1 2heal1 commented Sep 15, 2026

Copy link
Copy Markdown
Member

Summary

A real MF SSR playground exposed aborted responses after a dynamic lazy remote had resolved: the ready callback entered the response setup twice, and React rejected the second pipe() with React currently only supports piping to one writable stream. The resulting premature close made raw SSR requests fail even though browser hydration could display the remote.

Guard Node response-pipeline startup before scheduling template work. Re-entered ready callbacks reuse the already-started pipeline; cancellation and producer tracking remain in place. Add a deterministic regression using real React streams with a re-entered all-ready callback, and a patch changeset.

Validation

  • pnpm --filter @modern-js/runtime exec rstest tests/ssr/streamLifecycle.test.tsx: all 18 tests pass.
  • Without the guard, the new targeted regression fails with an aborted stream; the source was restored afterward.
  • pnpm --filter @modern-js/runtime run build: passed.
  • pnpm exec biome check on both changed TypeScript files and git diff --check: passed.
  • The same fix as a pnpm patch passes the complete MF Modern SSR E2E entry, including the real dynamic SSR/hydration scenario, scoped/full concurrent updates, overflow/timeouts and memory cycles.

Unrelated runtime/router suites and the full framework build were not repeated; this change is confined to Node stream startup. Targets the SSR integration branch as requested.

@changeset-bot

changeset-bot Bot commented Sep 15, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d02ca90

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

This PR includes changesets to release 119 packages
Name Type
@modern-js/runtime Patch
@modern-js/plugin-bff Patch
@modern-js/plugin-styled-components Patch
@modern-js/plugin-i18n Patch
@integration-test/alias-set Patch
app-document Patch
async-entry-test Patch
tmp Patch
bff-api-app Patch
bff-client-app Patch
bff-indep-client-app Patch
bff-hono Patch
integration-clean-dist-path Patch
integration-compatibility Patch
integration-custom-dist-path Patch
custom-file-system-entry Patch
integration-custom-template Patch
deploy Patch
deploy-server Patch
dev-server Patch
integration-disable-html Patch
app-custom-entries Patch
app-custom-routes-runtime Patch
app-custom Patch
app-entry Patch
app-route Patch
app-entry-server Patch
i18n-app-csr-html-lang Patch
i18n-app Patch
i18n-app-ssr-html-lang Patch
i18n-app-ssr Patch
i18n-custom-i18n-wrapper Patch
i18n-mf-app-provider Patch
i18n-mf-component-provider Patch
i18n-mf-consumer Patch
i18n-routes Patch
i18n-routes-ssr Patch
@integration-test/image-component Patch
main-entry-name Patch
nonce Patch
pure-esm-project Patch
react-compiler-test Patch
routes-match Patch
routes Patch
app-rsbuild-hooks Patch
rsc-csr-app Patch
rsc-csr-routes Patch
rsc-ssr-app Patch
rsc-ssr-routes Patch
basic-app-rstest-browser Patch
basic-app-rstest Patch
runtime-custom-plugin Patch
runtime-custom-config-plugin Patch
select-mul-entry-test Patch
select-one-entry-test Patch
server-config Patch
server-esm-tsx Patch
server-json-script Patch
server-monitors Patch
server-prod Patch
server-routes Patch
@source-code-build/app Patch
ssg-fixtures-mega-list-routes Patch
ssg-fixtures-nested-routes Patch
ssg-fixtures-simple Patch
ssg-fixtures-web-server Patch
ssr-base-async-entry-test Patch
ssr-base-async-pre-entry-test Patch
ssr-base-json-test Patch
ssr-base-test Patch
ssr-base-fallback-test Patch
init Patch
ssr-base-loadable Patch
ssr-partial-test Patch
rsc-closing-tags-test Patch
ssr-script-loading Patch
ssr-useid-test Patch
ssr-streaming-inline-test Patch
ssr-streaming-lazy-test Patch
ssr-streaming-test Patch
styled-components-stream Patch
styled-components-string Patch
integration-tailwindcss-v2 Patch
integration-tailwindcss-v3 Patch
integration-tailwindcss-v4-tools Patch
integration-tailwindcss-v4 Patch
tmp-dir Patch
write-to-dist Patch
@modern-js/bundle-diff-benchmark Patch
@modern-js/main-doc Patch
@modern-js/tsconfig Patch
@modern-js/adapter-rstest Patch
@modern-js/builder Patch
@modern-js/plugin-data-loader Patch
@modern-js/plugin-ssg Patch
@modern-js/image Patch
@modern-js/render Patch
@modern-js/bff-core Patch
@modern-js/bff-runtime Patch
@modern-js/server-core Patch
@modern-js/create-request Patch
@modern-js/plugin-polyfill Patch
@modern-js/prod-server Patch
@modern-js/server-runtime Patch
@modern-js/server Patch
@modern-js/server-utils Patch
@modern-js/app-tools Patch
@modern-js/create Patch
@modern-js/i18n-utils Patch
@modern-js/plugin Patch
@modern-js/runtime-utils Patch
@modern-js/sandpack-react Patch
@modern-js/types Patch
@modern-js/utils Patch
@modern-js/rslib Patch
@scripts/prebundle Patch
@scripts/rstest-config Patch
entries-app-builder Patch
@scripts/release-node 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

@github-actions

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

📊 Quick Summary
Project Total Size Change
bundle-diff 473.2 KB +642.0 B (0.1%)
📋 Detailed Reports (Click to expand)

📁 bundle-diff

Path: benchmark/bundle-diff/dist/rsdoctor-data.json

📌 Baseline Commit: 0ef3f4afd3 | PR: #8863

Metric Current Baseline Change
📊 Total Size 473.2 KB 472.6 KB +642.0 B (0.1%)
📄 JavaScript 465.8 KB 465.1 KB +642.0 B (0.1%)
🎨 CSS 1.2 KB 1.2 KB 0
🌐 HTML 5.5 KB 5.5 KB 0
📁 Other Assets 765.0 B 765.0 B 0

📦 Download Diff Report: bundle-diff Bundle Diff

Generated by Rsdoctor GitHub Action

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.

1 participant