Vue.js - Component is missing template or render function

81.5k views Asked by At

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.

9

There are 9 answers

0
tony19 On BEST ANSWER

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 },
    //...
  ]
})

demo

1
Ismail Omar On

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")
0
munandi sichali On

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.

0
Phil Cairns On

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>
0
Jorr.it On

The solution for me was to upgrade node module vue-loader to version 16.8.1.

0
Pezhvak On

Make sure you have added <router-view></router-view> in your #app container.

0
nahoang On

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.

0
Phil On

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);
0
Paul Wolbers On

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
    })