From 09c93bd247b21aff1254a27301433bcbe9c6b021 Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 15 Dec 2024 23:08:35 -0300 Subject: [PATCH 01/23] Docs Tweaks --- docs/broadcasting.md | 11 +++++++---- docs/conventions.md | 11 +++++++---- docs/csrf.md | 7 +++++++ docs/helpers.md | 9 +++++++-- docs/hotwire-native.md | 11 +++++++---- docs/index.md | 16 ---------------- docs/installation.md | 7 +++++++ docs/known-issues.md | 11 +++++++---- docs/overview.md | 7 +++++++ docs/testing.md | 11 +++++++---- docs/turbo-frames.md | 11 +++++++---- docs/turbo-streams.md | 11 +++++++---- docs/upgrade.md | 7 +++++++ docs/validation-response-redirects.md | 11 +++++++---- 14 files changed, 91 insertions(+), 50 deletions(-) delete mode 100644 docs/index.md diff --git a/docs/broadcasting.md b/docs/broadcasting.md index e27a40d..885503e 100644 --- a/docs/broadcasting.md +++ b/docs/broadcasting.md @@ -1,8 +1,11 @@ -# Broadcasting Turbo Streams Over WebSockets With Laravel Echo - -[TOC] +--- +layout: _layouts.docs +title: Broadcasting +description: Broadcasting Turbo Streams +order: 8 +--- -## Introduction +# Broadcasting Turbo Streams Over WebSockets With Laravel Echo So far, we've seen how to generate Turbo Streams to either add it to our Blade views or return them from controllers after a form submission over HTTP. In addition to that, you may also broadcast model changes over WebSockets (or Server-Sent Events) to all users that are viewing the same page. Although nice, **you don't have to use WebSockets if you don't have the need for it. You may still benefit from Turbo Streams over HTTP.** diff --git a/docs/conventions.md b/docs/conventions.md index 5f571a0..79d933f 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -1,8 +1,11 @@ -# Conventions - -[TOC] +--- +layout: _layouts.docs +title: Convetions +description: All the (optional) conventions and recommendations +order: 4 +--- -## Introduction +# Conventions The conventions described below are **NOT mandatory**. Feel free to pick what you like and also come up with your own conventions. With that out of the way, here's a list of conventions you may find helpful. diff --git a/docs/csrf.md b/docs/csrf.md index cabb3a9..1f02609 100644 --- a/docs/csrf.md +++ b/docs/csrf.md @@ -1,3 +1,10 @@ +--- +layout: _layouts.docs +title: CSRF Protection +description: CSRF Protection +order: 10 +--- + # CSRF Protection Laravel has built-in CSRF protection in place. It prevents our app from processing any non-GET requests that doesn't include a valid CSRF Token that was generated in our backend. diff --git a/docs/helpers.md b/docs/helpers.md index 7def225..d29ba21 100644 --- a/docs/helpers.md +++ b/docs/helpers.md @@ -1,6 +1,11 @@ -# Helpers +--- +layout: _layouts.docs +title: Helpers +description: All the helpers the package provides +order: 5 +--- -[TOC] +# Helpers Turbo Laravel has a set of Blade Directives, Components, helper functions, and request/response macros to help making the most out of Turbo in Laravel. diff --git a/docs/hotwire-native.md b/docs/hotwire-native.md index cb8db9c..a8e36e4 100644 --- a/docs/hotwire-native.md +++ b/docs/hotwire-native.md @@ -1,8 +1,11 @@ -# Hotwire Native - -[TOC] +--- +layout: _layouts.docs +title: Hotwire Native +description: Hotwire Native Helpers +order: 11 +--- -## Introduction +# Hotwire Native Hotwire also has a [mobile side](https://native.hotwired.dev/) and Turbo Laravel provides some helpers to help integrating with that. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index a58c7a5..0000000 --- a/docs/index.md +++ /dev/null @@ -1,16 +0,0 @@ -* Prologue - * [Upgrade Guide](/docs/{{version}}/upgrade) -* Getting Started - * [Installation](/docs/{{version}}/installation) - * [Overview](/docs/{{version}}/overview) - * [Conventions](/docs/{{version}}/conventions) -* The Essentials - * [Helpers](/docs/{{version}}/helpers) - * [Turbo Frames](/docs/{{version}}/turbo-frames) - * [Turbo Streams](/docs/{{version}}/turbo-streams) - * [Broadcasting](/docs/{{version}}/broadcasting) - * [Validation Response Redirects](/docs/{{version}}/validation-response-redirects) - * [CSRF Protection](/docs/{{version}}/csrf) - * [Hotwire Native](/docs/{{version}}/hotwire-native) - * [Testing](/docs/{{version}}/testing) - * [Known Issues](/docs/{{version}}/known-issues) diff --git a/docs/installation.md b/docs/installation.md index b48d569..ce2ff24 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,3 +1,10 @@ +--- +layout: _layouts.docs +title: Installation +description: Install Turbo Laravel in your Laravel app +order: 2 +--- + # Installation Turbo Laravel can be installed via [Composer](https://getcomposer.org/): diff --git a/docs/known-issues.md b/docs/known-issues.md index edb0fcf..c24efab 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -1,8 +1,11 @@ -# Known Issues - -[TOC] +--- +layout: _layouts.docs +title: Known Issues +description: Known Issues +order: 13 +--- -## Introduction +# Known Issues If you ever encounter an issue with the package, look here first for documented solutions. diff --git a/docs/overview.md b/docs/overview.md index f9bed08..de22fca 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -1,3 +1,10 @@ +--- +layout: _layouts.docs +title: Overview +description: A quick overview of Hotwire +order: 3 +--- + # Overview It's recommended to read the entire [Turbo Handbook](https://turbo.hotwired.dev/handbook/introduction) before diving here. But here's a quick intro. diff --git a/docs/testing.md b/docs/testing.md index 760aa6a..7b16a9f 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,8 +1,11 @@ -# Testing - -[TOC] +--- +layout: _layouts.docs +title: Testing +description: Testing Helpers +order: 12 +--- -## Introduction +# Testing Testing a Hotwired app is like testing a regular Laravel app. However, Turbo Laravel comes with a set of helpers that may be used to ease testing some aspects that are specific to Turbo: diff --git a/docs/turbo-frames.md b/docs/turbo-frames.md index dc019c5..cde2304 100644 --- a/docs/turbo-frames.md +++ b/docs/turbo-frames.md @@ -1,8 +1,11 @@ -# Turbo Frames - -[TOC] +--- +layout: _layouts.docs +title: Turbo Frames +description: The Turbo Frames Components and Helpers +order: 6 +--- -## Introduction +# Turbo Frames The Turbo Frame tag that ships with Turbo can be used on your Blade views just like any other HTML tag: diff --git a/docs/turbo-streams.md b/docs/turbo-streams.md index 20f1860..ea670dd 100644 --- a/docs/turbo-streams.md +++ b/docs/turbo-streams.md @@ -1,8 +1,11 @@ -# Turbo Streams - -[TOC] +--- +layout: _layouts.docs +title: Turbo Streams +description: The Turbo Streams Components and Helpers +order: 7 +--- -## Introduction +# Turbo Streams Out of everything Turbo provides, it's Turbo Streams that benefits the most from a tight backend integration. diff --git a/docs/upgrade.md b/docs/upgrade.md index 9969d32..ed9ad51 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -1,3 +1,10 @@ +--- +layout: _layouts.docs +title: Upgrade Guide +description: Upgrade from 1.x to 2.x +order: 1 +--- + # Upgrade Guide ## Upgrading from 1.x to 2.x diff --git a/docs/validation-response-redirects.md b/docs/validation-response-redirects.md index be2ddce..d143c87 100644 --- a/docs/validation-response-redirects.md +++ b/docs/validation-response-redirects.md @@ -1,8 +1,11 @@ -# Validation Response - -[TOC] +--- +layout: _layouts.docs +title: Validation Response +description: Validation Responses in Laravel and Hotwire +order: 9 +--- -## Introduction +# Validation Response By default, Laravel redirects failed validation exceptions "back" to the page where the request came from. This isn't usually a problem, in fact it's the expected behavior, since that page usually is the one where the form which triggered the request renders. From 373c4618cc61b85fcdcbb84aaf8e91a7fa7b7abe Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Sun, 15 Dec 2024 23:56:58 -0300 Subject: [PATCH 02/23] Fix docs meta --- docs/broadcasting.md | 2 +- docs/conventions.md | 2 +- docs/csrf.md | 2 +- docs/helpers.md | 2 +- docs/hotwire-native.md | 2 +- docs/installation.md | 2 +- docs/known-issues.md | 2 +- docs/overview.md | 2 +- docs/testing.md | 2 +- docs/turbo-frames.md | 2 +- docs/turbo-streams.md | 2 +- docs/upgrade.md | 2 +- docs/validation-response-redirects.md | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/broadcasting.md b/docs/broadcasting.md index 885503e..9a1676d 100644 --- a/docs/broadcasting.md +++ b/docs/broadcasting.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Broadcasting description: Broadcasting Turbo Streams order: 8 diff --git a/docs/conventions.md b/docs/conventions.md index 79d933f..83e340a 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Convetions description: All the (optional) conventions and recommendations order: 4 diff --git a/docs/csrf.md b/docs/csrf.md index 1f02609..0da5c9a 100644 --- a/docs/csrf.md +++ b/docs/csrf.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: CSRF Protection description: CSRF Protection order: 10 diff --git a/docs/helpers.md b/docs/helpers.md index d29ba21..3066321 100644 --- a/docs/helpers.md +++ b/docs/helpers.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Helpers description: All the helpers the package provides order: 5 diff --git a/docs/hotwire-native.md b/docs/hotwire-native.md index a8e36e4..1324718 100644 --- a/docs/hotwire-native.md +++ b/docs/hotwire-native.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Hotwire Native description: Hotwire Native Helpers order: 11 diff --git a/docs/installation.md b/docs/installation.md index ce2ff24..7c9ee15 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Installation description: Install Turbo Laravel in your Laravel app order: 2 diff --git a/docs/known-issues.md b/docs/known-issues.md index c24efab..f882d3c 100644 --- a/docs/known-issues.md +++ b/docs/known-issues.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Known Issues description: Known Issues order: 13 diff --git a/docs/overview.md b/docs/overview.md index de22fca..22f4a9f 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Overview description: A quick overview of Hotwire order: 3 diff --git a/docs/testing.md b/docs/testing.md index 7b16a9f..d20feb4 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Testing description: Testing Helpers order: 12 diff --git a/docs/turbo-frames.md b/docs/turbo-frames.md index cde2304..537f1ba 100644 --- a/docs/turbo-frames.md +++ b/docs/turbo-frames.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Turbo Frames description: The Turbo Frames Components and Helpers order: 6 diff --git a/docs/turbo-streams.md b/docs/turbo-streams.md index ea670dd..3c9f3fd 100644 --- a/docs/turbo-streams.md +++ b/docs/turbo-streams.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Turbo Streams description: The Turbo Streams Components and Helpers order: 7 diff --git a/docs/upgrade.md b/docs/upgrade.md index ed9ad51..b27c588 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Upgrade Guide description: Upgrade from 1.x to 2.x order: 1 diff --git a/docs/validation-response-redirects.md b/docs/validation-response-redirects.md index d143c87..66fbeee 100644 --- a/docs/validation-response-redirects.md +++ b/docs/validation-response-redirects.md @@ -1,5 +1,5 @@ --- -layout: _layouts.docs +extends: _layouts.docs title: Validation Response description: Validation Responses in Laravel and Hotwire order: 9 From 537cd77e4cc824b15bd810f205ddb56284b749bd Mon Sep 17 00:00:00 2001 From: Tony Messias Date: Mon, 13 Jan 2025 22:34:08 -0300 Subject: [PATCH 03/23] Update docs --- docs/broadcasting.md | 38 +++++++++-------- docs/conventions.md | 16 ++++--- docs/csrf.md | 3 -- docs/helpers.md | 6 +-- docs/hotwire-native.md | 5 +-- docs/installation.md | 6 +-- docs/overview.md | 60 +++++++++++++++++---------- docs/testing.md | 8 ++-- docs/turbo-frames.md | 10 +++-- docs/turbo-streams.md | 14 +++---- docs/upgrade.md | 2 +- docs/validation-response-redirects.md | 6 +-- 12 files changed, 91 insertions(+), 83 deletions(-) diff --git a/docs/broadcasting.md b/docs/broadcasting.md index 9a1676d..dfb9829 100644 --- a/docs/broadcasting.md +++ b/docs/broadcasting.md @@ -5,17 +5,19 @@ description: Broadcasting Turbo Streams order: 8 --- -# Broadcasting Turbo Streams Over WebSockets With Laravel Echo +# Broadcasting Turbo Streams -So far, we've seen how to generate Turbo Streams to either add it to our Blade views or return them from controllers after a form submission over HTTP. In addition to that, you may also broadcast model changes over WebSockets (or Server-Sent Events) to all users that are viewing the same page. Although nice, **you don't have to use WebSockets if you don't have the need for it. You may still benefit from Turbo Streams over HTTP.** +So far, we've seen how we may generate Turbo Streams to either add it to our Blade views or return them from controllers after a form submission over HTTP. In addition to that, we may also broadcast model changes over WebSockets (or [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)). -The key here is that we'd broadcast those exact same Turbo Stream tags we've seen before. Remember, "HTML over the wire." Turbo Stream Broadcasts use [Laravel Echo](https://github.com/laravel/echo) and [Laravel's Broadcasting](https://laravel.com/docs/broadcasting) system. +It's important to mention that this is an optional feature of Turbo and Turbo Laravel. **You don't have to use Turbo Streams Broadcasting if you don't have the need for it** in order to use Turbo. -Since broadcasts are commonly triggered after a form submission from one user, I'd still recommend feeding that specific user back with Turbo Streams (or a redirect and let Turbo refresh/morph) and only send the Turbo Stream broadcasts to _other_ users most of the time. This way, the user making the change will have an instant feedback compared to having to wait for a background worker to pick up the job and send it to them over WebSockets. +We can make our model changes generate Turbo Streams. Yes, the exact same Turbo Streams tags we're used to. Remember, "HTML over the wire." Turbo Streams Broadcasting use [Laravel Echo](https://github.com/laravel/echo) and [Laravel's Broadcasting](https://laravel.com/docs/broadcasting) component. + +Broadcasts are usually triggered after a form submission. You may still return Turbo Streams over HTTP to the user that triggered the form submission, and only send the Turbo Stream Broadcasting to _other_ users. This way, the user making the change will have an instant feedback compared to having to wait for the broadcasting over WebSockets, which may involve queue workers. ## Configuration -Broadcasting Turbo Streams relies heavily on [Laravel's Broadcasting](https://laravel.com/docs/broadcasting) component. This means you need to configure Laravel Echo in the frontend and either use [Pusher](https://pusher.com/) or any other open-source Pusher alternatives you may prefer. If you're not using Pusher, we recommend [Soketi](https://docs.soketi.app/) since it's easy to setup. +Broadcasting Turbo Streams relies heavily on [Laravel's Broadcasting](https://laravel.com/docs/broadcasting) component. This means you need to configure Laravel Echo in the frontend and either [Laravel Reverb](https://reverb.laravel.com/) or a paid service like [Pusher](https://pusher.com/). ## Listening to Broadcasts @@ -29,7 +31,7 @@ You may add this tag to any Blade view passing the channel you want to listen to /> ``` -For convenience, you may prefer using the `` Blade component that ships with Turbo Laravel (it requires that you have a custom element named `` available, since that's the tag this component will render). You may pass the model as the `source` prop to it, it will figure out the channel name for that specific model using [Laravel's conventions](https://laravel.com/docs/broadcasting#model-broadcasting-conventions): +For convenience, you may prefer using the `` Blade component that ships with Turbo Laravel (it requires that you have a custom element named `` available, since that's the tag this component will render in HTML). You may pass the model as the `source` prop to it, it will figure out the channel name for that specific model using [Laravel's conventions](https://laravel.com/docs/broadcasting#model-broadcasting-conventions): ```blade @@ -68,7 +70,7 @@ class Comment extends Model } ``` -This trait will augment any model with Turbo Stream broadacsting methods that you may use to trigger broadcasts. Here's how you can broadcast an `append` Turbo Stream for a newly created comment to all users visiting the post page: +This trait will augment any model with Turbo Stream broadcasting methods that you may use to trigger broadcasts _manually_. Here's how you can broadcast an `append` Turbo Stream for a newly created comment to all users visiting the post page: ```php Route::post('posts/{post}/comments', function (Post $post) { @@ -97,7 +99,9 @@ $comment->broadcastRemove(); $comment->broadcastRefresh(); ``` -These methods will assume you want to broadcast to your model's channel. However, you may want to send these broadcasts to a related model's channel instead: +These methods will assume you want to broadcast to your model's channel. In this case, it would broadcast the Turbo Streams to a private channel named `App.Models.Comments.{id}`. + +Additionally, you may send these broadcasts to any other model's channel: ```php $comment->broadcastAppendTo($post); @@ -110,7 +114,9 @@ $comment->broadcastRemoveTo($post); $comment->broadcastRefreshTo($post); ``` -These `broadcastXTo()` methods accept either a model, an instance of the [`Channel`](https://github.com/laravel/framework/blob/10.x/src/Illuminate/Broadcasting/Channel.php) class, or an array containing both of these. When it receives a model, it will guess the channel name using Laravel's [Broadcasting channel naming convention](https://laravel.com/docs/broadcasting#model-broadcasting-conventions). +These `broadcastXTo()` methods accept either a model, an instance of the [`Channel`](https://github.com/laravel/framework/blob/10.x/src/Illuminate/Broadcasting/Channel.php) class, or an array containing both of these. + +When it receives a model, it will guess the channel name using Laravel's [Broadcasting channel naming convention](https://laravel.com/docs/broadcasting#model-broadcasting-conventions). All of these broadcasting methods return an instance of the `PendingBroadcast` class that will only dispatch the broadcasting job when that pending object is being garbage collected. Which means you may make changes to this pending broadcast by chaining on the returned object: @@ -125,7 +131,7 @@ $comment->broadcastAppend() ->later(); // Don't send it now, dispatch a job to send in background instead... ``` -You may want to hook these broadcasts from your [model's events](https://laravel.com/docs/10.x/eloquent#events) to trigger Turbo Stream broadcasts whenever your models are changed in any context: +You may want to hook these broadcasts from your [model's events](https://laravel.com/docs/eloquent#events) to trigger Turbo Stream broadcasts whenever your models are changed in any context: ```php class Comment extends Model @@ -149,7 +155,7 @@ class Comment extends Model } ``` -For convenience, instead of adding all these lines to achieve this set of broadcasting, you may add a `$broadcasts = true` property to your model class. This property instructs the `Brodcasts` trait to automatically hook the model Tubro Stram broadcasts on the correct events: +For convenience, instead of adding all these lines to achieve this set of broadcasting, you may add a `$broadcasts = true` property to your model class. This property instructs the `Brodcasts` trait to automatically hook the model Turbo Stream broadcasts on the correct events: ```php class Comment extends Model @@ -189,7 +195,7 @@ class Comment extends Model This will send the Turbo Stream broadcast to private channel called `my-comments` when a new comment is created. -Alternatively, you may also set a `$broadcastsTo` proprety with either a string with the name of the relationship to be used to resolve the channel, or an array of relationships if you want to send the broadcast to multiple related model's channels: +Alternatively, you may also set a `$broadcastsTo` property with either a string with the name of the relationship to be used to resolve the channel, or an array of relationships if you want to send the broadcast to multiple related model's channels: ```php class Comment extends Model @@ -330,13 +336,13 @@ From this method, you may return an instance of an Eloquent model, a string repr ## Broadcasting Turbo Streams to Other Users Only -As mentioned erlier, you may want to feed the current user with Turbo Streams using HTTP requests and only send the broadcasts to other users. You may achieve that by chaining on the pending broadcast object that returns from all `broadcastX` methods: +As mentioned earlier, you may want to feed the current user with Turbo Streams using HTTP requests and only send the broadcasts to other users. You may achieve that by chaining on the pending broadcast object that returns from all `broadcastX` methods: ```php $comment->broadcastAppendTo($post)->toOthers(); ``` -Alternatively, you may use the Turbo Facade like so to configure a scope where all brodcasted Turbo Streams will be sent to other users only: +Alternatively, you may use the Turbo Facade like so to configure a scope where all broadcast Turbo Streams triggered inside of it will be sent to other users only: ```php use HotwiredLaravel\TurboLaravel\Facades\Turbo; @@ -365,7 +371,7 @@ class AppServiceProvider extends ServiceProvider } ``` -This only applies to broadcasts generated in an HTTP request, because this relies on having the `X-Socket-ID` header in the request, which Laravel Echo sets automatically. Any broadcast generate from a queue worker, for instance, will always be broadcasted to all users listening on the broadcasted channels. +This only applies to broadcasts generated in an HTTP request, because this relies on having the `X-Socket-ID` header in the request, which Laravel Echo sets automatically. Any broadcast generate from a queue worker, for instance, will always be broadcast to all users listening on the broadcast channels. ## Handmade Broadcasts @@ -483,5 +489,3 @@ turbo_stream() ->append('notifications', 'Hello World') ->broadcastToPresenceChannel('chat.123', fn ($broadcast) => $broadcast->toOthers()); ``` - -[Continue to Validation Response Redirects...](/docs/{{version}}/validation-response-redirects) diff --git a/docs/conventions.md b/docs/conventions.md index 83e340a..443a1eb 100644 --- a/docs/conventions.md +++ b/docs/conventions.md @@ -1,6 +1,6 @@ --- extends: _layouts.docs -title: Convetions +title: Conventions description: All the (optional) conventions and recommendations order: 4 --- @@ -13,9 +13,9 @@ The conventions described below are **NOT mandatory**. Feel free to pick what yo Laravel supports [resource routes](https://laravel.com/docs/controllers#resource-controllers) and that plays really well with Hotwire for most things. This creates route names such as `posts.index`, `posts.store`, etc. -If you don't want to use resource routes, at least consider using the naming convention: render forms in a route names ending in `.create`, `.edit`, or `.delete`, and name their handler routes ending with `.store`, `.update`, or `.destroy`, accordingly. +If you don't want to use resource routes, at least consider using the naming convention: render forms in route names ending in `.create`, `.edit`, or `.delete`, and name their handler routes ending with `.store`, `.update`, or `.destroy`, accordingly. -Turbo Laravel uses this naming convention so it doesn't redirect after failed valitions and, instead, triggers another internal request to the application as well so it can re-render the form returning a 422 response with. The form should re-render with the `old()` input values and any validation messages as well. +Turbo Laravel uses this naming convention so it doesn't redirect after failed validations and, instead, triggers another internal request to the application as well so it can re-render the form returning a 422 response with. The form should re-render with the `old()` input values and any validation messages as well. You may want to define exceptions to the route guessing behavior. In that's the case, set them in the `redirect_guessing_exceptions` in the `config/turbo-laravel.php` config file: @@ -28,11 +28,11 @@ return [ ]; ``` -When using this config, the redirection behavior will still happen, but the package will not attempt to guess the routes that render the forms on those routes. See the [Validation Response Redirects](/docs/{{version}}/validation-response-redirects) page to know more about why this happens. +When using this config, the redirection behavior will still happen, but the package will not attempt to guess the routes that render the forms on those routes. See the [Validation Response Redirects](/docs/validation-response-redirects) page to know more about why this happens. ## Partials -You may want to split up your views in smaller chunks (aka. "partials"), such as a `comments/_comment.blade.php` to display a comment resource, or `comments/_form.blade.php` to display the form for both creating and updating comments. This allows you to reuse these _partials_ in [Turbo Streams](/docs/{{version}}/turbo-streams). +You may want to split up your views in smaller chunks (aka. "partials"), such as a `comments/_comment.blade.php` to display a comment resource, or `comments/_form.blade.php` to display the form for both creating and updating comments. This allows you to reuse these _partials_ in [Turbo Streams](/docs/turbo-streams). Alternatively, you may override the pattern to a `{plural}.partials.{singular}` convention for your partials location by calling the `Turbo::usePartialsSubfolderPattern()` method of the Turbo Facade from your `AppServiceProvider::boot()` method: @@ -53,7 +53,7 @@ class AppServiceProvider extends ServiceProvider } ``` -You may also want to define your own pattern for partials, which you can do using the `Turbo::resolvePartialsUsing()` method. This method accepts either a string pattern or a Closure. If you pass a string pattern, you'll have two replaceholders available: `{singular}` and `{plural}`, which will get replaced with the model's singular and plural names, respectively, when the pattern is used. If you pass a Closure, you'll have the model instance available and you must return the view pattern using Laravel's dot notation convention. The pattern returned from the Closure will also get the placeholders applied, if you need that. Here's how you could manually define the partials subfolder pattern: +You may also want to define your own pattern for partials, which you can do using the `Turbo::resolvePartialsUsing()` method. This method accepts either a string pattern or a Closure. If you pass a string pattern, you'll have two placeholders available: `{singular}` and `{plural}`, which will get replaced with the model's singular and plural names, respectively, when the pattern is used. If you pass a Closure, you'll have the model instance available and you must return the view pattern using Laravel's dot notation convention. The pattern returned from the Closure will also get the placeholders applied, if you need that. Here's how you could manually define the partials subfolder pattern: ```php @csrf - ``` @@ -26,5 +25,3 @@ Since Turbo.js intercepts form submissions and converts those to fetch requests ``` With that being said, you may still want to use the `@csrf` Blade directive if you want to support users with JavaScript disabled, since the forms will still work if they contain the CSRF token. - -[Continue to Hotwire Native...](/docs/{{version}}/hotwire-native) diff --git a/docs/helpers.md b/docs/helpers.md index 3066321..937e543 100644 --- a/docs/helpers.md +++ b/docs/helpers.md @@ -192,7 +192,7 @@ use function HotwiredLaravel\TurboLaravel\dom_class; dom_class($comment); ``` -This function will generate the DOM class named based on your model's classname. If you have an instance of a `App\Models\Comment` model, it will generate a `comment` DOM class. +This function will generate the DOM class named based on your model's class name. If you have an instance of a `App\Models\Comment` model, it will generate a `comment` DOM class. Similarly to the `dom_id()` function, you may also pass a context prefix as the second parameter: @@ -238,7 +238,7 @@ Turbo will add a `Accept: text/vnd.turbo-stream.html, ...` header to the request The `request()->wasFromTurboFrame()` macro added to the request class will check if the request was made from a Turbo Frame. When used with no parameters, it returns `true` if the request has a `Turbo-Frame` header, no matter which specific Turbo Frame. -Aditionally, you may specific the optional `$frame` parameter. When that's passed, it returns `true` if it has a `Turbo-Frame` header where the value matches the specified `$frame`. Otherwise, it will return `false`: +Additionally, you may specific the optional `$frame` parameter. When that's passed, it returns `true` if it has a `Turbo-Frame` header where the value matches the specified `$frame`. Otherwise, it will return `false`: ```php if (request()->wasFromTurboFrame(dom_id($post, 'create_comment'))) { @@ -259,5 +259,3 @@ The `response()->turboStream()` macro works similarly to the `turbo_stream()` fu ### The `response()->turboStreamView()` macro The `response()->turboStreamView()` macro works similarly to the `turbo_stream_view()` function above. It was only added to the response for convenience. - -[Continue to Turbo Frames...](/docs/{{version}}/turbo-frames) diff --git a/docs/hotwire-native.md b/docs/hotwire-native.md index 1324718..902d774 100644 --- a/docs/hotwire-native.md +++ b/docs/hotwire-native.md @@ -11,8 +11,7 @@ Hotwire also has a [mobile side](https://native.hotwired.dev/) and Turbo Laravel Turbo visits made by a Hotwire Native client should send a custom `User-Agent` header. Using that header, we can detect in the backend that a request is coming from a Hotwire Native client instead of a regular web browser. -This is useful if you want to customize the behavior a little bit different based on that information. For instance, -you may want to include some elements for mobile users, like a mobile-only CSS file include, for instance. To do that, you may use the `@hotwirenative` Blade directive in your Blade views: +This is useful if you want to customize the behavior a little bit different based on that information. For instance, you may want to include some elements for mobile users, like a mobile-only CSS stylesheet, for instance. To do so, you may use the `@hotwirenative` Blade directive in your Blade views: ```blade @hotwirenative @@ -133,5 +132,3 @@ return [ ], ]; ``` - -[Continue to Testing...](/docs/{{version}}/testing) diff --git a/docs/installation.md b/docs/installation.md index 7c9ee15..7632408 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -13,12 +13,12 @@ Turbo Laravel can be installed via [Composer](https://getcomposer.org/): composer require hotwired-laravel/turbo-laravel ``` -After installing the package, you may run the `turbo:install` Artisan command. This command will add the Turbo.js dependency to your `package.json` file (when you're using Vite and NPM) or to your `routes/importmap.php` file (when it detects that you're using [Importmap Laravel](https://github.com/tonysm/importmap-laravel)). It also publishes some files to your `resources/js` folder, which imports Turbo for you: +After installing the package, you may run the `turbo:install` Artisan command: ```bash php artisan turbo:install ``` -Note: Turbo used to work with Livewire, but somewhere around Livewire V3 the bridges stopped working. There's an open issue to investigate Livewire V3 compatibility. If you're into Livewire and would love to use Turbo in a Livewire app (maybe you want to augment your Livewire & Turbo app with Hotwire Native or something like that), you're welcome to check out the issue and try to bring the compatibility back. If you wanted an application scaffolding like Laravel Breeze or Laravel Jetstream, checkout Turbo Breeze, our fork of Breeze that sets up a fresh Laravel app using Stimulus, Importmaps, TailwindCSS (via the CLI), and Turbo. +This will add the Turbo.js dependency to your `package.json` file, when you're using Vite and NPM, or to your `routes/importmap.php` file, when it detects that you're using [Importmap Laravel](https://github.com/tonysm/importmap-laravel). It also publishes some files to your `resources/js` folder, which imports Turbo for you -[Continue to Overview...](/docs/{{version}}/overview) +Note: Turbo used to work with Livewire, but somewhere around Livewire V3 the bridges stopped working. There's an open issue to investigate Livewire V3 compatibility. If you're into Livewire and would love to use Turbo in a Livewire app (maybe you want to augment your Livewire & Turbo app with Hotwire Native or something like that), you're welcome to check out the issue and try to bring the compatibility back. If you wanted an application scaffolding like Laravel Breeze or Laravel Jetstream, checkout Turbo Breeze, our fork of Breeze that sets up a fresh Laravel app using Stimulus, Importmaps, TailwindCSS (via the CLI), and Turbo. diff --git a/docs/overview.md b/docs/overview.md index 22f4a9f..254deeb 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -7,28 +7,44 @@ order: 3 # Overview -It's recommended to read the entire [Turbo Handbook](https://turbo.hotwired.dev/handbook/introduction) before diving here. But here's a quick intro. +It's highly recommended that you read the [Turbo Handbook](https://turbo.hotwired.dev/handbook/introduction) first before continuing here. However, a quick intro will be provided here and we'll link to the Turbo documentations when relevant. -Turbo offers a set of components that helps us building modern web applications with minimal JavaScript. It relies on sending HTML Over The Wire (that's the the name comes from) instead of JSON, which is how common JavaScript-heavy web applications do. +Turbo is the heart of Hotwire. In essence, it's a JavaScript library that turns regular web applications (aka. multi-page web applications) into something that _feels_ like a single-page application (SPA). -When Turbo is started in the browser, it will intercet app link clicks and form submissions and convert those into fetch requests (aka. AJAX) instead of letting the browser do a full page refresh. The component in Turbo that handles this is called [Turbo Drive](https://turbo.hotwired.dev/handbook/drive). +It provides a bunch of components that allows us to build modern web applications with minimal JavaScript. It relies on sending **H**TML **O**ver **T**he **Wire** (hence the name), instead of JSON, which is how JavaScript-heavy web applications are built, typically consuming some sort of JSON API. -Turbo Drive is nice when you want to have a full page visits. However, there are times where we want to focus the update on specific elements on the page, without affecting the other existing elements. To achieve that, Turbo adds two new custom HTML tags, which we can use to enchance the User Experience (UX): [Turbo Frames](https://turbo.hotwired.dev/handbook/frames) (``) and Turbo Streams (``). This is all available in the browser when we install Turbo, we only have to use these new tags if we want to. +When Turbo.js is started in the browser, it intercepts link clicks and form submissions to convert those into fetch requests (aka. AJAX) instead of letting the browser do a full page refresh. The component in Turbo that handles this behavior is called [Turbo Drive](https://turbo.hotwired.dev/handbook/drive). -Turbo Frames allows us to scope a Turbo visit to a specific `` element. When inside of a Turbo Frame tag, link clicks and form submissions will **NOT** replace the entire body of the document, but instead Turbo will look for a matching Turbo Frame tag in the response using its DOM ID and replace that specific portion of the page. +Turbo Drive will do the heavy-lifting of the _SPA feel_ in our application. Just by turning it on, the [perceived performance](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance) should be noticeable. The default behavior of Turbo will be to _replace_ the contents of the `` tag in our page with the one from the response it gets from the link or form submission. + +Additionally, since Turbo 8, we can also instruct Turbo to [_morph_ the page](https://turbo.hotwired.dev/handbook/page_refreshes) instead of just replacing its contents by adding a meta tag on the pages we can it enabled: + +```html + + +``` + +Alternatively, Turbo Laravel provides some Blade components to make it easier (and autocomplete friendlier) to interact with these Turbo page configurations: + +```blade + +``` + +Turbo Drive does a lot for us, and with _morphing_ it gets even more powerful, but sometimes you can want to [decompose a page into independent sections](https://turbo.hotwired.dev/handbook/frames) (for different reasons, such as having more control over HTTP caching for these sections). For these use cases, Turbo offers _Turbo Frames_. + +Turbo Frames are custom HTML tags that Turbo provides. You can think of those as "modern iframes", if you will. When link clicks or form submissions happen inside of a Turbo Frame, instead of replacing or morphing the entire page, Turbo will only affect that specific Turbo Frame's content. It will do so by extracting a _matching Turbo Frame_ (one that has the same DOM ID) on the response. Here's how you can use Turbo Frames: ```html

