# Vue3 + Vite Global Component Registration

I'm working on a project in my new job and as part of the project I'm trying to register some components globally. As a company we're going to build out a component library and we want to be able to use some components without having to manually import them in each component. In Vue2 this was an [easy thing to do](https://v2.vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components) but in Vue3 it's a bit more complex.

# Initial Attempt
I found another [blog post](https://dev.to/jirehnimes/how-to-register-global-components-in-vue-3-dynamically-3gl) that describes how to do this in Vue3 but the issue I ran into was an error indicating that "require is not defined". I don't know if this is because of JS modules, or the fact that I'm using TypeScript, or that we're using [Vite](https://vitejs.dev/) for the project, but it doesn't work.

# Svelte Experience to the Rescue
As I've noted in a [previous blog post](https://jeffpohlmeyer.com/building-a-blog-with-sveltekit-tailwindcss-and-mdsvex) we can import "local" files into a Vite module using a [glob import](https://vitejs.dev/guide/features.html#glob-import). So what I'll end up doing is grabbing all files that match a given format, convert the file names to the format I want, and globally register all components.
## Grab Components
Let's assume that the file structure of the project includes a `main.ts` file at the root of the project, as well as a `/src/lib/components` folder, which is where I'll store all of the components to be globally registered. This I also stole from Svelte, although we can't just use `import * from '$lib/components/...` like we can in Svelte. Regardless, this felt like a natural place to store these components.

We'll be able to simply grab all components using `const components = import.meta.globEager('/src/lib/components/<Name Pattern>.vue')`
## Create a plugin
Let's also create a plugin to grab and register all of these components, and set it up at `/src/plugins/global-components.ts`. It is here we'll set up the script to grab and register all components as
```typescript
import { App } from 'vue'

export const register = (app: App<Element>): void => {
  // Grab all components in `/src/lib/components/` that start with "Base"
  const components = import.meta.globEager('../lib/components/Base*.vue')
  Object.entries(components).forEach(([path, component]) => {
    // Just get the file name itself, remove the .vue extension, and remove the "Base" at the front of the file name
    const pathSplit = path.split('/')
    const fileName = pathSplit[pathSplit.length - 1].split('.vue')[0].split('Base')[1]

    // Convert to kebab-case and register with a "jvp-" prefix
    const kebab = fileName.replace(/([a-z0–9])([A-Z])/g, '$1-$2').toLowerCase()
    app.component(`jvp-${kebab}`, component.default.render())
  })
}
```
The comments _should_ be fairly self-explanatory, but just in case they're not this is what is happening
- Fetch all components that live in `/src/lib/components` that begin with `Base` in the file name
- For each of these components
  - Grab the file name by splitting the path on the `/` character, and getting the last entry in the resulting array.
  - Remove the `.vue` extension as well as the `Base` prefix
  - Convert the PascalCase file name to kebab-case using your favorite method (my Googling led me to https://medium.com/@mattkenefick/snippets-in-javascript-converting-pascalcase-to-kebab-case-426c80672abc)
  - Register the component with the prefix you want (I'm using "jvp" for these)

There are likely better ways to handle the file name search and string manipulation but this was a simple way for me to do it since I'm prescribing the naming convention myself.
## Use plugin in `main.ts`
Now that this is set up we need to use it in our `main.ts` file. This is a fairly simple process. First we need to import our newly created `register` function and execute it with the `app` instance that we create in `main.ts`. It should look something like this
```typescript
import App from './App.vue'
import { createApp } from 'vue'
import { register } from './plugins/global-components'

const app = createApp(App)
register(app)
```
and we should now have access to any and all components created in `/src/lib/components/Base<NameRemainder>.vue` throughout our app as `<jvp-name-remainder />` without having to import it directly. Again, there may be a simpler/easier way to handle this functionality, but this is the first way I tried that actually worked so I'm just going to leave this here.
