Stars: 517
Forks: 21
Pull Requests: 17
Issues: 9
Watchers: 6
Last Updated: 2023-09-05 16:49:47
Painless Laravel Broadcasting with SSE
License: MIT License
Languages: PHP
Bring live to your application
Unlock the power of Laravel's broadcasting system with Wave. Imagine that real-time server broadcasting is possible over native HTTP without any WebSockets setup.
Meet the Server-sent Events 🗼 Works seamlessly with Laravel's default redis
broadcasting driver and supports Laravel Echo.
Server-Sent Events (SSE) is specially tuned for real-time server-to-client communication.
Experience it live with our demo streaming tweets 🐤.
Works well at home. Should be battle tested for 1.0, feedbacks appreciated!
⚡ Works with native Redis Driver: Wave seamlessly integrates with Laravel's default redis
broadcasting driver, ensuring efficient real-time data transfer.
🔄 Resume From Last: Connection drops? No problem! Wave intelligently resumes the event stream from the last event, ensuring no crucial data is lost in transit.
🍃 Resource-Friendly Broadcasting with pauseInactive
: This feature maximizes resource efficiency by closing the data stream when inactive (such as when the user minimizes the browser) and automatically reopens it upon resumption of visibility. Turned off by default.
🎛️️ Full Requests Control: Wave hands you the reins over connection and authentication requests, granting you the freedom to shape your broadcasting setup to your exact requirements.
🟢 Live Models: With a simple interface that respects Laravel's native conventions for Model Events Broadcasting and Broadcast Notifications, Wave turbocharges your application with real-time updates.
In light of recent events in Ukraine, my life has taken an unexpected turn. Since February 24th, I've lost my commercial work, my permanent residence, and my ability to plan for the future.
During these challenging times, I derive strength and purpose from creating open source projects, such as Wave.
I welcome you to visit my GitHub Sponsorships profile. There, you can discover more about my current work, future ambitions, and aspirations. Every ⭐ you give brings joy to my day, and your sponsorship can make a profound difference in my ability to continue creating.
I'm truly grateful for your support, whether it's a shout-out or a heartfelt "thank you".
Install Wave on both server and client sides using Composer and npm:
composer require qruto/laravel-wave
npm install laravel-wave
Then, set your .env
file to use the redis
broadcasting driver:
BROADCAST_DRIVER=redis
Ensure that you have
output_buffering = On
in your php.ini
After installing Wave, your server is ready to broadcast events.
You can use it with Echo as usual or try Wave
model to work with predefined Eloquent events.
Import Laravel Echo with WaveConnector
and pass it to the broadcaster option:
import Echo from 'laravel-echo';
import { WaveConnector } from 'laravel-wave';
window.Echo = new Echo({ broadcaster: WaveConnector });
For fresh installations, locate Echo connection configuration in resources/js/bootstrap.js file.
Replace it by the snippet above:
- import Echo from 'laravel-echo';
- import Pusher from 'pusher-js';
- window.Pusher = Pusher;
- window.Echo = new Echo({
- broadcaster: 'pusher',
- key: import.meta.env.VITE_PUSHER_APP_KEY,
- wsHost: import.meta.env.VITE_PUSHER_HOST ?? `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
- wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
- wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
- forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
- enabledTransports: ['ws', 'wss'],
- });
+ import Echo from 'laravel-echo';
+ import { WaveConnector } from 'laravel-wave';
+ window.Echo = new Echo({ broadcaster: WaveConnector });
Use Echo as you typically would.
📞 Receiving Broadcasts documentation
With native conventions of Model Events Broadcasting and Broadcast Notifications you can use Wave models to receive model events and notifications.
import { Wave } from 'laravel-wave';
window.Wave = new Wave();
wave.model('User', '1')
.notification('team.invite', (notification) => {
console.log(notification);
})
.updated((user) => console.log('user updated', user))
.deleted((user) => console.log('user deleted', user))
.trashed((user) => console.log('user trashed', user))
.restored((user) => console.log('user restored', user))
.updated('Team', (team) => console.log('team updated', team));
Start by calling the model
method on the Wave
instance with the model name and key.
By default, Wave prefixes model names with App.Models
namespace. You can customize this with the namespace
option:
window.Wave = new Wave({ namespace: 'App.Path.Models' });
📄 Check out full Laravel Broadcasting documentation
These options can be passed to the Wave
or Echo
instance:
Name | Type | Default | Description |
---|---|---|---|
endpoint | string | /wave |
Primary SSE connection route. |
namespace | string | App.Events |
Namespace of events to listen for. |
auth.headers | object | {} |
Additional authentication headers. |
authEndpoint | string? | /broadcasting/auth |
Authentication endpoint. |
csrfToken | string? | undefined or string |
CSRF token, defaults from XSRF-TOKEN cookie. |
bearerToken | string? | undefined |
Bearer tokenfor authentication. |
request | Request? | undefined |
Custom settings for connection and authentication requests. |
pauseInactive | boolean | false |
If true , closes connection when the page is hidden and reopens when visible. |
debug | boolean | false |
Toggles debug mode. If set to true , provides detailed event logs in the console, helping with event diagnosis and troubleshooting. |
new Echo({
broadcaster: WaveConnector,
endpoint: '/sse-endpoint',
bearerToken: 'bearer-token',
//...
});
// or
new Wave({
authEndpoint: '/custom-broadcasting/auth',
csrfToken: 'csrf-token',
})
You can publish the Laravel configuration file with:
php artisan vendor:publish --tag="wave-config"
Here are the contents of the published configuration file:
return [
/*
|--------------------------------------------------------------------------
| Resume Lifetime
|--------------------------------------------------------------------------
|
| Define how long (in seconds) you wish an event stream to persist so it
| can be resumed after a reconnect. The connection automatically
| re-establishes with every closed response.
|
| * Requires a cache driver to be configured.
|
*/
'resume_lifetime' => 60,
/*
|--------------------------------------------------------------------------
| Reconnection Time
|--------------------------------------------------------------------------
|
| This value determines how long (in milliseconds) to wait before
| attempting a reconnect to the server after a connection has been lost.
| By default, the client attempts to reconnect immediately. For more
| information, please refer to the Mozilla developer's guide on event
| stream format.
| https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format
|
*/
'retry' => null,
/*
|--------------------------------------------------------------------------
| Ping
|--------------------------------------------------------------------------
|
| A ping event is automatically sent on every SSE connection request if the
| last event occurred before the set `frequency` value (in seconds). This
| ensures the connection remains persistent.
|
| By setting the `eager_env` option, a ping event will be sent with each
| request. This is useful for development or for applications that do not
| frequently expect events. The `eager_env` option can be set as an `array` or `null`.
|
| For manual control of the ping event with the `sse:ping` command, you can
| disable this option.
|
*/
'ping' => [
'enable' => true,
'frequency' => 30,
'eager_env' => 'local', // null or array
],
/*
|--------------------------------------------------------------------------
| Routes Path
|--------------------------------------------------------------------------
|
| This path is used to register the necessary routes for establishing the
| Wave connection, storing presence channel users, and handling simple whisper events.
|
*/
'path' => 'wave',
/*
|--------------------------------------------------------------------------
| Route Middleware
|--------------------------------------------------------------------------
|
| Define which middleware Wave should assign to the routes that it registers.
| You may modify these middleware as needed. However, the default value is
| typically sufficient.
|
*/
'middleware' => [
'web',
],
/*
|--------------------------------------------------------------------------
| Auth & Guard
|--------------------------------------------------------------------------
|
| Define the default authentication middleware and guard type for
| authenticating users for presence channels and whisper events.
|
*/
'auth_middleware' => 'auth',
'guard' => 'web',
];
Depending on your web server configuration, you might observe that the connection drops at certain intervals.
Wave is designed to automatically reconnect after a request timeout.
During reconnection, you won't lose any events as Laravel Wave
stores event history for one minute by default.
The resume_lifetime
value in the config file
allows you to adjust this duration.
⚠️ Ensure that the interval between events is shorter than your web server's request timeout and that no other low-level timeout options are set to keep the connection persistent
Wave tries to send a ping event on each Server-Sent Events (SSE) connection request
if the last event occurred earlier than the ping.frequency
config value.
If your application doesn't expect many SSE connections,
specify the list of environments in which a ping event will be sent
with each Wave request. By default, this is set to local
.
For more control over the ping event, disable automatic sending by adjusting the ping.enable
config value.
Wave offers the sse:ping
command for manually sending a single ping or operating at an interval.
Use the Laravel Tasks scheduler to send a ping event every minute:
protected function schedule(Schedule $schedule)
{
$schedule->command('sse:ping')->everyMinute();
}
If you require shorter intervals between ping events, use the --interval option to set the number of seconds:
php artisan sse:ping --interval=30
For example, basic fastcgi_read_timeout
value is 60s
for Nginx + PHP FastCGI server setup.
This means that to keep the connection persistent, events must occur more often than every 60 seconds.
Web servers usually don't expect persistent HTTP connections and may have limitations at various stages 😟.
For a Nginx + PHP FPM setup, the connection is typically limited to 1m
by FastCGI.
Modify the location directive after the end of location ~ \.php$
as follows:
location = /wave {
rewrite ^/wave$ /index.php?$query_string break;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_read_timeout 2m;
}
Note: Copy the fastcgi_pass
Unix socket path from location ~ \.php$
.
Some platforms, such as Laravel Forge, configure the PHP FPM pool with request_terminate_timeout = 60
, terminating all requests after 60 seconds.
You can disable this in the /etc/php/8.1/fpm/pool.d/www.conf
config file:
request_terminate_timeout = 0
Alternatively, you can configure a separate pool for the SSE connection:
Writing instruction...
📍 Local broadcasting driver ◻️ Laravel Octane support 📥 📤 two ways live models syncing 📡 Something awesome with opened live abilities...
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
Package template based on Spatie Laravel Skeleton.
The MIT License (MIT). Please see License File for more information.