You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
By streaming data to the client as it is generated, you can significantly reduce memory usage and improve performance, especially for very large responses. Streamed responses allow the client to begin processing data before the server has finished sending it:
366
370
367
371
```php
368
-
function streamedContent(): Generator {
369
-
yield 'Hello, ';
370
-
yield 'World!';
371
-
}
372
-
373
372
Route::get('/stream', function () {
374
373
return response()->stream(function (): void {
375
-
foreach (streamedContent() as $chunk) {
376
-
echo $chunk;
374
+
foreach (['developer', 'admin'] as $string) {
375
+
echo $string;
377
376
ob_flush();
378
377
flush();
379
378
sleep(2); // Simulate delay between chunks...
@@ -382,11 +381,262 @@ Route::get('/stream', function () {
382
381
});
383
382
```
384
383
385
-
> [!NOTE]
386
-
> Internally, Laravel utilizes PHP's output buffering functionality. As you can see in the example above, you should use the `ob_flush` and `flush` functions to push buffered content to the client.
384
+
For convenience, if the closure you provide to the `stream` method returns a [Generator](https://www.php.net/manual/en/language.generators.overview.php), Laravel will automatically flush the output buffer between strings returned by the generator, as well as disable Nginx output buffering:
Streamed responses may be consumed using Laravel's `stream` npm package, which provides a convenient API for interacting with Laravel response and event streams. To get started, install the `@laravel/stream-react` or `@laravel/stream-vue` package:
402
+
403
+
```shell tab=React
404
+
npm install @laravel/stream-react
405
+
```
406
+
407
+
```shell tab=Vue
408
+
npm install @laravel/stream-vue
409
+
```
410
+
411
+
Then, `useStream` may be used to consume the event stream. After providing your stream URL, the hook will automatically update the `data` with the concatenated response as content is returned from your Laravel application:
When sending data back to the stream via `send`, the active connection to the stream is canceled before sending the new data. All requests are sent as JSON `POST` requests.
460
+
461
+
The second argument given to `useStream` is an options object that you may use to customize the stream consumption behavior. The default values for this object are shown below:
462
+
463
+
```tsx tab=React
464
+
import { useStream } from"@laravel/stream-react";
465
+
466
+
function App() {
467
+
const { data } =useStream("chat", {
468
+
id: undefined,
469
+
initialInput: undefined,
470
+
headers: undefined,
471
+
csrfToken: undefined,
472
+
onResponse: (response:Response) =>void,
473
+
onData: (data:string) =>void,
474
+
onCancel: () =>void,
475
+
onFinish: () =>void,
476
+
onError: (error:Error) =>void,
477
+
});
478
+
479
+
return <div>{data}</div>;
480
+
}
481
+
```
482
+
483
+
```vue tab=Vue
484
+
<script setup lang="ts">
485
+
import { useStream } from "@laravel/stream-vue";
486
+
487
+
const { data } = useStream("chat", {
488
+
id: undefined,
489
+
initialInput: undefined,
490
+
headers: undefined,
491
+
csrfToken: undefined,
492
+
onResponse: (response: Response) => void,
493
+
onData: (data: string) => void,
494
+
onCancel: () => void,
495
+
onFinish: () => void,
496
+
onError: (error: Error) => void,
497
+
});
498
+
</script>
499
+
500
+
<template>
501
+
<div>{{ data }}</div>
502
+
</template>
503
+
```
504
+
505
+
`onResponse` is triggered after a successful initial response from the stream and the raw [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) is passed to the callback. `onData` is called as each chunk is received - the current chunk is passed to the callback. `onFinish` is called when a stream has finished and when an error is thrown during the fetch / read cycle.
506
+
507
+
By default, a request is not made to the stream on initialization. You may pass an initial payload to the stream by using the `initialInput` option:
508
+
509
+
```tsx tab=React
510
+
import { useStream } from"@laravel/stream-react";
511
+
512
+
function App() {
513
+
const { data } =useStream("chat", {
514
+
initialInput: {
515
+
message: "Introduce yourself.",
516
+
},
517
+
});
518
+
519
+
return <div>{data}</div>;
520
+
}
521
+
```
522
+
523
+
```vue tab=Vue
524
+
<script setup lang="ts">
525
+
import { useStream } from "@laravel/stream-vue";
526
+
527
+
const { data } = useStream("chat", {
528
+
initialInput: {
529
+
message: "Introduce yourself.",
530
+
},
531
+
});
532
+
</script>
533
+
534
+
<template>
535
+
<div>{{ data }}</div>
536
+
</template>
537
+
```
538
+
539
+
To cancel a stream manually, you may use the `cancel` method returned from the hook:
540
+
541
+
```tsx tab=React
542
+
import { useStream } from"@laravel/stream-react";
543
+
544
+
function App() {
545
+
const { data, cancel } =useStream("chat");
546
+
547
+
return (
548
+
<div>
549
+
<div>{data}</div>
550
+
<buttononClick={cancel}>Cancel</button>
551
+
</div>
552
+
);
553
+
}
554
+
```
555
+
556
+
```vue tab=Vue
557
+
<script setup lang="ts">
558
+
import { useStream } from "@laravel/stream-vue";
559
+
560
+
const { data, cancel } = useStream("chat");
561
+
</script>
562
+
563
+
<template>
564
+
<div>
565
+
<div>{{ data }}</div>
566
+
<button @click="cancel">Cancel</button>
567
+
</div>
568
+
</template>
569
+
```
570
+
571
+
Each time the `useStream` hook is used, a random `id` is generated to identify the stream. This is sent back to the server with each request in the `X-STREAM-ID` header. When consuming the same stream from multiple components, you can read and write to the stream by providing your own `id`:
572
+
573
+
```tsx tab=React
574
+
// App.tsx
575
+
import { useStream } from"@laravel/stream-react";
576
+
577
+
function App() {
578
+
const { data, id } =useStream("chat");
579
+
580
+
return (
581
+
<div>
582
+
<div>{data}</div>
583
+
<StreamStatusid={id} />
584
+
</div>
585
+
);
586
+
}
587
+
588
+
// StreamStatus.tsx
589
+
import { useStream } from"@laravel/stream-react";
590
+
591
+
function StreamStatus({ id }) {
592
+
const { isFetching, isStreaming } =useStream("chat", { id });
If you need to stream JSON data incrementally, you may utilize the `streamJson` method. This method is especially useful for large datasets that need to be sent progressively to the browser in a format that can be easily parsed by JavaScript:
392
642
@@ -400,8 +650,74 @@ Route::get('/users.json', function () {
400
650
});
401
651
```
402
652
653
+
The `useJsonStream` hook is identical to the [`useStream` hook](#consuming-streamed-responses) except that it will attempt to parse the data as JSON once it has finished streaming:
The `eventStream` method may be used to return a server-sent events (SSE) streamed response using the `text/event-stream` content type. The `eventStream` method accepts a closure which should [yield](https://www.php.net/manual/en/language.generators.overview.php) responses to the stream as the responses become available:
407
723
@@ -428,6 +744,9 @@ yield new StreamedEvent(
428
744
);
429
745
```
430
746
747
+
<aname="consuming-event-streams"></a>
748
+
#### Consuming Event Streams
749
+
431
750
Event streams may be consumed using Laravel's `stream` npm package, which provides a convenient API for interacting with Laravel event streams. To get started, install the `@laravel/stream-react` or `@laravel/stream-vue` package:
Sometimes you may wish to turn the string response of a given operation into a downloadable response without having to write the contents of the operation to disk. You may use the `streamDownload` method in this scenario. This method accepts a callback, filename, and an optional array of headers as its arguments:
0 commit comments