At this point we have supercharged our IDE environment and setup a default project boilerplate/structure for our future applications. Now it’s time to leverage these optimizations in a new project.
One of the things I see mostly when I work with developers are overly complex components and monolithic features that only become more difficult to work in over time. In this article we will discuss ways to alleviate spaghetti components and make our code more maintainable, extensible and testable.
Proper planning of your application structure removes early bottlenecks. When building out a project, I highly recommend having a mock-up to reference. Even something simple helps with visualization as you start to setup the underlying functionality of your app.
Creating a new project
Let’s start by creating a new project using the preset we created in Part 2:
vue create my-project --preset vuetifyjs/vue-cli-preset-vuetify
Once installed, let’s create our component structure. I normally separate this into 1 of 3 categories.
Base components are global and are automatically bootstrapped.
Core components should be used one time and are generally layout level such as a toolbar or navigation drawer.
Scoped components are structured to mimic the views that they support. For example, if you have a specific component for your Home page, it would be nested in
Taking the above image, let’s identify the different components we will need as well as their category.
Working our way from top to bottom, our first component is a toolbar. In most cases, your application will only contain 1, which makes this a core component. Create a new vue file in
Once created, let’s update our main App.vue file to include our toolbar. We can also remove the initial Helloworld.vue file and its references.
Moving on to the next section we have the main content area. Just like the toolbar, we can take our view specific markup and tuck it away into a core component.
In this design, the content has a maximum width and does not scale the entire screen. This is perfect for v-container which provides this functionality by default.
Now that we have our core structure in place, we can move on to some of our base components. First up will be the cards displayed in the content area.
Since base components are global, we will need to bind them to our main Vue instance. To do this, create a file called
base.js in your plugins folder. We will import our base components here and then hook them up to Vue. Once imported, bind your custom component using Vue.component.
Now that we have our process complete for registering base components, future ones will go down smoother. Let’s take our new component and update the Home.vue view with mock data.
At this point, our application should start to resemble the mock-up. If you’re following along, you should have a directory structure that looks like this:
With the baseline in place, let’s start to flesh out the application toolbar. Using the mock-up from before, we can see there are 3 distinct types of components.
This is a crucial part to an efficient process. Understanding how things break down. It makes our components more testable and easier to maintain. As an exercise, see if you can identify the above components that you would use in Vuetify and update your toolbar to visually match the above. Once complete, your app should look something like this:
With our initial mock in place, we can go back and clean-up areas that we might have breezed past, such as async loaded components and views.
Looking at our previous implementation, we are explicitly importing our core components. While there is nothing wrong with this, code-splitting is a first class citizen in Vue and should be used when you can.
Vue components can accept a function that returns a promise and as import returns a promise, you can structure your code as such:
This also gives us the power to define custom chunk names (among other things) for these components to be included in. By default, our asynchronously imported components will be assigned a numeric value in our bundle.
While this is great, let’s say that we want to group all of our core components in 1 chunk, what does this look like?. Fortunately, it is a very trivial exercise with vue-cli-3. Supplying a special type of comment will tell Webpack as it’s building your bundle that a specific import should be kept under a specific namespace. For more information on code splitting, you can checkout the official documentation.
With just a few lines, we’re able to create a more controlled environment to develop in. Vue even supports more advanced implementations such as loading components (while your async component is being loaded) and error components for missing imports. You can view additional documentation on usage here.
As an exercise, see if you can asynchronously load the Home view in router.js.
Monolithic components help no one, especially the future you that will ultimately have to add/update/fix features. Keeping functionality small and scoped will lead to a better overall development experience, but there is also something else we can do to save ourselves, unit testing.
In the next part of this series, we will expand upon our mock application, add new functionality and create unit/e2e tests to ensure that it continues to operate as we expect.