[Vue 3] automatic component registration

Has anyone been able to find a way to implement automatic registration with Vue3 like you would in Vue2: https://vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components?

I’ve tried numerous things trying to find a way around it, but yet to find a good solution.
Imports aren’t asynchronous, so:

   export const app = createApp(App)

and importing that into a js file:

import { app } from '@/main.js'

doesn’t work, since app is still undefined at that point.

Has anyone got any solution or approach to automatically registering components?

It looks like everything should be the same apart from using app.component rather than Vue.component.

Why is your app still undefined?

Would you not register the components in the same file that calls createApp?

I think I was having a brain fart initially. Got it working.

It was undefined, because I was importing the main.js file, which was importing the register component file, so App hadn’t been created yet. :sweat_smile:

I ended up doing similar to what you said in the end - they all register in the main.js file now.
I turned the requireContext into an exported module, and imported that function into main.js and all works perfectly now.

basically, ./register-components.js:

import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // The relative path of the components folder
  './components',
  // Whether or not to look in subfolders
  false,
  // The regular expression used to match base component filenames
  /Base[A-Z]\w+\.(vue|js)$/
)

export const registerComponents = app => requireComponent.keys().forEach(fileName => {
  // Get component config
  const componentConfig = requireComponent(fileName)

  // Get PascalCase name of component
  const componentName = upperFirst(
    camelCase(
      // Gets the file name regardless of folder depth
      fileName
        .split('/')
        .pop()
        .replace(/\.\w+$/, '')
    )
  )


  // Register component globally
  app.component(
    componentName,
    // Look for the component options on `.default`, which will
    // exist if the component was exported with `export default`,
    // otherwise fall back to module's root.
    componentConfig.default || componentConfig
  )
})

then in main.js:

import { registerComponents } from '@/plugins/register-components'

export const app = createApp(App)
    .use(vueAxios, axios)
    .use(store)
    .use(router)

registerComponents(app)

app.mount('#app')

With a few small tweaks you could make that a proper Vue plugin and use it via app.use.

1 Like