Global components allow us to use components without manually importing them.
Consider a <global-link></global-link>
component, which we might use in more instances. It would be nice to
just use the component without thinking about the import path.
Modern editors basically can auto-import the paths, but it still leaves us with a doubt. One way is to extract the files and configure them to auto-import. Let's see how it can be done in Vue 3.
# Fetch global component files
Consider we have two files GlobalLink.vue
and GlobalImage.vue
and they are placed inside the folder components/global
.
Vite provides a function to import or fetch list of files called glob
. Create a file called index.ts
inside components/global
and paste the below code.
// components/global/index.ts
const globalComponents = import.meta.glob(
'./components/global/*.vue',
{ eager: true }
)
- Pass the folder path and specify the extension of the files we want to fetch. In this case, we need
.vue
files eager: true
makes the import dynamic.false
will make them static.
Let's see why we opted for dynamic import.
This is the output from the above import.meta.glob
method. There are two file paths printed out,
./components/global/GlobalImage.vue
./components/global/GlobalLink.vue
If you take a closer look, the object contains file path as key and the value is an object named default
.
In GlobalLink
, the expanded default object contains name
, render
and setup
. When we set eager
to true,
the components we recieve are fetched on demand. That's the reason we got a resolved default
object.
In the next step, we will loop through these values and register the components globally.
# Extract files
Create a file called config-extract-components.ts
// config/config-extract-components.ts
export const extractFolderFiles = (filesTree: Record<string, any>) => {
const file: Record<string, any> = {}
Object.entries(filesTree).forEach(([path, definition]) => {
const name = path.split('/').pop()?.replace(/\.\w+$/, '') as string
file[name] = definition
})
return file
}
- path:
./components/global/GlobalImage.vue
- definition:
default
We split the path and extract only the name Eg: GlobalImage
with its default
definition as value and all the file names
within a specified folder.
Let's combine the two methods. Your index.ts
inside global components should look like,
// components/global/index.ts
import type { App } from 'vue'
import { extractFolderFiles } from '@/configs/config-extract-components'
const globalComponents = import.meta.glob(
'./components/global/*.vue',
{ eager: true }
)
const components = extractFolderFiles(globalComponents)
export default function install (app: App) {
for (const name in components) {
app.component(name, components[name].default)
}
}
Exporting a default install
method makes this a Vue plugin. We can import this into main.ts
file and register it as a plugin.
// main.ts
import GlobalComponents from '@/components/global'
const app = createApp(App)
app.use(GlobalComponents)
...
We have now successfully automated the component registration process for global vue components in Vue 3. Though it tempts to register most of the components globally, be cautious about the following,
- You loose tree-shaking. Unused global components will also be added to the production build.
- Naming collision with other components or external component libraries.
If you notice, we also follow a naming convention with the global component names by prefixing filenames with
Global
(Eg: GlobalLink.vue
, GlobalImage.vue
). To read more about folder structure and naming conventions in a Vue project visit this link: Vue 3 & TS starter template.
Link to github repo of a starter template with this example - components/global/index.ts
And that's a wrap.