I can't comment yet, but I have an addition to Shaya Ulmans answer:
Using Vue 2.6(.10):
It does not need to be in the created hook if you check if the component has been registered already. If you don't and for example add it in the mounted hook or a custom method, it can not find the component if you did not register it yet.
This can be solved with a simple v-if statement.
I created a class based on Shaya Ulmans answer as a trial that can register a component locally to a given component using a config and dynamic imports. It could be done using a mixin, but I only require dynamic local registration in a subset of my components.
/**
* @class dynamicLocalComponentRegistrator
* @classdesc can register components to a given component locally
*/
export class dynamicLocalComponentRegistrator {
/**
* @typedef ComponentConfig
* @type {object}
* @property {string} name
* @property {Function} component
*/
/**
* Reference to component the components should be locally registered to
* @type {VueComponent}
*/
localComponent;
/**
* Keep track of registered components
* @type {string[]}
*/
registeredComponents = [];
constructor (localComponent) {
this.localComponent = localComponent;
}
/**
* Register multiple components, skipping those that are already registered
*
* @param {ComponentConfig[]} componentConfigArray
*/
registerMultipleComponents (componentConfigArray) {
componentConfigArray.forEach(componentConfig => {
if (!this.isRegistered(componentConfig.name)) {
this.registerComponent(componentConfig);
}
})
}
/**
* Register a component locally to the local component
*
* @param {ComponentConfig} componentConfig
*/
registerComponent (componentConfig) {
if (!componentConfig.hasOwnProperty('name') || !componentConfig.hasOwnProperty('component') || typeof componentConfig.component !== 'function') {
throw 'cannot register component: invalid config'
}
componentConfig.component().then(component => {
this.localComponent.$options.components[componentConfig.name] = component.default;
this.registeredComponents.push(componentConfig.name);
});
}
/**
* Shorthand to check registration
*
* @param {string} componentName
* @returns {boolean}
*/
isRegistered(componentName) {
return this.registeredComponents.includes(componentName);
}
}
Just import this in the components you need to have the functionality in. Then, wherever you like, create an instance and give this to the constructor.
For example:
mounted() {
this.componentRegistrator = new dynamicLocalComponentRegistrator(this);
this.componentRegistrator.registerMultipleComponents(this.customComponents);
}
And to use it in a .vue template:
<component v-if="componentRegistrator && componentRegistrator.isRegistered(dynamicComponent.name)" :is="dynamicComponent.name" />
This does not throw errors and so far works beautifully.