در حال بارگذاری ...

Use Case: Slow Invoices0:00

Now, let's take a look at another common use case for server-fetched partials. This is actually the reason that I started getting into them in the first place. I was building a little invoice page for an app exactly like this one, but instead of getting the invoices out of Eloquent, where it's really fast, like right now I refresh the page super fast, I was pulling them out of Stripe. And it took like one to three seconds because I was actually hitting the Stripe API every single time. So I thought, well, I'm not gonna make my users wait three seconds for the page to load, so I'll extract this into a Vue component, show a loading wheel, fetch the invoices from JSON, from the backend, and then show them.

so I'll extract this into a Vue component, show a loading wheel, fetch the invoices from JSON, from the backend, and then show them. But instead, I thought, this is actually a perfect application for server-fetched partials. So let's implement it and then apply some caching so we can make the practice even better. Great. So for starters, this invoices page is way too fast. I want to simulate it being really slow. So here's the route that loads the whole page. I pass the invoices into the Vue. Let's actually go into the model and fake some slowness.

Extract Invoices Partial0:58

I pass the invoices into the Vue. Let's actually go into the model and fake some slowness. So inside the boot method, we'll add a sleep one. So this is just gonna tell PHP to hang for one second when it encounters that sleep function. Now if we reload the page, it takes one second to load. Great. So the next task is to server-fetched partialify this big chunk right here so that we load the page instantly and then fetch it in the background, just like we did in the last video. So let's go to that invoices blade page. And here it is.

So let's go to that invoices.blade.php page. And here it is. Here's the entirety of the page. We're loading Tailwind instead of Bootstrap this time. I have some dummy sidebar content. And then here's the part where I loop through all the invoices and create a table of content. So let's take this table and pull it out into a server-fetched partial. So we're yanking it out. And now we'll create a new partial called _invoices.blade.php. Paste it all in.

Add Fetch-Based Loading1:53

And now we'll create a new partial called _invoices.blade.php. Paste it all in. So then inside here, we can write our plain little script tag and use the fetch API to fetch it from the server. So fetch partials/invoices. And then down here, we'll use document.querySelector to get some ID out of the DOM and then innerHTML equals the HTML we get back. So let's create an ID. We'll say jsInvoicesPartialTarget. Copy that ID.

We'll say JS invoices partial target. Copy that ID. Paste it in right here. And there we go. Last step is to actually create the endpoint that serves that partial. So partials/invoices endpoint. So we'll duplicate the original one. And paste it in right here. And now instead of serving the invoices page, we're just going to serve the partial. And now the original one doesn't actually need to load any data because it's just fetching

Switch to Include Fragment3:54

It's so lightweight. It's so simple. I love it. So to pull this into our project, the first step says installation, npm install. But I really don't want to deal with npm or Webpack or any of that just for the simple little tool. So I want to show you a different tool called Unpackage that allows you to take these npm packages and turn them into basically little CDN links that you can pop into your site. So let's do that. We're going to create a script tag and set the src to https://unpkg.com/.

So let's do that. We're going to create a script tag and set the source to HTTPS, unpackage.com slash. And now we're literally just going to paste in that package name at GitHub slash Include Fragment Element. Beautiful. And now we have access to it. So let's replace everything we just did with that new tool. OK, include fragment. And then we're going to add the source attribute as that path. So partials/invoices.

And then we're going to add the source attribute as that path. So partials/invoices. And we'll add a little bit of a loading state just for kicks. OK, refresh the page. Check it out. Loading. And then the fragment with a lot less JavaScript. We wrote zero JavaScript. We just included this little lightweight package. Super nice.

Build Loading Placeholder6:27

Maybe fade this out to show that it's a loading state and then load the actual content. And because we're using Tailwind, this kind of thing is actually pretty easy. So let's just build it out. Cool. So instead of loading, I'm going to take that invoices partial and paste it in right here. And now instead of actually loading real invoices, I'm going to generate a random array. So I'll say range. This is a php function to generate an array of numbers from one to whatever. So let's say from one to 10. And the purpose of this is just to create an array with 10 items.

So let's say from one to 10. And the purpose of this is just to create an array with 10 items. So I don't actually care about those numbers. And then inside here, let's actually get rid of a bunch of this boilerplate. Okay. Inside here, we're just going to say someTitle. So someTitle. We don't actually care about font styling at the moment. And then for the money, I don't know, let's say 123.45 cents. And again, we don't care about font styling.

Like one, I want the different lengths to be staggered and I want them a little bit longer. So to get those staggered lengths, instead of passing in a static title, I'm going to generate a random string from 10 to 30 characters. So php has str_repeat. So we'll say str_repeat, and then you can pass in a character that you want to repeat. And then a number of times you want to repeat it. And in our case, we want to repeat it a random number of times. So we'll say rand(10, 30). And now if we refresh, check it out much cleaner.

So the last little touch is adding a little fade out to this table to show that it's kind of more in a waiting state than actual content loaded. So we'll create an overlay div, and I'll style it in the browser to serve as kind of a fade out and show you exactly as I go. Okay, so here's our empty div. And for starters, we're going to give it a background color of black, just so we can see it as we style it. We'll make it absolutely positioned and inset: 0, which is going to set top to 0, right to 0, bottom and left. So there we go, we have this overlay.

to zero, bottom and left. So there we go, we have this overlay. Now instead of BG black, I want to create an actual gradient background. So you can do this in CSS with background-image, linear-gradient, okay. So right now the angle is a little off, and it's going to black instead of transparent. So let's change black to the actual background color, which is going to make it look transparent. And then instead of 45 degrees, we'll make it zero degrees. Okay, and there we go. We have a nice little fade out from top to bottom. So let's take this entire element and copy the outer HTML and then paste it in right.

