Production-Grade Vue.js Component File Structure
Transcript from the "Component File Structure" Lesson
>> So, pro tip, single file component code block order. Here we have our my first component that we have from earlier, right, we have our template block, our script block, and our style block. And this is typically what we see when we scaffold a vue application and what most people have as their snippets.
[00:00:17] But I'd like to propose that this is actually not the optimum way for viewing our single file components. Because if we think about it another way, when we're modifying our HTML and CSS, for example, right, we go from our template down into our styles and from our styles, back up to our templates.
[00:00:52] So what does this mean? This means that when you're in the midst of styling your application, you're jumping from the template block, all the way down to the style block, then kind of all the way back up, but then into your like. And so the idea here is that the scope of concern's really, as we can see, the shared concern is the template.
[00:01:07] Very rarely are you updating the script blocks, so that you can update the style block. And so instead, what I'd like to propose is going forward, try it out. I would recommend putting the script block on the top first, rather than putting the template because what you end up with instead is, the script can impact the template just as you would normally want to, right?
[00:01:28] V bind V on whatever. But at the same time, when you're, then basically updating styles, you already had that, you've optimized basically scroll space and context switching when use it on, developers are going through hundreds of lines of code. Because I think as we all know, most of the time, the script block is one of the biggest things inside of our components.
[00:01:45] So, rather than forcing us to sort of live with that, there's nothing stopping us from switching it. And so, this is personally how, I like to do single file components. So that's why it's not necessarily a best practice. I'd say, you and your team should give it a try, see how you like it, but I found that as far as the ergonomics from less context switching, this has worked out really well for me.
[00:02:05] All right, so, component file organization. This one is a little bit controversial, experience when I've talked about it. So, typically, when we talk about component organization, most of us are used to nesting everything in folders, right? So this is the traditional nested structure. Here we have our components directory.
[00:02:23] And then we have this is these are our dashboard components. These are our login components. And then we have our test in a different one. And so, while a lot of times when we're trading components, it feels really nice to organize it this way. Instead, what I want to propose to you is to instead, to use a flat structure instead.
[00:02:44] And so there's a couple reasons for this. When we take a look at the two different file structures compared side by side, you'll notice a couple of things. One is that we no longer have any folders and the reason for this is because you'll notice that inside of dashboard and login, one of the things is that there's a shared header.vue component.
[00:03:02] And we talked a little bit earlier about naming components and while like ignoring the one word rule. And one of the problems with this is now you have basically multiple components with the same names, and over time, as we can imagine, as an app architecture scales, you're gonna get more and more folders that basically contains similar components because people will go yeah, I'm working on the shopping cart feature.
[00:03:26] So, I'm just going to build all my components in shopping cart, in my shopping cart folder. And so, as you can sort of hear from that scenario, you lose discoverability. First of all, that's one of the biggest things you lose. Whereas like here on the right hand side, we can see immediately that by the way, there's a generic header component, but there's a dashboard header and there is a, in this case, login header.
[00:03:47] Another thing that flat, we sort of recommend when it comes to like enterprise level applications is rather than keeping your tests in a separate directory, actually having your unit test live right next to the component. And what this allows you to do, as you can see visually is you instantly know when a component does or does not have a test.
[00:04:05] And so especially as we, later on, we talked a little bit about code coverage and those sort of things. This is the kind of thing that we want to make it as easy as possible as it is for developers to instantly recognize when something missing or something can be optimize on.
[00:04:21] And so, in this way, you can see now that we can easily see what has tests, we can see what sort of relationship components have with one another. And when it comes to things like jumping around file. This makes it a lot easier because now you can just do dashboard header, it'll just jump you to the right place.
[00:04:37] And more importantly, when it comes to like refactoring components, you don't have to worry about changing the file path now. So that's another optimization you end up getting by keeping that flat directory structure. Now, while it does all these things as far as making like file structure, like easier, and then finding files is also easier, I know that a lot of people still really enjoy using folders, right?
[00:05:03] And so, what I recommend as a base rule when it comes to sort of working through whether or not nested or flat works for your organization, is to at least avoid going beyond one level deep a folder structures. Because as we can imagine, we go back here, if dashboard inside dashboard you have an admin folder and then the admin folder has more, like you're basically end up scoping your application in a way that you basically kind of lose sense of where everything is.
[00:05:28] And so, I don't know about you all, but when I walk into a code base, it can be overwhelming sometimes to like figure out where everything is, especially when it's heavily nested. And so a hybrid approach to this that some people like like it's okay that like if your team likes having like page level components that like really do scope.
[00:05:47] Then I would still recommend maintaining that sort of like specific component naming, so that it's very clear that a, this is the dashboard header, this is the login header. Because again, when we're importing, like while it's obvious in the directory structure, when it comes to our actual markup, you can't tell the difference, right?
[00:06:05] They both gonna say header if you keep it the way that it's currently in the directory. So, that's like a hybrid way of doing it. And so, something to keep in mind as far as like potential ways to manage that. One exam, so another pro tip regarding this is registering your base components globally.
[00:06:26] And so, as we know, right, when we're doing things as common as import base button, import space icon, this can be a little bit tedious because over time, right, one of the reasons we import components manually is because we're trying to tell the, our build tool that like hey, only bring this in whenever you need to.
[00:06:43] And so in a way, we're basically trying to optimize for performance. But when it comes to base components that are basically like guaranteed to be used everywhere, it helps with the ergonomics is simply just assume that those are available to you, exactly as you would in HTML, right?
[00:06:59] Like imagine if every time you use HTML, you have to import a div element than an H1 element, then a P element, than a button out. Like that would be rather tedious. And so while you might lose out on some, I don't know, you might have, honestly, might not even be noticeable, global registration which was popularized with Chris Fritz is a script that you can add inside of your main.js file.
[00:07:21] That will, so this is specific, but it will basically automatically go through such all of the components that let's say either you prefix with base. And so, as far as what you're wondering like here is the line where it actually does the regex. So you can customize it to whatever your team wants.
[00:07:37] But the idea is it says hey, for these components that we know we're using a lot. We're going to go ahead and register those as global elements so that every file doesn't have to import base button, for example. And so this is a nice optimization for applications. I'm using these base components and something to basically keep in mind.
[00:07:57] And so, as far as the flat nested directory, this is actually one example where I've also seen people will just have a folder for their base components. And so they usually have it like at an underscore base so that it's like alphabetically, like the top thing, and then they'll group everything in there.
[00:08:11] And then again, one thing I can't emphasize enough with the things we talked about today is a lot of these things are like different ideas and perspectives for you to consider for your team. It's not like if you don't import all your global components, your thing is not enterprise grade level.
[00:08:27] No, these are techniques that are supposed to be used to make app development faster because that's what we want, right? We want techniques for our teams that allow us to not only, like basically to move quicker and build quicker, in a way that's sustainable for everyone. So, I can't emphasize that enough and I'll probably be repeating it throughout the day.
[00:08:43] But none of this is hardcore like you have to do this, otherwise you're not enterprise grade. None of that is true. So we have question regarding how, if you're organizing these components, like flat for example and they're all in the same folder, how do you then manage between components using design patterns like factories to generate components.
[00:09:02] So in those regards, that might for example be a great exception where you might wanna go ahead and group your factory components in a single directory, because you're indicating to your team that like hey, we have this set of factory components that are being generated with this design pattern and this is where you can consistently find them.
[00:09:20] So that's how I would probably approach that particular scenario and not mix it up with the rest of the components that might have less, sort of more of that like standard component functionality as opposed to generators. So, that would be my approach to that scenario. So, we also have a question regarding, so someone tried to, similarly move all the unit tests into like the flat directory structure.
[00:09:40] And so when you do that, it is important to go ahead and update like where the tests are being watched inside of the config file. So, this is a great time. So I'd mentioned Chris Fritz who sort of popularize the global import. If you, one of the resources that I mentioned at the end is the vue enterprise boilerplate.
[00:09:57] The vue enterprise boilerplate contains a lot of really like, this is where you're probably going to get a lot of your snippets and basically analysis of code patterns. So, so going forward, so if you want to like, what a lot of people have done is actually take Chris's vue enterprise boilerplate and like basically forked it and then like customize it into their team's needs basically.
[00:10:19] So to the point of like the tests for example, I think this is in his, I think it might be in this just config. So you can see that like in this particular case, he's gone through and actually, I believe he's actually customized some of the pieces for where to watch things, but that is one of the things you would have to change.
[00:10:41] If you wanted your unit tests to also exist on a flat directory structure. So that one is more of a, that one does require a little bit more work but something to, it might be worth doing from like and sort of a, call it an instinct code coverage recognition process.
[00:10:57] And so for those wondering though, I guess I'll just, this question immediately regarding vue enterprise, boilerplate, it is, so it's built and based primarily in vue 2. And basically, I'm going forward we'll eventually be creating a vue 3 version of the vue enterprise boilerplate. But nonetheless, a lot of the ideas in here and the scripts probably work for the most part actually migrated over, but we will have an official vue enterprise boilerplate for vue three in the future.
[00:11:22] So just something to keep in mind as far as the versioning goes. So, there's also a question regarding vues. And so of course, because vue is also called vue, this is a little confusing. And so what first of this question, this is referring to basically page vues. So in, basically we can imagine if we had a vues folder here that contain the various pages.
[00:11:44] So this is when we talk about routing. So you have like a home vue might have like an about vue. So, these components, these vue components would not, they would not apply to that flat directory structure. Because in this case, I would recommend vue is actually really should be its own root level because every thinking from like sort of the atomic design principle like vues encapsulate that page level of like, it deals with routing, right, you might have route guards and those sort of things.
[00:12:15] And then whereas everything components really should be composed into those individual vues. So in that regard, I would recommend vues staying on root level and then components being a separate root level folder by root level, I mean on source. And that way you'll have that separation of concerns.
[00:12:32] So, good question though. Thank you.