Reputation: 3888
In Vue 3, I created the following Home
component, 2 other components (Foo
and Bar
), and passed it to vue-router
as shown below. The Home
component is created using Vue's component
function, whereas Foo
and Bar
components are created using plain objects.
The error that I get:
Component is missing template or render function.
Here, the Home
component is causing the problem. Can't we pass the result of component()
to a route object for vue-router
?
<div id="app">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/foo">Foo</router-link></li>
<li><router-link to="/bar">Bar</router-link></li>
</ul>
<home></home>
<router-view></router-view>
</div>
<script>
const { createRouter, createWebHistory, createWebHashHistory } = VueRouter
const { createApp } = Vue
const app = createApp({})
var Home = app.component('home', {
template: '<div>home</div>',
})
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar },
],
})
app.use(router)
app.mount('#app')
</script>
See the problem in codesandbox.
Upvotes: 40
Views: 99154
Reputation: 56965
Answering as a canonical with respect to Vue 3.3.0.
I had forgotten to import another component in a <script setup>
, but I had a piece of reactive state that had the same name, leading Vue to interpret the state as the component.
<template>
<confirmation-modal></confirmation-modal>
</template>
<script setup>
import ConfirmationModal from "./ConfirmationModal.vue"; // x
const confirmationModal = ref({});
</script>
Originally, the import marked 'x' was missing. Adding the import resolved the "Component is missing template or render function" warning, as well as a secondary warning, Vue received a Component which was made a reactive object.
Renaming the reactive state to const confirmationModalOptions = ref({});
resolved a final name clash and eliminated all warnings.
Upvotes: 1
Reputation: 7566
For me the problem was that I have enabled verbatimModuleSyntax for typescript and used eslint . --fix
with "@typescript-eslint/consistent-type-imports": "error"
enabled in the eslint.config.json for my '*.vue' files. In Composition API SFCs that resulted in
// not just a mere interface - vue3 SFC needs the import to resolve
// the component in the template, should not be optimized away
import type SomeDialog from '@foo/SomeDialog.vue'; // type added
const someDialog = ref<SomeDialog | null>(null);
But Vue needs to resolve the import which the ccompiler would optimize away if it is just a type. So run autofixes with that rule with care. To avoid the rule being applied, you can either put this before the import
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
or pass the component as a parameter to the ref:
const someDialog = ref(SomeDialog);
Upvotes: 0
Reputation: 2478
You need to create separate class (App.vue) for doing the render thing.
Check it below example out:
./views/App.vue
<template>
<main>
<router-view>
</router-view>
</main>
</template>
router.js
import { createRouter, createWebHistory } from 'vue-router'
import ExampleComponent from './components/ExampleComponent.vue';
const routes = [
{
path: '/',
name: 'home',
meta: {
title: "Home",
},
component: ExampleComponent
}
];
export default createRouter({
history: createWebHistory(),
routes
})
app.js (OR main.js)
require('./bootstrap');
import { createApp } from 'vue';
import router from './router'
import App from "./views/App.vue";
createApp(App)
.use(router).mount('#app');
That's it.
Upvotes: 0
Reputation: 768
I was extending a Quasar component in Vue 3, and ran into this problem. I solved it by adding the setup: QInput.setup
line last in the component options.
<script>
import { defineComponent } from 'vue'
import { QInput } from 'quasar'
const { props } = QInput
export default defineComponent({
props: {
...props,
outlined: {
type: Boolean,
default: true
},
dense: {
type: Boolean,
default: true
},
uppercase: {
type: Boolean,
default: false
}
},
watch: {
modelValue (v) {
this.uppercase && this.$emit('update:modelValue', v.toUpperCase())
}
},
setup: QInput.setup
})
</script>
Upvotes: 0
Reputation: 29
I had this issue too. It's a timing issue. I added a v-if to create the component when the page is mounted. That fixed it for me.
<review-info
v-if="initDone"
:review-info="reviewInfo"
/>
// script
onMounted(() => {
initDone = true
})
Upvotes: 1
Reputation: 1300
The solution for me was to upgrade node module vue-loader to version 16.8.1.
Upvotes: 0
Reputation: 10868
Make sure you have added <router-view></router-view>
in your #app
container.
Upvotes: 5
Reputation: 39
The solution was simple on my side, I created a component that was empty, after filling in the template and a simple text HTML code, it was fixed.
Upvotes: 2
Reputation: 585
FOR vue-cli vue 3
render function missed in createApp. When setting your app by using createApp function you have to include the render function that include App.
in main.js update to :
FIRST change the second line in javascript from:-
const { createApp } = Vue
to the following lines:
import { createApp,h } from 'vue'
import App from './App.vue'
SECOND
Change from :-
const app = createApp({})
to:
const app = createApp({
render: ()=>h(App)
});
app.mount("#app")
Upvotes: 22
Reputation: 138306
When app.component(...)
is provided a definition object (the 2nd argument), it returns the application instance (in order to allow chaining calls). To get the component definition, omit the definition object and provide only the name:
app.component('home', { /* definition */ })
const Home = app.component('home')
const router = createRouter({
routes: [
{ path: '/', component: Home },
//...
]
})
Upvotes: 11