We have a nice little fade out from top to bottom. So let's take this entire element and copy the outer HTML and then paste it in right here. Okay, and there we go. So there is our placeholder. One last little cleanup measure is we'll take this and we'll put it into its own little Blade include. So include invoices/placeholder.blade.php. Okay, there we go. And we can re-include the fragment, load the page and check it out.

Cache the Rendered Partial10:39

Okay, there we go. And we can re include the fragment, load the page and check it out. We have a nice little inline loading placeholder and then our meaningful content. Really nice. So let's actually cache this partial so that when we load it, it's instant. So if you take a look at include fragment that read me a little further down, they talk about different patterns where you'd use this. And so GitHub says the first time a User visits a page that contains a time consuming piece of markup, in our case, it's that little invoice table, a loading indicator is displayed, okay, we've done that.

you don't have to load it every single time. So let's go ahead and do that and implement some caching. So to get started, why don't we just cache this view that we're returning from this endpoint, so that every time we load the first time it takes a second, but then subsequent times it just loads instantly. Alright, so we're going to use Laravel's caching features, cache, remember, and then you pass in a key, and then some amount of time in seconds, so let's say 10 seconds, and then a callback, where you return the thing that you want to be cached. And if Laravel detects that there's something existing already for the key, it'll just return what it has cached.

And if Laravel detects that there's something existing already for the key, it'll just return what it has cached. If not, it'll regenerate the cache and return the value. Really nice, really simple inline. Alright, so for a key, the general convention is to use a dot syntax to kind of namespace your cache keys. So we'll say partials.invoices. And now the other little thing that's a little weird is this says 10. And I happen to know that the key is 10 seconds, but honestly, I have to look it up every time. I don't know, is this minutes or whatever.

confusing. So here's my favorite pattern for specifying cache expiration times. So you can use Carbon::parse, actually. So Carbon::parse, then you can pass in a string, like 10 seconds, and it'll just work. Because the second parameter to cache()->remember can also be a date time in the future. So Carbon::parse 10 seconds means cache this until 10 seconds from now. And so if you wanted to switch to minutes, you could do minutes or months or anything you wanted. So I think this is really nice and expressive reads really well. Okay, so let's try this out.

So I think this is really nice and expressive reads really well. Okay, so let's try this out. We're going to load the page and we should see it load. But we don't, there's an error. So let's actually load the partial in a separate tab and see if we can get a little bit nicer error message. partials/invoices takes a second and it says serialization of closure is not allowed. And if you dig in, when we're trying to put the thing in the cache, it's using php serialize on our view, presumably this view object, and it's not working. So if we open up php artisan tinker, and try out serialize, if you pass in a string, it

on our view, presumably this view object, and it's not working. So if we open up php artisan tinker, and try out serialize, if you pass in a string, it works great. If you pass in an object, it works great too. But if you pass in a closure, so just an anonymous function here, it's going to say exception with message serialization of closure is not allowed. So because of that, we can deduce that somewhere inside this view object, there's a closure, and php is throwing a fit when it encounters it. So I think for that reason, we don't want to wrestle with php and try to get it to cache this.

So I think for that reason, we don't want to wrestle with php and try to get it to cache this. We just want to render the view into a string, cache the string, and then load the string. So to get a string out of a view is actually super simple. This is one of the lesser known little features, but anywhere you want, you can render a view and then just chain on ->render(), and it'll spit out a string. Okay, so now let's refresh and see what happens. There we go. It's working again. So now when we reload the page, it should get it out of the cache.

So why don't we try to get that out of the cache in the original page load, and then show it if we have it. So we'll create a key called cachedInvoicesPartial that's set to cache()->get('partials.invoices'). Okay. And now inside of the view itself, we can wrap this up inside of an if statement, we'll say if ($cachedInvoicesPartial). And echo that out, else, echo out our little @include fragment. Okay, so we load the page. And now we reload.

Okay, so we load the page. And now we reload. And oops, we have something weird going on. Instead of getting the HTML rendered out as DOM, we're just getting the HTML itself. So if we take a look at the source that actually gets returned view page source, look at this, there's all these at less than and at greater than instead of actual less than and greater than symbols. So this is because Blade, whenever you're echoing out in Blade, it's doing an extra level of security. It's escaping whatever you pass through it, so that users can't store like a script tag.

level of security. It's escaping whatever you pass through it, so that users can't store like a <script> tag that has cross site scripting attack or something like that. So this in Blade actually translates to echo E cachedInvoices partial. That's what this compiles to. And that E method is something built into Laravel to encode HTML special characters in a string. It uses htmlspecialchars, a PHP function to wrap up strings in safe HTML characters. So let's just take a look at that for fun. htmlspecialchars we say hey, it spits out hey, but then we pass in a <div> and we get

So let's just take a look at that for fun. HTML special cares we say hey, it spits out Hey, but then we pass in a div and we get at less than and add greater than. Alright, so that's not what we want. And to bypass that, there's another Blade syntax where you pass in two exclamation points. So {!! !!} and then !! {!!. Okay. Now let's try this again. We try to load the page. Okay, now it's in the cache refresh.

It's so clean and reliable to me about it. We've taken what would be a pretty complex operation, creating a view component or React component to wrap up something and defer loading and show a loading wheel and everything. And we've boiled it down to just simple Blade, we've written no JavaScript by hand, and everything's in php. So it's still really testable, just like I showed you in the last video. So there we go. Another really cool application for server fetched partials. Until next time.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