Components are the core feature of Vue.
In fact, you'll often find yourself writing hundreds of them, which means in a large project, importing and registering components can become monotonous. 😤
This statement is especially true for generic components but fortunately, there's a workaround by auto registering base components. This can boost productivity and make your life far easier, and so I recommend it for almost all projects.
I've talked about this topic before in the Complete Vue Developer course, however, that course covers how to perform this task with Webpack instead of Vite. If you're interested in the Webpack counterpart solution, check out the Auto-Registering Global Components lecture.
Otherwise, let's dive in and we'll show you how to set auto-registering components in Vite!
I know I just gave you the spiel on why you would want to autoregister components, but there are some pitfalls you can fall into if you're not careful.
Keep in mind these two important details:
For these reasons, auto registering components works best for components that are generic and used multiple times throughout your app.
Does this sound like something you need in your own app?
Well then, let's give it a try!
You can apply this code to any project.
If you already have a project then feel free to skip to the next section, but if you want to start with a fresh project and follow along, you can do so at Stackblitz.
Alternatively, you can run the following command:
npm init vue@latest
Note: This solution is only applicable to Vite. Webpack projects can't use this code.
While not required, Lodash can help us format the names of our components to ensure consistency, so it's helpful to use.
You can install Lodash with the following command:
npm i --save lodash
💡 Top tip:
Vue has a style guide with recommendations on how components should be named, so feel free to use Lodash to help you adhere to these guidelines.
For this example, let's create a directory dedicated to base components called base from within the src/components/.
Why?
Because it'll be easier to import components if they're not scattered throughout your project.
Next, let's add two base components called Button.vue and Header.vue. In both components, we'll add some template code:
Button.vue:
<template>
<button>
Hello world!
</button>
</template>
Header.vue:
<template>
<h1>What's up!</h1>
</template>
Lastly, let's include these components from the App.vue component.
<template>
<BaseButton />
<BaseHeading />
</template>
In the example above, we're prefixing the components with the word Base
to help developers identify these components as generic components.
Vue's functionality can be extended with plugins, so let's create our own.
Why?
Well by using a plugin, we're given access to the current Vue instance, and we'll be able to export our plugin across various projects.
Inside the src directory, create a file called globals.js with the following code:
import _ from 'lodash';
export default {
install(app) {
}
};
A plugin is simply an object with a method called install()
.
We can register components, directives, or perform other actions against this instance.
In addition to defining the plugin, we're importing Lodash as we'll need its functions later down the line.
In the programming world, there's a special concept known as glob. (No, not the x-men).
'Glob' is a feature for locating files within a filesystem using patterns, and various programming languages and tools implement this feature differently.
For Vite, we have two functions for using globs called import.meta.glob()
and import.meta.globEager()
.
The import.meta.glob()
function will lazy load files, which isn't what we want, as we're interested instead in importing and registering components immediately.
In this case, we can use the import.meta.globEager()
function instead, as this does not lazy load components.
In the install()
method, we're using this function as follows:
const componentFiles = import.meta.globEager(
'./components/base/*.vue'
);
This function does not need to be imported as it's automatically made available via Vite.
Behind the scenes, Vite is using a package called fast-glob. Check out the link for info on the supported pattern syntax.
The value passed into this function is a pattern that will be used by Vite to begin importing files. We're providing a relative path to the components/base directory.
In the latter portion of the path, the *
character acts as a wildcard. Any files that end with the vue extension will be imported.
The imported files are returned as an object and stored in a variable called componentFiles
.
The next step is to begin registering the components.
However, because we don't know how many components will be returned, it would be a good idea to loop through the list of components.
There are two options at our disposal:
The componentFiles
variable will store an object, which isn't loopable unless we use the for of
loop.
Alternatively, we can convert our object into an array by using the Object.entries()
method like so:
Object.entries(componentFiles).forEach(([path, m]) => {
})
The Object.entries()
method will convert an object into an array by storing each key-value pair where the first item is the key and the second item is the value.
After the conversion, we can begin using array methods to loop through the imported components.
For readability, I recommend destructuring the array. This way, the first item in the array will store the path to the file, and the second item in the array stores the component object.
Inside the loop, we can begin preparing the component name:
const componentName = _.upperFirst(
_.camelCase(path.split('/').pop().replace(/\.\w+$/, ''))
);
Note:
The path
variable will contain the full path to the file, which isn't suitable for a component name.
To prepare the name for Vue registration, we're using the _.upperFirst()
and _.camelCase()
functions. The upperFirst()
function will uppercase the first character in the name. The camelCase()
function will capitalize each word in the name.
Before using these functions, we're stripping the filename from the path and removing the .vue
extension. This will leave us with just the name of the component.
For example, if we had the following path /some/path/Example.vue
, the outcome would become Example
.
After all has been said and done, we can finally register the component with the component()
function. In the following example, our component is prefixed with the word Base
to prevent naming conflicts, and the component data can be accessed under the m.default
property since components are exported under the default namespace.
app.component(
`Base${componentName}`, m.default
);
Altogether, the solution looks like this:
import _ from 'lodash';
export default {
install(app) {
const componentFiles = import.meta.globEager(
'./components/base/*.vue'
);
Object.entries(componentFiles).forEach(([path, m]) => {
const componentName = _.upperFirst(
_.camelCase(path.split('/').pop().replace(/\.\w+$/, ''))
);
app.component(
`Base${componentName}`, m.default
);
})
},
};
We can now begin using our plugin by importing the file and chaining the use()
function after the app has been created but before it's been mounted.
import { createApp } from 'vue'
import App from './App.vue'
import GlobalComponents from './globals'
createApp(App)
.use(GlobalComponents)
.mount('#app')
If we were to mount the application before registering our plugin, our components may not be available during the mounting phase.
Important:
You should always register plugins before mounting.
So there you have it, a 7-step process to auto-register your components for Vue.
You can simply follow along and set this up for yourself, but before that, I just want to point out one final thing.
There's a Vite plugin that can autoregister/auto-import components called Unplugin Vue Component that we can also use.
But wait, does that mean that all our efforts were for nothing!?
Not necessarily because the method we just used above comes with additional benefits.
Like what?
Well, our solution can be expanded to import directives, classes, or any other type of file you can imagine. Likewise, it's not limited to just components. Either way, you now have both solutions at your disposal! 😄
Want to learn more about Vue?
Here's a teaser from my Complete Vue Developer course. In the video below I walk you through how to build your first app with Vue!