Blade includes vs components: how we decide
Welcome to No Compromises. A peek into the mind of two old web devs who have seen some things. This is Joel.
And this is Aaron.
There's a bunch of different ways to build front ends with with Laravel. I like Blade. Aaron, you and I are on the same page here. We kind of lean on it. We've done projects with view and other things, and those are fine. But if it's our choice, we're going to lean on Blade. And one of the things we could talk about today it has to do with how do you use Blade effectively to keep a well-maintained front end? We have a couple different mechanisms. We could include files, we have Blade components. I want to talk back and forth because sometimes it's a little fuzzy for me when we reach for one versus the other, and what the reasons are for that, but I think it could be an interesting discussion.
I think that is a interesting point. How do you decide which one of these tool sets that are available in Laravel what to use? And you kind of touch on it. It was like, how do you first decide what we want to do for the front end? And one of the things that maybe is implicitly underneath what you said is, we'll pick the simplest tool for the job. A lot of time, there are projects that require view front ends and stuff like that, and we do them and whatever, and it's when that is the requirement for the job. But we want to move to the simplest version of something to keep our project moving forward, our momentum, make it easy to maintain, and stuff like that. As you kind of start building out these things in Blade, you'll start to run into duplicate code, things like that. So that's kind of where I think we come into this idea of includes, Blade includes versus components and things like that. Maybe it makes sense to talk about what we're even saying when we say include?
Like, try to describe the actual code. I'm thinking of the Blade directive at include, and then you pass it a view name.
And there's @include, and you pass it a view name. There's like, include if, and there's a couple other permutations of them. There's even, I think, the ability to fall back, if my view doesn't exist, do a different one. There's a lot of flexibility there. And then there's also the other option we have is Blade components, which you'll see a lot of times, that'll be possibly a PHP class and a Blade file. Or, it might just be a Blade file, and you recognize those in the code by X_ whatever the name of the component is. There's two different ways to kind of encapsulate some of the code. Follow me so far?
I am. And not to throw a pop quiz at you, but I think it'll be relevant to the discussion. Blade components are a newer thing, right? Like, not super new, but it used to be a package, right? If you wanted to have Blade components, you had to bring a package in and then Laravel... Was it one of the Laravel 5 or 6? It was pretty early on? It came later. Like, include certainly existed before Blade components did.
Yeah. Include was around forever, and then Blade components were... I remember that it was like, "Oh, where would I use this?" And then seeing a giant Blade component around our content and sort of in our startup packages that they give you, and stuff like that.
That app layout or whatever, yeah. But yes, I am tracking with you, and I think we've explained it well.
So the question that comes to my mind is, if I had these two tool sets, which one do I use and why? I mean, that's kind of what you said, "How do I know which one to pick?" right?
Right, exactly. And not just which one do I pick as, like, "Oh, I always use one or the other," but what is the heuristic? When would I choose X versus Y, and why specifically am I doing that? Those are things I like to have established in my brain to make it easier when I'm programming.
Exactly. I'm going to give you a little bit of insight into how I choose which is which based off some of the features that both of them have. The first thing is, let's just come up with this idea. I have this layout on my screen, and there is a bunch of rows of data. And then on maybe the right-hand side, there is information about the created and updated, and stuff like that, about maybe a parent thing. Basically, there's generic information on the right-hand side and there's specific information on the left.
I'm trying to picture this. The fields, the inputs for the form, are on the left, and maybe the right is kind of read-only metadata?
Nope, no form. We have a table of rows, and on the right-hand side, there's metadata about something else.
Got it. So, it's read-only in both cases. Okay.
Yeah. So when I start to build out these rows of results, I might look at that and say, "Wow, in my blade file, there's so much around this table." I have stuff on top, there's a card where I'm describing stuff. Then I have my table, and then every row in my table has maybe 10 columns. And there's so much logic inside of those.
[Unintelligible 00:05:13].
Yeah. Before you know it, my blade is thousands of lines long. And I'm looking at that going like, "Ah, what is taking up so much room?" And it turns out it's maybe each row where all the calculations happen, where we display this is 500 lines. I'm going crazy with the amounts here to generate to give you an idea of the context. But let's just say there's 500 lines that are required to generate a single row. When I look at that, I start thinking, "Okay, maybe I want to move some of this code into somewhere else so it's not always in my face." I know that in general I have a card on this thing, I have a table, I have other functionality, I have the sidebar, so I don't need that all in my face. I have a general idea that I'll look at the card section, or I'll look at the table section, or I'll look at this, and then maybe I'll drill into that thing if there's something I need to deal with. When I start looking at which one of those tool sets can I use to move some code somewhere else, I look at maybe what are some of the features of that functionality. Well, in this case, I'm not looking for reusability, I'm not looking for anything else. I just want a little bit of separation in my code. I just kind of want to put things in their own little buckets. Maybe then I'll start using something include. And the reason for that is that it understands the context of the current Blade it's in. So when you include it will get all the context of everything that's there. All the different variables, all that as if they were in the main Blade file, are now in your include file. You can pass in additional things if you want, but it's just basically saying I include... Almost like a PHP include. It's just saying, I am now in this context, but I'm in a different file.
Let me pick a couple things out of that. I like how you specifically called out, you're not extracting this to an include because, "Oh, I'm going to reuse it in another table and somewhere else." It literally is to sort of make the file more approachable, to be able to scan it and more quickly see what's happening. Like, I'm taking this big chunk of code and collapsing it to the name of a view, and I'm like, "Oh, table row. I know what that is." If I need to know specifically what's in the table row, I click through to it. It's cleaning up the file, it's not about reuse at this point. That tracks a lot with me, and I can see why you would do that.
There are times when we might use it for reuse.
Sure.
But that's only in very specific scenarios. For example, a create form and an edit form where they're basically the same thing. In my Blade, I'll put the form logic inside of an include file, and then in my create, it's just including that thing. And maybe in my edit, it's including that thing, and it had a little bit of metadata about the file as well.
Yeah. So it could be for reuse, it's just that's not a requirement. In your mind, I wouldn't only extract something if it's because it's reused. It could literally just be to organize the code and make it easier to understand.
Yep. Then, like I said, the other functionality or feature is it does retain all the context.
I'm going to use a different word. Because you say context, but... and maybe it's just the programmer nerd in me, but we're talking about scope, right? It can see all of the variables that the parent Blade has in it are all present in the included Blade as well.
Correct. Which is both a positive, knowing what we're trying to do here, but it could be a negative. And that would be why someone would be like, "I don't want that," and that's kind of why we're going to talk about the Blade components.
Sure. Hopefully, this isn't too much of a tangent. But I recall I was doing something where I was pulling in include, and I was passing in two variables that were already in scope. And you're like, "Why are you doing that?" I like doing it because it made it clear to me, like, what are the ones it relies on? But you still don't like that approach because it's like redundant and it's just fooling yourself. I seem to recall that was your argument against it at the time.
I mean, it was a nice sort of hint. Like, "Oh, this is what you do." But I mean, it didn't... In my mind, if I saw two variables coming in, my mind says those are the only two variables I have available to me then.
Okay, sure.
And then I wouldn't expect to have other ones in there, and when I do, that confuses the scope for me.
Exactly. And you convinced me when we argued about it before. But I think I thought it was clever. Like, "Oh, I'm kind of self-documenting how this works," and you're like, "Joel, no, you're not. Just stop it."
Well, it does kind of bring us to the other thing, which is the Blade component. In my initial setup, I know it was kind of confusing, but I kind of said, "This is a specific thing on the left-hand side and there's more abstract stuff on the right-hand side." I'm going to go maybe to that edit form. Let's use that as a better example. On our edit form, we have included form, but on the right-hand side, we have maybe something that says, "This thing you're editing was created at this date, and it was updated at this date." You know, getting that metadata out of the thing and just showing it on the screen for niceness. The format of that is probably going to be the same on every single edit. The edits form itself will change, but the format of the metadata will always be the same. The other thing about that is every single model I'm editing is different. In my edit form, I might be referring to $ client, in another form I might be referring to $ company, another $ user. If I was doing an include, I won't know what variable is coming in there then. So we could do what you said, which is pass in another new variable, but this kind of is now where I make my decision to start working with a Blade component. Because I have an abstract piece of logic that I want to componentize that deals with a very recognizable form of data, but it is different. So it's not always a client, it's not always a user, but they always have the same sort of things, almost a contractor interface. And that's when I kind of start putting that stuff into a component because I know that I want to pass in something. Like, I want a property called model, and I'll pass in my client, I'll pass in my user. And then in that component, all it has in its scope is the thing I passed in, and all it will do is display the created and updated information.
Right. You've normalized what that variable name is going to be called in a predictable way, and you've sort of isolated from all the other scope that's coming in from the parent Blade too. Because it can only see the thing specifically that you pass in, whereas with include it sees everything.
Yep. It's about scope, and it's about is this actually an abstract or reusable thing. Or, is it just a thing for my current Blade or workflow, or something like that?
I'm going to just throw something at you. Do you ever think about performance in terms of include versus Blade component? Or, is that just such a far minimal... Like, a niche thing to worry about? Because I think they do have different performance characteristics too. If you were doing that table row and you had a million rows or something, I think it would perform differently with includes versus Blade components.
Honestly, I don't really reach for that unless I really have to. I don't really think about that because more often than not, it's not my Blade components that's the bottleneck, it's something else.
That's true. I was maybe thinking of it because I know in some projects, not ours, but I was talking to somebody that actually was their bottleneck. But I don't personally run into that myself, but I can see how it would happen. Especially if you have nested within nested within nested, and now that whole thing is in a loop. And all of a sudden, you have 50,000 Blade components on a page.
And that might have been. Like I said, there's a reason why you might do specific versions. It could have been a performance issue, but it also could have been maybe that isn't the way that it should have been done.
That's right, yeah. It's sort of going too far with components.
Or includes. And then saying, "I don't like this tool because it didn't work for me, and it's really strange situation that I shouldn't have done anyway."
Yes, blame the tool when it was actually your decisions on how to use that tool. All right, I'm glad we talked about this. Because it's more clear in my mind and it's been a little fuzzy in the past. But I'll summarize it this way. If all we're trying to do is basically organize a Blade file into smaller chunks to make it easier to understand, but we conceptually want to treat the whole thing as one Blade file, reach for an include and/or its variance. Include if, et cetera. If we're really trying to encapsulate something and not expose it to the outside world, control what comes into it, or reuse it in multiple different contexts, that's when we'd reach for a Blade component.
I couldn't have said it better myself. There's some customs that we have that are, I guess, just accepted and normal, but if you think about introducing them brand new now, everyone would think you're just crazy. One of them I think about is the idea of trick-or-treating with Halloween. For those who don't know, Halloween celebration of, I don't know, evil. That something-
No, let's be honest. It's a celebration of candy. That's what it is.
Well, that's what I was getting to. There's a reason that it happened, but I don't remember because, whatever. But it's about candy now. Let's go and go trick-or-treating. And trick-or-treating is you walk different houses as kids and ask for candy, and people give you candy, and you're dressed up. And I just wanted to describe that in case someone didn't know what it was. But I also wanted to describe what it was real quick, because that's crazy. I mean, think about it. We tell kids and everything, "Don't talk to strangers, don't eat random food," whatever. It's really weird of someone saying, "Oh, you're such a cute little kid," randomly. And then on this one day, we're like, "Hey, kids," that don't have a lot of cognitive ability, "please forget everything we've been teaching you and now dress up, go to random strangers, eat their food." You can imagine introducing-
At night.
At night. Can you imagine introducing that now? People would be like, "What? No, we're not going to send their kids to some random house."
Yeah. There would be a backlash against trying to do that. When you put it all together like that, it sounded absolutely insane.
For all the Blade lovers out there like us, are you jiving with what we said, or do you have a different opinion?
We'd love to hear it. If you have other ways that you make a decision between includes and components, let us know. We'd love to hear your feedback.