You declare component-b in component-a. Local registering of components make them only accessible withing the components they are registered (declared), not globally, not even to their children.
And, in your code, component-b is being used by the root component, not by component-a. component-a's template is:
<div><span>Hi</span><slot></slot></div>
There's no use of component-b there. With:
new Vue({
el: '#app'
});
<div id="app">
<component-a>
<component-b></component-b>
</component-a>
</div>
You do are using component-b in the root's template. But it was not registered nowhere the root component can see.
You have some alternatives.
Move the registration to the root, where it is used:
Vue.component('component-a', {
template: '<div><span>Hi</span><slot></slot></div>'
});
new Vue({
el: '#app',
components: {
'component-b': {
template: '<div>Hello</div>'
}
}
});
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<component-a>
<component-b></component-b>
</component-a>
</div>
Register it globally, like component-a
Vue.component('component-a', {
template: '<div><span>Hi</span><slot></slot></div>',
});
Vue.component('component-b', {
template: '<div>Hello</div>'
});
new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<component-a>
<component-b></component-b>
</component-a>
</div>
Or use it inside component-a instead of the root and move the slot (changes semantics)
Vue.component('component-a', {
template: '<div><span>Hi</span><component-b><slot></slot></component-b></div>',
components: {
'component-b': {
template: '<div><slot></slot></div>'
}
}
});
new Vue({
el: '#app'
});
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<div id="app">
<component-a>
<div>Hello</div>
</component-a>
</div>