Download the PHP package dancycodes/gale without Composer
On this page you can find all versions of the php package dancycodes/gale. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download dancycodes/gale
More information about dancycodes/gale
Files in dancycodes/gale
Package gale
Short Description Laravel-native reactive frontends using Alpine Gale. Build dynamic UIs with Blade templates and Server-Sent Events.
License MIT
Homepage https://github.com/dancycodes/gale
Informations about the package gale
Laravel Gale
Laravel Gale is a server-driven reactive framework for Laravel. It uses standard HTTP responses (JSON) by default to deliver real-time UI updates to Alpine.js components directly from your Blade templates -- no JavaScript framework, no build complexity, no API layer. For long-running operations or real-time streaming, Server-Sent Events (SSE) is available as an explicit opt-in.
GALE = Gouater + Anais + Loic + Eunice (Founders' initials)
This README documents both:
- Laravel Gale -- The PHP backend package (
dancycodes/gale) - Alpine Gale -- The Alpine.js frontend plugin (bundled with Laravel Gale)
Full documentation: Frontend API
Table of Contents
- Requirements
- Quick Start
- Installation
- How It Works
- Dual-Mode Architecture
- Request/Response Flow
- RFC 7386 JSON Merge Patch
- Mode Configuration
- HTTP vs SSE Comparison
- Choosing a Mode
- Configuring the Default Mode
- Per-Request Mode Override
- Backend: Laravel Gale
- The gale() Helper
- State Management
- DOM Manipulation
- Blade Fragments
- Redirects
- Navigation
- Events and JavaScript
- Component Targeting
- Streaming Mode (SSE)
- Request Macros
- Blade Directives
- Validation
- Conditional Execution
- Route Discovery
- Frontend: Alpine Gale
- The $action Magic
- State Synchronization (x-sync)
- CSRF Protection
- Global State ($gale)
- Element State ($fetching)
- Loading Directives
- Navigation
- Component Registry
- Form Binding (x-name)
- File Uploads
- Message Display
- Polling (x-interval)
- Confirmation Dialogs
- Configuration Reference
- Advanced Topics
- DOM Patching Modes
- View Transitions API
- SSE Protocol Specification
- State Serialization
- API Reference
- Troubleshooting
- Testing
- Contributing
- License
Requirements
- PHP 8.2 or higher
- Laravel 11 or 12
- Alpine.js 3.x (bundled -- no separate install needed)
No Node.js or npm required for basic usage. @gale serves the pre-built JS bundle from public/vendor/gale/.
Quick Start
A complete reactive counter in under 20 lines:
routes/web.php:
resources/views/counter.blade.php:
Click the button. The count updates via HTTP. No page reload, no JavaScript written.
Installation
Add @gale to your layout's <head>:
That's it. The @gale directive outputs:
- CSRF meta tag
- Alpine.js (v3) with the Morph plugin
- The Alpine Gale plugin
- Debug panel (when
APP_DEBUG=true)
Existing Alpine.js Projects
Gale bundles Alpine.js (v3) with the Morph plugin. If you already have Alpine.js installed, remove it to prevent conflicts:
Then use @gale instead -- it handles everything.
Using Additional Alpine Plugins
Gale exposes window.Alpine, so other plugins work normally:
Optional: Publish Configuration
How It Works
Dual-Mode Architecture
Gale operates in two modes with an identical developer API:
-
HTTP mode (default): Responses are standard JSON payloads (
Content-Type: application/json). Simple, works with all hosting environments, CDNs, and load balancers. Suitable for the vast majority of interactions. - SSE mode (opt-in): Responses are streamed as Server-Sent Events (
Content-Type: text/event-stream). Required for long-running operations, real-time progress, or live streaming. Activated per-request with{ sse: true }or globally via configuration.
The backend API is identical in both modes -- the same gale()->state(), gale()->view(), and all other methods work regardless of transport. The frontend automatically detects the response type and processes accordingly.
Request/Response Flow
RFC 7386 JSON Merge Patch
State updates follow RFC 7386:
| Server Sends | Current State | Result |
|---|---|---|
{ count: 5 } |
{ count: 0, name: "John" } |
{ count: 5, name: "John" } |
{ name: null } |
{ count: 0, name: "John" } |
{ count: 0 } |
{ user: { email: "new" } } |
{ user: { name: "John", email: "old" } } |
{ user: { name: "John", email: "new" } } |
- Values merge: Sent values replace existing values
- Null deletes: Sending
nullremoves the property - Deep merge: Nested objects merge recursively
Mode Configuration
HTTP vs SSE Comparison
| Feature | HTTP Mode (Default) | SSE Mode (Opt-in) |
|---|---|---|
| Transport | Standard JSON over HTTP | Server-Sent Events stream |
| Response type | application/json |
text/event-stream |
| Hosting | Works everywhere | Requires SSE-compatible hosting |
| CDN / Load Balancer | Fully compatible | May require configuration |
| Serverless | Fully compatible | Not recommended |
| Latency | Single response | Streaming (events sent as they occur) |
| Progress updates | Not supported | Real-time progress |
| Long-running ops | Subject to timeout | Stream indefinitely |
| Connection overhead | New connection per request | Held open during stream |
| Error handling | Standard HTTP status codes | Inline error events |
| Retry | Automatic with backoff | Built-in SSE reconnection |
| Best for | Forms, CRUD, navigation, most interactions | Dashboards, progress bars, chat, AI streaming |
Choosing a Mode
Use HTTP mode (default) when:
- Building forms, CRUD operations, or standard interactions
- Deploying to serverless, CDN-fronted, or shared hosting
- You want the simplest possible setup
- Response times are fast (< 1 second)
Use SSE mode when:
- You need real-time progress updates (file processing, imports)
- Building live dashboards or chat interfaces
- Streaming AI-generated content
- Operations take more than a few seconds
Configuring the Default Mode
The default mode can be set at three levels (highest priority first):
1. Request header (per-request, set automatically by frontend):
2. Environment variable (application-wide):
3. Config file (config/gale.php):
Per-Request Mode Override
On the frontend, override per request:
Or use gale()->stream() on the backend, which always uses SSE regardless of configuration:
Backend: Laravel Gale
The gale() Helper
Returns a request-scoped GaleResponse instance with a fluent API:
The same instance accumulates events throughout the request. In HTTP mode, they are serialized as a single JSON response. In SSE mode, they are streamed as individual events.
State Management
state()
Set state values to merge into the Alpine component:
patchState()
Alias for state() when passing an array -- preferred for explicit multi-key patches:
forget()
Remove state properties (sends null per RFC 7386):
messages()
Set the messages state object (used for validation errors and notifications):
clearMessages()
Clear all messages:
flash()
Deliver flash data to both the session and the _flash Alpine state key in one call:
In the view, display flash reactively:
DOM Manipulation
view()
Render a Blade view and patch it into the DOM:
html()
Patch raw HTML into the DOM:
DOM Convenience Methods
| Method | Mode | State Handling |
|---|---|---|
outer($selector, $html, $opts) |
outer |
Server-driven |
inner($selector, $html, $opts) |
inner |
Server-driven |
outerMorph($selector, $html, $opts) |
outerMorph |
Client-preserved |
innerMorph($selector, $html, $opts) |
innerMorph |
Client-preserved |
append($selector, $html, $opts) |
append |
New elements init |
prepend($selector, $html, $opts) |
prepend |
New elements init |
before($selector, $html, $opts) |
before |
New elements init |
after($selector, $html, $opts) |
after |
New elements init |
remove($selector) |
remove |
Cleanup |
View options:
| Option | Type | Default | Description |
|---|---|---|---|
selector |
string | null |
CSS selector for target element |
mode |
string | 'outer' |
DOM patching mode |
useViewTransition |
bool | false |
Enable View Transitions API |
settle |
int | 0 |
Delay (ms) before patching |
scroll |
string | null |
Auto-scroll: 'top' or 'bottom' |
show |
string | null |
Scroll into viewport: 'top' or 'bottom' |
focusScroll |
bool | false |
Maintain focus scroll position |
Blade Fragments
Extract and render specific sections from Blade views without rendering the entire template.
Define fragments in Blade:
Render fragments:
Redirects
Full-page browser redirects with session flash support:
| Method | Description |
|---|---|
with($key, $value) |
Flash data to session |
withInput($input) |
Flash form input for repopulation |
withErrors($errors) |
Flash validation errors |
back($fallback) |
Redirect to previous URL with fallback |
backOr($route, $params) |
Back with named route fallback |
refresh($query, $fragment) |
Reload current page |
home() |
Redirect to root URL |
route($name, $params) |
Redirect to named route |
intended($default) |
Redirect to auth intended URL |
forceReload($bypass) |
Hard reload via JavaScript |
Navigation
Trigger SPA navigation from the backend:
Events and JavaScript
dispatch()
Dispatch custom DOM events from the server:
Listen in Alpine:
js()
Execute JavaScript in the browser:
debug()
Send debug data to the Gale debug panel (dev mode only):
Component Targeting
Target specific named Alpine components from the backend:
Streaming Mode (SSE)
For long-running operations, stream events in real-time. gale()->stream() always uses SSE regardless of the global mode setting:
Request Macros
Gale registers these macros on the Laravel Request object:
Blade Directives
@gale
Include the JavaScript bundle and CSRF meta tag:
Accepts optional options:
@fragment / @endfragment
Define extractable fragments:
@ifgale / @else / @endifgale
Conditional rendering based on request type:
Validation
Standard Laravel validation works reactively for Gale requests. ValidationException is automatically converted to a gale()->messages() response:
Form Request classes also work out of the box:
Conditional Execution
Route Discovery
Optional attribute-based route discovery:
List discovered routes:
Frontend: Alpine Gale
All frontend features require an Alpine.js context (x-data or x-init).
The $action Magic
The $action magic handles all HTTP requests. It defaults to POST with automatic CSRF injection -- the most common pattern for server actions.
CSRF tokens are automatically injected for all non-GET methods. No manual token handling required.
Request Options
| Option | Type | Default | Description |
|---|---|---|---|
method |
string | 'POST' |
HTTP method |
include |
string[] | -- | Only send these state keys |
exclude |
string[] | -- | Don't send these state keys |
headers |
object | {} |
Additional request headers |
sse |
bool | false |
Force SSE mode for this request |
http |
bool | false |
Force HTTP mode for this request |
retryInterval |
number | 1000 |
Initial retry delay (ms) |
retryScaler |
number | 2 |
Exponential backoff multiplier |
retryMaxWaitMs |
number | 30000 |
Maximum retry delay (ms) |
retryMaxCount |
number | 10 |
Maximum retry attempts |
requestCancellation |
bool | false |
Cancel previous in-flight request |
debounce |
number | -- | Trailing-edge debounce (ms) |
throttle |
number | -- | Leading-edge throttle (ms) |
onProgress |
function | -- | Upload progress callback (0-100) |
State Synchronization (x-sync)
The x-sync directive controls which Alpine state properties are sent to the server:
| x-sync Value | Result |
|---|---|
x-sync (empty) |
Send all state (wildcard) |
x-sync="*" |
Send all state (explicit wildcard) |
x-sync="['a','b']" |
Send only a and b |
x-sync="a, b" |
Send only a and b (string syntax) |
| No directive | Send nothing (use include option if needed) |
CSRF Protection
The @gale directive adds <meta name="csrf-token">. The $action magic reads this token automatically for all non-GET requests.
Global State ($gale)
The $gale magic provides global connection state:
| Property | Type | Description |
|---|---|---|
loading |
bool | Any request in progress |
activeCount |
number | Number of active requests |
retrying |
bool | Currently retrying a request |
retriesFailed |
bool | All retries exhausted |
error |
bool | Has any error |
lastError |
string | Most recent error message |
errors |
array | All error messages |
clearErrors() |
function | Clear all errors |
Element State ($fetching)
Track per-element loading state:
Note: $fetching is a function -- always use $fetching() with parentheses.
Loading Directives
x-loading
Show/hide elements or apply classes during loading:
x-indicator
Bind a boolean state variable to loading activity:
Navigation
x-navigate Directive
Enable SPA navigation on links and forms:
| Modifier | Description |
|---|---|
.merge |
Merge query params with current URL |
.replace |
Replace history entry instead of push |
.key.{name} |
Navigation key for targeted updates |
.only.{params} |
Keep only these query params |
.except.{params} |
Remove these query params |
.debounce.{ms} |
Debounce navigation |
.throttle.{ms} |
Throttle navigation |
$navigate Magic
x-navigate-skip
Exclude specific links from navigation:
Component Registry
Named components that can be targeted from the backend or other components.
| Method | Description |
|---|---|
get(name) |
Get component Alpine data object |
has(name) |
Check if component exists |
all() |
Get all registered components |
getByTag(tag) |
Get components with tag |
state(name, property) |
Get reactive state value |
update(name, state) |
Merge state into component |
create(name, state) |
Set state (with onlyIfMissing option) |
delete(name, keys) |
Remove state keys |
invoke(name, method, ...args) |
Call method on component |
watch(name, property, callback) |
Watch for changes |
when(name, timeout?) |
Promise resolving when component exists |
onReady(name, callback) |
Callback when component ready |
Form Binding (x-name)
Combines x-model behavior with automatic state creation and name attributes:
Supports nested paths, checkboxes, radios, selects, and modifiers:
File Uploads
| Magic | Description |
|---|---|
$file(name) |
Get single file info |
$files(name) |
Get array of files |
$filePreview(name, index?) |
Get preview URL |
$clearFiles(name?) |
Clear file input(s) |
$formatBytes(size, decimals?) |
Format bytes to human-readable |
$uploading |
Upload in progress |
$uploadProgress |
Progress 0-100 |
Message Display
Display validation errors and notifications from the server:
Array validation with dynamic paths:
Polling (x-interval)
Run expressions at configurable intervals:
Confirmation Dialogs
Configuration Reference
After running php artisan vendor:publish --tag=gale-config, edit config/gale.php:
Environment variables:
| Variable | Default | Description |
|---|---|---|
GALE_MODE |
http |
Default response mode (http or sse) |
GALE_DEBUG |
false |
Enable debug panel and dd()/dump() interception |
GALE_SANITIZE_HTML |
true |
Sanitize patched HTML for XSS |
GALE_ALLOW_SCRIPTS |
false |
Allow <script> tags in patched HTML |
GALE_MORPH_MARKERS |
true |
Inject Blade morph anchor comments |
GALE_CSP_NONCE |
null |
CSP nonce value |
Advanced Topics
DOM Patching Modes
Gale provides 9 DOM patching modes in three categories: | Category | Modes | State Handling | |---|---|---| | **Server-driven** | `outer` (default), `inner` | State from server HTML via `initTree()` | | **Client-preserved** | `outerMorph`, `innerMorph` | Existing Alpine state preserved via `Alpine.morph()` | | **Insertion/Deletion** | `before`, `after`, `prepend`, `append`, `remove` | New elements initialized | **Use `outer` when** the server controls all state (forms, server-rendered content). **Use `outerMorph` when** client state must survive the update (counters, toggles, focus). **Backward compatibility**: `replace()` maps to `outer()`, `morph()` maps to `outerMorph()`. **HTMX-compatible aliases**: `outerHTML` = `outer`, `innerHTML` = `inner`, `beforebegin` = `before`, `afterend` = `after`, `afterbegin` = `prepend`, `beforeend` = `append`, `delete` = `remove`.View Transitions API
Enable smooth page transitions via the browser's View Transitions API: Global configuration: Falls back gracefully in unsupported browsers.SSE Protocol Specification
When using SSE mode, Gale streams these event types: | Event | Purpose | |---|---| | `gale-patch-state` | Merge state into Alpine component | | `gale-patch-elements` | DOM manipulation | | `gale-patch-component` | Update named component | | `gale-invoke-method` | Call method on component | **gale-patch-state format:** **gale-patch-elements format:** **gale-patch-component format:** **gale-invoke-method format:**State Serialization
When making requests, Alpine Gale serializes the component's `x-data` based on `x-sync`: **Serialized:** Properties in `x-sync`, form fields with `name` attribute, nested objects, arrays. **Not serialized:** Functions, DOM elements, circular references, properties starting with `_` or `$`.Global Configuration API
Morph Lifecycle Hooks
Register callbacks to run before/after DOM morphing. Useful for preserving third-party library state (Chart.js, GSAP, TipTip, Sortable):API Reference
GaleResponse Methods
| Method | Description | |---|---| | `state($key, $value, $options)` | Set state to merge into component | | `patchState($state)` | Set multiple state keys (alias for `state(array)`) | | `forget($keys)` | Remove state keys | | `messages($messages)` | Set messages state | | `clearMessages()` | Clear messages | | `flash($key, $value)` | Flash to session + Alpine `_flash` state | | `debug($label, $data)` | Send debug data to debug panel | | `view($view, $data, $options, $web)` | Render and patch Blade view | | `fragment($view, $fragment, $data, $options)` | Render named fragment | | `fragments($fragments)` | Render multiple fragments | | `html($html, $options, $web)` | Patch raw HTML | | `outer($selector, $html, $options)` | Replace element (server state) | | `inner($selector, $html, $options)` | Replace inner content (server state) | | `outerMorph($selector, $html, $options)` | Morph element (preserve state) | | `innerMorph($selector, $html, $options)` | Morph children (preserve state) | | `append($selector, $html, $options)` | Append HTML | | `prepend($selector, $html, $options)` | Prepend HTML | | `before($selector, $html, $options)` | Insert before element | | `after($selector, $html, $options)` | Insert after element | | `remove($selector)` | Remove element | | `js($script, $options)` | Execute JavaScript | | `dispatch($event, $data, $options)` | Dispatch DOM event | | `navigate($url, $key, $options)` | Trigger SPA navigation | | `navigateMerge($params, $key)` | Navigate merging query params | | `navigateReplace($url, $key)` | Navigate replacing history | | `updateQueries($params, $key)` | Update query params in place | | `clearQueries($keys)` | Clear query params | | `reload()` | Full page reload | | `componentState($name, $state, $options)` | Update component state | | `componentMethod($name, $method, $args)` | Call component method | | `redirect($url)` | Create redirect response | | `stream($callback)` | Stream mode (always SSE) | | `when($condition, $true, $false)` | Conditional execution | | `unless($condition, $callback)` | Inverse conditional | | `whenGale($gale, $web)` | Gale request conditional | | `whenNotGale($callback)` | Non-Gale conditional | | `whenGaleNavigate($key, $callback)` | Navigate conditional | | `web($response)` | Set web fallback response | | `reset()` | Clear all accumulated events |Request Macros
| Macro | Description | |---|---| | `isGale()` | Check if request is a Gale request | | `state($key, $default)` | Get state from component | | `isGaleNavigate($key)` | Check if navigation request | | `galeNavigateKey()` | Get navigation key | | `galeNavigateKeys()` | Get all navigation keys | | `validateState($rules, $messages, $attrs)` | Validate component state |Frontend Magics
| Magic | Description | |---|---| | `$action(url, options?)` | POST with auto CSRF (default) | | `$action.get(url, options?)` | GET request | | `$action.post(url, options?)` | POST with auto CSRF | | `$action.put(url, options?)` | PUT with auto CSRF | | `$action.patch(url, options?)` | PATCH with auto CSRF | | `$action.delete(url, options?)` | DELETE with auto CSRF | | `$gale` | Global connection state | | `$fetching()` | Element loading state (call as function) | | `$navigate(url, options?)` | Programmatic navigation | | `$components` | Component registry API | | `$invoke(name, method, ...args)` | Invoke component method | | `$file(name)` | Get file info | | `$files(name)` | Get files array | | `$filePreview(name, index?)` | Get preview URL | | `$clearFiles(name?)` | Clear files | | `$formatBytes(size, decimals?)` | Format bytes | | `$uploading` | Upload in progress | | `$uploadProgress` | Upload progress 0-100 |Frontend Directives
| Directive | Description | |---|---| | `x-sync` | Sync state to server (wildcard or specific keys) | | `x-navigate` | Enable SPA navigation | | `x-navigate-skip` | Skip navigation handling | | `x-component="name"` | Register named component | | `x-name="field"` | Form binding with state | | `x-files` | File input binding | | `x-message="key"` | Display messages | | `x-loading` | Loading state display | | `x-indicator="var"` | Loading state variable | | `x-interval` | Auto-polling / repeating expression | | `x-interval-stop="expr"` | Stop polling condition | | `x-confirm` | Confirmation dialog |Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| "Multiple instances of Alpine" | Duplicate Alpine.js loaded | Remove existing Alpine, use @gale only |
$action is undefined |
Magic used outside x-data |
Wrap in x-data element |
| CSRF 419 error | Token expired or missing | Verify @gale is in <head> |
| State not updating | Key mismatch | Check x-data property names match server keys |
| Navigation not working | Missing directive | Add x-navigate to links or container |
| Messages not showing | Wrong key | Ensure x-message key matches server message key |
| Counter not updating | Missing x-sync |
Add x-sync to x-data element to send state |
| JSON shown instead of page | Missing web: true |
Add web: true to gale()->view() for page routes |
For in-depth troubleshooting, see Debug & Troubleshooting.
Testing
Contributing
Contributions are welcome. To contribute:
- Fork the repository and create a feature branch
- Write tests for any new functionality
- Run the full test suite:
vendor/bin/pest && vendor/bin/phpstan analyse - Format code:
vendor/bin/pint - Submit a pull request with a clear description of the change
Report bugs via GitHub Issues.
License
MIT License. See LICENSE.
Credits
Created by DancyCodes -- [email protected]
All versions of gale with dependencies
illuminate/support Version ^11.0|^12.0|^13.0
symfony/finder Version ^5.4.2|^6.0|^7.0|^8.0