Warning
This is an internal project, and is not intended for public use. No support or stability guarantees are provided.
These demos drive the chunked swap through abstractCreateStream. Compare with the client useStream benchmarks, which do the same work without the factory.
The line charts keep the calculations server-side (RSC owns the swap); the scatter charts use the fallback→content hoist, where the swap — and so the heavy compute — is client-side:
The server Loader computes and renders the chart in RSC. Each chunk gets its own Suspense boundary and streams in one-by-one from the server — its coarse slice shows until that chunk's boundary resolves, then RSC flushes the full detail. The swap is driven entirely by streaming RSC; the client only hydrates the finished SVG, with no client-side projection (a small per-chunk stagger stands in for a real per-chunk data load).
import { createStreamFactory } from '@mui/internal-docs-infra/abstractCreateStream';
import FullLineChart from './FullLineChart';
import { SimpleLineChart } from './SimpleLineChart';
// Server `Loader`: the full chart is computed and rendered in RSC, streamed under
// Suspense behind the coarse `ChunkLoading` placeholder. Nothing computes on the
// client — it only hydrates the finished markup.
const createStream = createStreamFactory({
ChunkContent: FullLineChart,
ChunkLoading: SimpleLineChart,
Loader: () => import('./FullLineChart'),
});
export default createStream(import.meta.url);The server Loader computes the dataset in RSC and hands it to a client component as props, which runs the same coarse→full serial swap as the client benchmark. The projection stays on the server; the full dataset is serialized into the RSC payload.
import { createStreamFactory } from '@mui/internal-docs-infra/abstractCreateStream';
import ServerLineChart from './ServerLineChart';
import { SimpleLineChart } from './SimpleLineChart';
// Server `Loader` computes the dataset in RSC, then renders the client animator
// with the data as props — so the heavy projection stays on the server while the
// serial coarse→full swap still runs on the client.
const createStream = createStreamFactory({
ChunkContent: ServerLineChart,
ChunkLoading: SimpleLineChart,
Loader: () => import('./ServerLineChart'),
});
export default createStream(import.meta.url);The scatter uses the fallback→content hoist. The chunk's quick initial clusters the points (coarse) — ScatterLoading renders it (so it's in the SSR HTML) and hoists the clusters up the swap with useCoordinatedFallback. The full load tiles and assigns the detailed dots; requireHoist holds the swap until the coarse is hoisted, so the swap is seamless. ScatterContent then reads those same clusters via useCoordinatedContent, paints each chunk's detailed dots behind the opaque coarse overlay one at a time (rendered and painted, but never visible) while a loading indicator counts them off, and once the last is painted drops the overlay in a single commit — revealing the whole scatter at once, with no re-render of the detail.
Because the hoist (and thus the swap) is a client concern, the heavy detail pass runs in the browser; only the coarse initial runs during SSR. Contrast the line charts, where RSC owns the swap.
import * as React from 'react';
import { createStreamFactory } from '@mui/internal-docs-infra/abstractCreateStream';
import { ScatterChartLoading } from './scatterParts';
import ScatterChart from './ScatterChart';
// Server loading: the `Loader` dynamically imports `ScatterChart` (server-only),
// which computes the scatter on the server and streams it under Suspense — no
// loader functions cross the RSC boundary. `ScatterChart` then drives the
// coarse→detail hoist swap on the client.
const createStream = createStreamFactory({
ChunkContent: ScatterChart,
ChunkLoading: ScatterChartLoading,
Loader: () => import('./ScatterChart'),
});
const Stream = createStream(import.meta.url);
export default function Page() {
return <Stream />;
}import * as React from 'react';
import { createStreamFactory } from '@mui/internal-docs-infra/abstractCreateStream';
import { ScatterChartLoading } from './scatterParts';
import ScatterChart from './ScatterChart';
// Server loading: the `Loader` dynamically imports `ScatterChart` (server-only),
// which computes the scatter on the server and streams it under Suspense — no
// loader functions cross the RSC boundary. `ScatterChart` then drives the
// coarse→detail hoist swap on the client.
const createStream = createStreamFactory({
ChunkContent: ScatterChart,
ChunkLoading: ScatterChartLoading,
Loader: () => import('./ScatterChart'),
});
const Stream = createStream(import.meta.url);
export default function Page() {
return <Stream />;
}