160
});
161
}
162
163
+ function dripStream(input) {
164
+ const reader = input.getReader();
165
+ let nextDrop = 0;
166
+ let controller = null;
167
+ let streamDone = false;
168
+ const buffer = [];
169
+ function flush() {
170
+ if (controller === null || nextDrop === 0) {
171
+ return;
172
+ }
173
+ while (buffer.length > 0 && nextDrop > 0) {
174
+ const nextChunk = buffer[0];
175
+ if (nextChunk.byteLength <= nextDrop) {
176
+ nextDrop -= nextChunk.byteLength;
177
+ controller.enqueue(nextChunk);
178
+ buffer.shift();
179
+ if (streamDone && buffer.length === 0) {
180
+ controller.done();
181
+ }
182
+ } else {
183
+ controller.enqueue(nextChunk.subarray(0, nextDrop));
184
+ buffer[0] = nextChunk.subarray(nextDrop);
185
+ nextDrop = 0;
186
+ }
187
+ }
188
+ }
189
+ const output = new ReadableStream({
190
+ start(c) {
191
+ controller = c;
192
+ async function pump() {
193
+ for (;;) {
194
+ const {value, done} = await reader.read();
195
+ if (done) {
196
+ streamDone = true;
197
+ break;
198
+ }
199
+ buffer.push(value);
200
+ flush();
201
+ }
202
+ }
203
+ pump();
204
+ },
205
+ pull() {},
206
+ cancel(reason) {
207
+ reader.cancel(reason);
208
+ },
209
+ });
210
+ function drip(n) {
211
+ nextDrop += n;
212
+ flush();
213
+ }
214
+
215
+ return [output, drip];
216
+ }
217
+
218
async function readResult(stream) {
219
const reader = stream.getReader();
220
let result = '';
631
expect(serializedContent.length).toBeLessThan(150 + expectedDebugInfoSize);
632
});
633
634
+ it('should break up large sync components by outlining into streamable elements', async () => {
635
+ const paragraphs = [];
636
+ for (let i = 0; i < 20; i++) {
637
+ const text =
638
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris' +
639
+ 'porttitor tortor ac lectus faucibus, eget eleifend elit hendrerit.' +
640
+ 'Integer porttitor nisi in leo congue rutrum. Morbi sed ante posuere,' +
641
+ 'aliquam lorem ac, imperdiet orci. Duis malesuada gravida pharetra. Cras' +
642
+ 'facilisis arcu diam, id dictum lorem imperdiet a. Suspendisse aliquet' +
643
+ 'tempus tortor et ultricies. Aliquam libero velit, posuere tempus ante' +
644
+ 'sed, pellentesque tincidunt lorem. Nullam iaculis, eros a varius' +
645
+ 'aliquet, tortor felis tempor metus, nec cursus felis eros aliquam nulla.' +
646
+ 'Vivamus ut orci sed mauris congue lacinia. Cras eget blandit neque.' +
647
+ 'Pellentesque a massa in turpis ullamcorper volutpat vel at massa. Sed' +
648
+ 'ante est, auctor non diam non, vulputate ultrices metus. Maecenas dictum' +
649
+ 'fermentum quam id aliquam. Donec porta risus vitae pretium posuere.' +
650
+ 'Fusce facilisis eros in lacus tincidunt congue.' +
651
+ i; /* trick dedupe */
652
+ paragraphs.push(<p key={i}>{text}</p>);
653
+ }
654
+
655
+ const stream = await serverAct(() =>
656
+ ReactServerDOMServer.renderToReadableStream(paragraphs),
657
+ );
658
+
659
+ const [stream2, drip] = dripStream(stream);
660
+
661
+ // Allow some of the content through.
662
+ drip(5000);
663
+
664
+ const result = await ReactServerDOMClient.createFromReadableStream(
665
+ stream2,
666
+ {
667
+ serverConsumerManifest: {
668
+ moduleMap: null,
669
+ moduleLoading: null,
670
+ },
671
+ },
672
+ );
673
+
674
+ // We should have resolved enough to be able to get the array even though some
675
+ // of the items inside are still lazy.
676
+ expect(result.length).toBe(20);
677
+
678
+ // Unblock the rest
679
+ drip(Infinity);
680
+
681
+ // Use the SSR render to resolve any lazy elements
682
+ const ssrStream = await serverAct(() =>
683
+ ReactDOMServer.renderToReadableStream(result),
684
+ );
685
+ const html = await readResult(ssrStream);
686
+
687
+ const ssrStream2 = await serverAct(() =>
688
+ ReactDOMServer.renderToReadableStream(paragraphs),
689
+ );
690
+ const html2 = await readResult(ssrStream2);
691
+
692
+ expect(html).toBe(html2);
693
+ });
694
+
695
it('should be able to serialize any kind of typed array', async () => {
696
const buffer = new Uint8Array([
697
123, 4, 10, 5, 100, 255, 244, 45, 56, 67, 43, 124, 67, 89, 100, 20,