hotwired-laravel / turbo-laravel

This package gives you a set of conventions to make the most out of Hotwire in Laravel.
https://turbo-laravel.com
MIT License
803 stars 50 forks source link

Investigate ways of only rendering the layout's content (slot) on Turbo Frame requests #40

Closed tonysm closed 1 year ago

tonysm commented 2 years ago

Requests done inside a Turbo Frame have a special Header, such as Turbo-Frame: post_311. By detecting if this header exists, we can programmatically avoid rendering the layout and only render its contents.

One "simple" way of doing this would be to parse the response content and remove only the Turbo Frame it wants from it and return, which would result in less data being sent through the pipes.

However, I think the best way of doing this would be to find a way to not render the layout at all, so we don't spend computational power in there. Also, if users have things like View composer or are making use of lazy-loading relationships and things like that, those wouldn't even execute, to begin with.

tobyzerner commented 2 years ago

I achieve this in my app by wrapping all my views in an <x-layout> component, and putting logic in that component to determine whether to render the layout vs. just the slot. The component looks like this:

Layout.php:

use Illuminate\View\Component;

class Layout extends Component
{
    public function __construct(public ?string $title = null)
    {
    }

    public function render()
    {
        // If the current request is intended to retrieve the contents of a
        // Turbo Frame, then don't bother rendering the layout chrome.
        if (request()->header('Turbo-Frame')) {
            return '{{ $slot }}';
        }

        return view('components.layout');
    }
}

components/layout.blade.php (simplified):

<!doctype html>
<html>
<head>
    <title>{{ $title }}</title>
</head>
<body>
    {{ $slot }}
</body>
</html>

And then my views all look like this:

<x-layout :title="Hello">
     <h1>This is the page content</h1>
</x-layout>

Not sure how this could be applied in the context of a package, but just posting here in case it sparks some inspiration.

tonysm commented 2 years ago

@tobyzerner that's exactly how I was thinking this could be solved, but I haven't had the time to test it. Thanks for testing this out!

tonysm commented 1 year ago

Closing this because:

  1. I think the answer shared here is enough
  2. I don't think this is the default way in turbo-rails anymore (and makes sense, as responses for Turbo Frames might return meta tags)