Briefly, in the previous articles I described the web app I started working on – mainly based on this fantastic Docker tutorial. You can find my repository here: github.com/wforbes/node-docker, with ample step-by-step notes in the README file. In the last post I added a Vue container into the mix and got it hot-reloading on my local dev environment.
In this post, I’ll be sprucing up the Vue app with the UI library Vuetify, setting up the project structure and doing some of the initial work on the app. Let’s get it.
Side note: I’ll start including links to the commits from what I mention in this article. That way you can jump right over to see the code changes, browse the files, or pull that commit to see the code in action.
Adding Vuetify to the vue-client app
Vuetify is a UI library based on Material Design. It’s easy to get started with and provides a ton of great components right out of the box. I’ve been using it at my day job for over 2 years now and I’m a huge fan. Their documentation is amazing, as it includes a “UI Components” section with awesome examples for every component in the library. Sample code is provided with various ways to use each component. A++!
We’ll pick it up from this commit.
Commit #48: “Remove vue client folder to recreate it with vuetify”
I had a problem. When I initially added Vuetify to the project and started moving stuff around I eventually found that it wasn’t building with scope of the Vuetify colors, components, and basically anything else. I suspect that I wasn’t adding it to the Vue instance or there was something else amiss. Instead of spending too much time tracking down the issue, I opted to simply recreate the Vue project. I wanted to rename it to ‘client-vue‘, which leaves room to create other clients in the future. We’ll continue from there.
Commit #49: “Readd vue project to the client-vue directory“
First things first, I added my preferred linting settings to the /.eslint.js file.
Commit #50: “Vue – Add lint settings“
Then we hop into the terminal, make sure we’re in the client-vue directory and run:
vue add vuetify
This will add the Vuetify dependencies and give you a boilerplate starter project that’s similar to the Vue boilerplate starting code, but utilizing Vuetify!
Commit #51: “Vue – add vuetify“
Running the command: npm run serve will give us a that boilerplate app on your localhost…
Modifying the home page
Next, I went ahead and modified the /components/HelloWorld.vue file to reflect this actual project. No design changes, just content. Linked the github repo, found some tech icon graphics at https://vectorlogo.zone/, added some dummy links to modules that I intend on adding soon, and linked the original Docker tutorial that inspired this project.
Commit #52: “Vue- update main page, add multiple tech logos“
Then, I updated the app title in the app bar component to node-docker… it has a ring to it, doesn’t it? Just rolls off the tongue…
Commit #53: “Vue – Fix app bar title link“
Making a case for a Feature-Based Directory Structure
Let’s talk about how to arrange the files of the project.
Now, I understand that the Vue core team developers really support a ‘flat’ file structure. That means you have one /components directory, one /views directory, and most of your code sits in those. That’s what the boilerplate code we’re looking at is set up with. That’s how many of the main Vue community projects are structured with. This comprehensive VueSchool.io article explains it in the “A Flat Component Directory Structure” section… but when your project starts to scale up, you end up with this:
I guess it’s easier to find files… because they’re basically all in one place… but I’ve found that it really makes it hard to tell what files are used for what area of the app, aside from making sure to prefix all the file names like you see in the image above.
In my opinion, the main downside to this is that any Vuex modules or Views that are directly related to these components are separated from them in their /store or /views directories. Again, with a prefix on the file names that’s probably not a huge issue… but it further obscures what files are used for which area of the app. If you wanted to move the “Search” related functionality into another app you’d have to grab 3 files here in the /components directory, a file from the /store directory, and then maybe another file from the /views directory. Adding a new feature means the same hopping around, and well… I just don’t like it personally.
I concede that it makes complete sense to put small components that get reused throughout many pages of the app into a /components directory. That’s clear, and I support that… but until you know which components can get optimized into their own files and reused, I don’t support prematurely structuring things this way.
ALRIGHT! With that out of the way, here’s what we have with the vue add vuetify scaffolded project. The HelloWorld.vue file is in the components folder, the two full pages Home.vue and About.vue are in the views folder, and our App.vue is hanging out in the root /src folder….
And this is what I initially change things to when starting up a new project. The content of the HelloWorld.vue file is now in the Home.vue file, the Home.vue and About.vue files are in the /home/views/ directory, and the App.vue file is in the /app directory.
“So what’s the big deal?”, you might be thinking. Well with only 3 files, its hard to see the advantage – I know. Let me show you an example of an old project that uses the ‘feature-based’ directory structure I’m talking about. I do things a little differently now, but this still carries the main idea:
Each folder in the /src directory relates to a ‘feature’. I’ve expanded the /src/activities/ and /src/app/ folders in the example. ‘Activities’ relates to a main module, or feature of the example app. Then, as you’d imagine, the App directory contains everything related to or reused across the app. In each of these feature folders there’s a /views, /components, and /models (aka /store) directory.
This way, if I ever need to fix or add a component on the Activities page… I can jump right to that directory, open up the components folder and easily get it done. If I ever wanted to move the core App-wide code into a new project, I can just copy the /app directory over and get started. With all of a feature’s code modularized in the same place it makes it possible to move any one of them into another app, remove it, or replace it with a new version.
As this project unfolds, you’ll see this directory structure in action.
Commit #54: “Vue – move files into feature-based directory structure“
Setting up the AppBar and NavMenu components
For my final stunts tonight, I’m going to be moving the <v-app-bar> from the App.vue file into it’s own /src/app/components/AppBar.vue file. Then I’ll be setting up a vertical slide-out navigation menu in the /app/components/NavMenu.vue file.
For some added bonuses I’ll set a Vuetify color theme, add a favicon and little basic logo from https://favicon.io/, and add icon graphics in the app bar and nav menu.
This is fairly straightforward.
Copy and paste the <v-app-bar> markup from App.vue into the new AppBar.vue file, import and reference that component file in App.vue. That’s Commit #55. (I also added the Vuetify color theme there)
Create the NavMenu.vue file and use the <v-navigation-drawer> component to set up the start of our nav menu. Import and reference NavMenu in the AppBar file. Set a prop for open and emit handler for close on the <nav-menu> tag in AppBar, tie that up to a <v-app-bar-nav-icon> element (that appears as the menu button on the app bar), and away you go. I added one navigation item for the “About” page for good measure. That’s Commit #56. (I also included the favicon files from favicon.io and added them into the project)
This is the result… NavMenu closed:
And with the NavMenu open:
I hope that breezing through this stuff what somewhat helpful to you and being able to browse through the commits gave some insight. Forgive me for soapboxing about directory structure, but I’ve found it really beneficial after a couple years of working in Vue every day at my day job.
Next, I’m aiming to build out a signup and login component so we can start hitting the API… then figuring out the best way to build for production with Docker!