Personal Vue 3 component package missing template or render function

10k views Asked by At

I recently uploaded my own Vue 3 component to NPM to make it usable for others. When using it in other projects it gives this warning:

[Vue warn]: Component is missing template or render function. 
at <VueToggle id="1" title="Toggle me" > 
at <App>

What could be the reason this is happening? The way I am building and publishing the app is by running this code.

import VueToggle from "./components/VueToggle";

export default {
    install(app) {
        app.component("vue-toggle", VueToggle);
    }
};

And then running this build command in my package.json:

"build-library": "vue-cli-service build --target lib --name vue-toggle-component ./src/install.js",

How I use my component in a different project:

<template>
  <VueToggle id="1" title="Toggle me"/>
</template>

<script>
import VueToggle from 'vue-toggle-component';

export default {
  name: 'App',
  components: {
    VueToggle,
  }
}
</script>

The component itself:

<template>
  <section class="wrapper" :class="{dark: darkTheme}" :title="title">
    <input
      :id="id"
      :name="name"
      v-model="toggleState"
      class="toggle"
      type="checkbox"
      @click="toggleState = !toggleState"
    />
    <label :for="id" class="toggler" :style="[toggleState && {'background': activeColor}]"/>
    <span class="title" v-text="title" @click="toggleState = !toggleState"/>
  </section>
</template>

<script>
export default {
  name: 'VueToggle',
  props: {
    activeColor: {type: String, default: '#9FD6AE'},
    darkTheme: {type: Boolean, default: false},
    id: {type: String, required: true},
    name: {type: [String, Boolean], default: false},
    title: {type: String, required: true},
    toggled: {type: Boolean, default: false},
  },
  data() {
    return {
      toggleState: this.toggled
    }
  },
}
</script>

The package: https://www.npmjs.com/package/vue-toggle-component

3

There are 3 answers

0
bvj On

The following concerns a new project using Vue 3 & Typescript created with Quasar CLI (v2 beta). Although I'm getting the same error reported by the OP, my source layout might be different as I'm not using single-file components.

[Vue warn]: Component is missing template or render function.

I resolved the above issue by specifying the vue file as the component source. I typically split my components into separate vue and ts files.

The related fragment:

MyComponent: require("./components/My.vue").default

In context:

export default defineComponent({
  name: "App",
  components: {
    MyComponent: require("./components/My.vue").default
  },
  setup() {
  ...

To quiet the linters, I have the following es-lint comments

export default defineComponent({
  name: "App",
  components: {
    // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-var-requires
    MyComponent: require("./components/My.vue").default
  },

Ideally, the import statement would be used instead of the inline require assignment.

0
Alex Buchatski On

When you use your component, replace

import VueToggle from 'vue-toggle-component';

with

import VueToggle from 'vue-toggle-component.vue';

Or if component users use webpack, they may specify in config:

resolve: {
    extensions: ['.vue', '.ts', '.js']
}
0
Paradoxdotexe On

The problem is that you are trying to import 'vue-toggle-component' like a Vue component, when your library is exporting a Vue plugin (made up of an install function that declares your component).

There are two way to fix this.

Solution 1

Remove the component import entirely.

// component.vue (separate project)
<template>
  <VueToggle id="1" title="Toggle me"/>
</template>

<script>
export default {
  name: 'App'
}
</script>

Then import your library plugin and styles in index.js of the separate project. You should activate the plugin using Vue.use().

// index.js (separate project)
import { createApp } from "vue";
import App from './App.vue';

import VueToggleComponent from 'vue-toggle-component';
import '@vue-toggle-component/dist/style.css';

const app = createApp(App);
app.mount('#app');

app.use(VueToggleComponent);

Your component should now be imported by default into the project and can be used from anywhere.

Solution 2

Add anonymized exports for each component for individual importing.

// install.js
import VueToggle from "./components/VueToggle";

export default {
    install(app) {
        app.component("vue-toggle", VueToggle);
    }
};

export { default as VueToggle } from "./components/VueToggle";

Then import the component as a non-default export in your separate project.

// component.vue (separate project)
<template>
  <VueToggle id="1" title="Toggle me"/>
</template>

<script>
import { VueToggle } from 'vue-toggle-component';

export default {
  name: 'App',
  components: {
    VueToggle,
  }
}
</script>

Finally, install your library's styles.

// index.js (separate project)
import { createApp } from "vue";
import App from './App.vue';

import '@vue-toggle-component/dist/style.css';

const app = createApp(App);
app.mount('#app');

Conclusion

Personally, I think Solution #2 is more flexible and intuitive to use.