Hello, World!

- - I'm a trigger. My response must have a matching Turbo Frame tag (same ID) - + + Click me
``` -We may also configure Turbo Frames to lazy-load its contents by adding a `src` attribute to the Turbo Frame tag. The content of a lazy-loading Turbo Frame tag can be used to indicate "loading states": +Alternatively, you may want a Turbo Frame to immediately fetch its contents instead of waiting for a user interaction. For that, you may add a `[src]` attribute to the Turbo Frame tag with the URL of where Turbo should fetch that content from. This technique is called [Lazy-loading Turbo Frames](https://turbo.hotwired.dev/handbook/frames#lazy-loading-frames): ```blade @@ -36,7 +52,7 @@ We may also configure Turbo Frames to lazy-load its contents by adding a `src` a ``` -A lazy-loaded Turbo Frame will dispatch a fetch request (aka. AJAX) as soon as it enters the DOM, replacing its contents with the contents of a matching Turbo Frame in the response. We may defer the request so it's only dispatched when the Turbo Frame element is visible in the viewport with by setting the `loading="lazy"` attribute: +A lazy-loaded Turbo Frame will dispatch a fetch request (aka. AJAX) as soon as it enters the DOM, replacing its contents with the contents of a matching Turbo Frame in the response HTML. Optionally, you may add a `[loading=lazy]` attribute to the lazy-loaded Turbo Frame so Turbo will only fetch its content when the Turbo Frame is visible (within the viewport): ```blade @@ -44,33 +60,35 @@ A lazy-loaded Turbo Frame will dispatch a fetch request (aka. AJAX) as soon as i ``` -You may also trigger a Turbo Frame with forms and links that are _outside_ of the frame tag by adding a `data-turbo-frame` attribute in the link, form, or submit buttons, passing the ID of the Turbo Frame: +You may also trigger a Turbo Frame with forms and links that are _outside_ of the frame tag by adding a `[data-turbo-frame]` attribute in the link, form, or submit buttons, passing the ID of the Turbo Frame: ```blade
I'm a link - + ...
``` -Turbo Streams, the other custom HTML tag that ships with Turbo, is a bit different. We can use Turbo Stream tags to trigger some actions on the document. For instance, here's Turbo Stream that appends a new comment into the comments list that already lives on the page: +Turbo Drive and Turbo Frames allows us to build A LOT of different sorts of interactions. However, sometimes you may want to update multiple sections of a page after a form submission, for instance. For those use cases, Turbo provides another custom HTML tag called [Turbo Streams](https://turbo.hotwired.dev/handbook/streams). + +All link clicks and form submissions that Turbo intercepts are annotated by Turbo, which tells our back-end application that Turbo is _on_, so we can return a special type of response that only contains Turbo Streams. Turbo.js will do so by adding a custom [MIME type](https://developer.mozilla.org/en-US/docs/Web/HTTP/MIME_types/Common_types) of `text/vnd.turbo-stream.html` to the [`Accept` HTTP Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept). + +Turbo Streams allows for a more fine-grained control over the page updates. For instance, here's an example of a Turbro Stream that appends a new comment to a comments section: ```html ``` -In this case, this new comment of DOM ID `#comment_123` will be _appended_ into the list of comments, which has the `#comments` DOM ID. All the default Turbo Stream actions, except the `refresh` one, require a `target` or a `targets` attribute. The difference here is that if you use the `target` attribute, it expects a DOM ID of the target element, and if you use the `targets` attribute, it expects a CSS selector of the target(s) element(s). +The `[action=append]` will add the contents of what's inside the `` tag into the element that has a DOM ID matching the `[target=comments]` attribute, so `#comments` in this case. -There are 8 default Turbo Stream actions in Turbo: +There are 8 _default_ Turbo Stream actions in Turbo: | Action | Description | |---|---| @@ -83,7 +101,9 @@ There are 8 default Turbo Stream actions in Turbo: | `remove` | Removes the targeted elements (doesn't require a `