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 }
)
  1. Pass the folder path and specify the extension of the files we want to fetch. In this case, we need .vue files
  2. 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,

  1. ./components/global/GlobalImage.vue
  2. ./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
}
  1. path: ./components/global/GlobalImage.vue
  2. 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,

  1. You loose tree-shaking. Unused global components will also be added to the production build.
  2. 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.