Organize registering Vue global components in Vue 3

Viewed 4508

In Vue 2 you can globally register components over multiple files by using the following code in index.js without bloating the main.js file

import Vue from 'vue'
import MyComponent from '@/components/MyComponent'

Vue.component('my-component-name', MyComponent)

And in the main.js file use

import '@/components'

But this method doesn't seem to work for me in Vue 3

main.js

import { createApp } from 'vue';
import '@/components'

const app = createApp({});

app.mount("#app");

index.js

import Vue from 'vue' // doesn't work with import { createApp } from 'vue' too
import MyComponent from '@/components/MyComponent'

Vue.component('my-component-name', MyComponent)

How can you achieve the same result in Vue 3?

3 Answers

I was stumbling upon the same issue. To still have my components in an external file, I made my registerComponents.ts as a component loader function that as an argument receives the vue app it should add the components to.

So in my case I have a file registerComponents.ts that looks like this

import { App } from "vue";

// import components
import button from '@/components/Button.vue';

// register components
export const registerComponents = (app: App): void => {
    app.component('tw-button', button);
}

and my main.ts then uses the function before mounting:

const app = createApp(App)
    .use(store)
    .use(router)
    .use(i18n);

registerComponents(app);

app.mount("#app");

Maybe this helps somebody :-)

There is no global registration in Vue 3. Everything is scoped to a particular app.

So the closest you can get is:

const app = createApp({});

app.component('my-component-name', MyComponent)

app.mount("#app");

You will have to decide the best way to pass the relevant bits between your two files. For example, you might make index.js a plugin.

RFC: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0009-global-api-change.md

In Vue 3 we can have multiple application instances

const app1 = createApp({})
app1.mount('#container-1')

const app2 = createApp({})
app2.mount('#container-2')

that can co-exist on that same page. So we can no longer use Vue from import Vue from 'vue' to register/use plugins.


My solution

See the implementation live on Stackblitz

Step 1: Create a folder to keep plugins/packages/dependencies

I've called it plugins since they will be plugged in main.js.

Step 2: Create main-app.js

You can also call it app1.js or whatever you want. Here is the content:

import { createApp } from 'vue'
import App from '../App.vue'

export const app = createApp(App)

Step 3: Plug it in main.js

import { app } from './plugins/main-app'

app.mount('#app')

Step 4: Create a new plugin

Now let's create a src/plugins/global-components.js

import { app } from './main-app'
import MyComponent from '@/components/MyComponent'

app.component('my-component-name', MyComponent)

Register it in main.js:

import { app } from './plugins/main-app'
import './plugins/global-components'

app.mount('#app')

You can go a step further and have an index.js in src/plugins where it will be like main.js and then in main.js you simply have import './plugins' but personally I don't like this extra step

Related