I'm going to build small UI library package with Vue components and use it in my Inertia-Laravel Project.
//Logo.vue
<template>
<Link href="/" class="text-xl font-bold flex items-center lg:ml-2.5">
My Logo
</Link>
</template>
<script>
import { Link } from '#inertiajs/inertia-vue3'
export default {
name: "Logo",
components: {
Link,
},
}
</script>
I was able to build this as package Vite or Vue-SFC-RollUp and publish it on npm.
But when I was going to install it on my inertia/laravel projects and use it, I got some warning and error.
MyProjectComponent.vue
<template>
...
<Logo />
...
</template>
<script>
import {Logo} from 'mypackage-ui'
export default {
components: {Logo}
}
</script>
Error message:
export 'default' (imported as 'require$$1') was not found in 'vue'
(possible exports: BaseTransition, Comment, EffectScope, ... , withScopeId)
If I remove <Link> in Logo.vue and use <a> tag and update package, then it's working well.
Any suggestion would be highly appreciated.
I'm using Vue 3.
The solution to this is to add the inertia link as a component in the app.js file:
import { createInertiaApp, Head, Link } from '#inertiajs/inertia-vue3';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => require(`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.component('InertiaHead', Head)
.component('InertiaLink', Link)
.use(ZiggyVue, Ziggy)
.mount(el);
},
});
Related
I have an Vue.js / Electron App. I'm trying to use a v-content (from vuetify) component in my vue App.vue, but it does not load, and in Electron console I get the following warning, that makes clear why:
runtime-core.esm-bundler.js:38 [Vue warn]: Failed to resolve component: v-content
If this is a native custom element, make sure to exclude it from component resolution via
compilerOptions.isCustomElement at <App>
Others Vuetify components like v-app-bar and v-toolbar-title worked perfectly...
I'm not sure if Vuetify components can be considered "native" as the warning says, but anyway I did not find how to exclude the component from "component resolution via compilerOptions.isCustomElement". Does anybody knows where to find it?
The previous questions of the same issue posted here doesn't helped me. This one is the closer of my issue.
My App.vue:
<template>
<v-app>
<v-app-bar app color ="primary" dark>
<v-toolbar-title>OwnTime</v-toolbar-title>
</v-app-bar>
<v-content>
My content
</v-content>
</v-app>
</template>
<script>
import HomePage from "./components/HomePage"
export default {
name: 'App',
components: {
HomePage
},
data: () => ({
//
}),
}
</script>
My Main.js:
import { createApp } from 'vue'
import App from './App.vue'
import vuetify from './plugins/vuetify'
import { loadFonts } from './plugins/webfontloader'
loadFonts()
createApp(App)
.use(vuetify)
.mount('#app')
My vue.config.js:
const { defineConfig } = require('#vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
configureWebpack: {
devtool: 'source-map',
},
pluginOptions: {
vuetify: {
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
}
}
})
I'm trying to use VuePlyr in Nuxt 2. Right now I have it working as a plugin /plugins/vue-plyr.js,
import Vue from 'vue'
import VuePlyr from '#skjnldsv/vue-plyr'
import 'vue-plyr/dist/vue-plyr.css'
Vue.use(VuePlyr)
but it is just used in one page, so I would like to remove it from the main bundle and just import it locally when used. I've tried this in my page (the template part was working when using the plugin).
<template>
<client-only>
<vue-plyr>
<div data-plyr-provider="vimeo" :data-plyr-embed-id="id" />
</vue-plyr>
</client-only>
</template>
<script>
import 'vue-plyr/dist/vue-plyr.css'
import Vue from 'vue'
export default {
async mounted () {
const VuePlyr = await import('#skjnldsv/vue-plyr')
Vue.use(VuePlyr)
}
}
</script>
but unfortunately, I'm getting this error
[Vue warn]: Unknown custom element: <vue-plyr> - did you register the component correctly?
Any idea how I could achieve this? Related with How to make a dynamic import in Nuxt?
You could import it like that
export default {
components: {
[process.client && 'VuePlyr']: () => import('#skjnldsv/vue-plyr'),
}
}
As mentioned in a previous answer.
In your nuxt config define the plugin as client only:
plugins: [
{ src: "~/plugins/vue-plyr.js", mode: "client" }
],
Then also make sure there's a client-only tag around the use of the component:
<template>
<client-only>
<vue-plyr>
<div data-plyr-provider="vimeo" :data-plyr-embed-id="id" />
</vue-plyr>
</client-only>
</template>
Edit: importing the component again in the mounted method isn't necessary if you added it as a plugin
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
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.
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.
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']
}
If I start my vue instance from a main.js file
//main.js
var vm = new Vue({
el: '#app',
render: h => h(App),
router,
data: {
}
});
export {
vm
}
app.vue itself is a router view.
<template>
<router-view></router-view>
</template>
<script>
export default {}
</script>
So lets say one of the components that gets loaded in the router needs access
to vm? I've gotten as far as to do this in the component:
import vm from '../main.js'
It seems to find the main.js file. But how do I then access vm? An example of a problem is when I use vue-lazyload(https://github.com/hilongjw/vue-lazyload) and need to access vm like I try here:
<template>
<div class="hero-unit-bg" v-lazy:background-image="imgUrl" >
</div>
</template>
<script>
import Vue from 'vue'
import VueLazyload from 'vue-lazyload'
import vm from '../main.js'
Vue.use(VueLazyload)
vm.$Lazyload.$on('loaded', function ({ bindType, el, naturalHeight, naturalWidth, $parent, src, loading, error }, formCache) {
console.log(el, src)
})
export default {
name: 'HeroUnit',
data () {
return {
imgUrl: 'img/hero-unit-bg.png' // String
}
},
methods: {
},
}
}
</script>
Console shows vm.$Lazyload as undefined. So I don't think I'm importing vm properly. Am I missing something? Thank you.
If you are exporting like this:
export { vm }
then you need to import it like this:
import { vm } from './module.js'
For a default export, it would work like this:
export default vm
import vm from './module.js'
You'd likely create a circular dependency by importing main.js into a component. You actually don't need to reference the root instance, as the code Vue.use(VueLazyLoad) makes the plugin accessible from any component method via this.$LazyLoad.
For example, you could setup your code as follows:
main.js:
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
App.vue
export default {
...
mounted() {
this.$Lazyload.$on('loaded', function ({ bindType, el, naturalHeight, naturalWidth, $parent, src, loading, error }, formCache) {
console.log(el, src)
})
}
}
MyComponent.vue
<template>
<div v-lazy-container="{ selector: 'img' }">
<img data-src="//placekitten.com/200/200">
<img data-src="//placekitten.com/200/201">
<img data-src="//placekitten.com/200/202">
</div>
</template>
demo
I am getting a lot of Vue warnings saying $listeners is readonly or $attrs is readonly and related to different Bootstrap items or to .
For example:
[Vue warn]: $attrs is readonly.
found in
---> <BDropdown>
<Display>
<App>
<Root>
I am very sure it has something to do with loading the Vue instance twice somehow, but I don't really know, how to do it any other way, so that the routing still works.
In my main.js the code is as follows:
import Vue from 'vue'
import App from './App'
import router from './router'
import firebase from 'firebase';
import './components/firebaseInit';
import store from './store';
import { i18n } from './plugins/i18n.js'
import BootstrapVue from 'bootstrap-vue'
import VueCarousel from 'vue-carousel';
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue);
Vue.use(VueCarousel);
let app;
firebase.auth().onAuthStateChanged(user => {
if(!app) {
app = new Vue({
el: '#app',
router,
store,
i18n,
components: { App },
template: '<App/>'
})
}
})
My router/index.js code looks as follows:
import Vue from 'vue'
import Router from 'vue-router'
import firebaseApp from '#/components/firebaseInit'
Vue.use(Router)
let router = new Router({
routes: [
{
path: '/',
name: 'display',
component: Display
},
...
]
})
// Nav Guards
router.beforeEach((to, from, next) => {
// check for requiredAuth
if(to.matched.some(record => record.meta.requiresAuth)) {
// check if NOT logged in
...
} else {
// proceed to route
next();
}
} else {
next();
}
})
export default router;
As the sample errors come from Display.vue, here is an extract of that code:
<template>
<div>
<b-row>
<b-input-group prepend="Category">
<b-dropdown v-bind:text="currentCategory">
<b-dropdown-item #click="categroyChanged('All')">All</b-dropdown-item>
<b-dropdown-item v-for="c in categories" v-bind:key="c" #click="categoryChanged(c)">{{c}}</b-dropdown-item>
</b-dropdown>
</b-input-group>
</b-row>
<div class="row" v-for="i in Math.ceil(products.length / 3)" v-bind:key="i">
<div v-for="product in products.slice((i - 1) * 3, i * 3)" v-bind:key="product.id" class="col-md-4 col-6 my-1">
<b-card
v-bind:img-src="product.thumbUrl"
img-fluid
img-alt="image"
overlay>
<div slot="footer">
<small class="text-muted">{{product.name}}<br />{{product.price}} VND</small>
</div>
<router-link v-bind:to="{name: 'view-product', params: {product_id: product.product_id}}" class="secondary-content">
<i class="fa fa-eye"></i>
</router-link>
<router-link v-if="isEmployee" v-bind:to="{name: 'edit-product', params: {product_id: product.product_id}}" class="secondary-content">
<i class="fa fa-pencil"></i>
</router-link>
<button #click='addToCart(product)' class='button is-info'><i class="fa fa-cart-arrow-down"></i></button>
</b-card>
</div>
</div>
</div>
</template>
<script>
import firebaseApp from './firebaseInit'
import { mapActions } from 'vuex'
export default {
name: 'display',
data () {
return {
txtSearch: null,
isLoggedIn: false,
currentUser: false,
isEmployee: false,
products: []
}
},
beforeMount () {
var db = firebaseApp.firestore();
db.collection('products').get().then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
'product_id': doc.id,
'article_number': doc.data().article_number,
'barcode': doc.data().barcode,
'category': doc.data().category,
'colour': doc.data().colour,
'description': doc.data().description,
'name': doc.data().name,
'name_ger': doc.data().name_ger,
'price': doc.data().price,
'size': doc.data().size,
'thumbUrl': doc.data().thumbUrl,
}
this.products.push(data)
})
})
}
},
methods: {
...mapActions(['addToCart']),
... many methods ...
}
}
</script>
How can I get rid of these errors?
There are two common reasons why this can happen:
Multiple Vue Locations
This can be due to contradictory locations of where you are importing Vue from, in different files, as others have said. So you might have both import Vue from 'vue' and perhaps import Vue from 'vue.runtime.esm' in your code, for example.
But this can result in multiple instances of Vue, which will cause these errors.
The solution in this case is to use import Vue from 'vue' everywhere in your code, and then alias it in your packaging system (webpack, Parcel, rollup etcetera). An example of this in webpack.config.js, or webpack.renderer.config.js if you're using Electron, would be:
module.exports = {
// ...
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
}
}
// ...
}
See more examples in the Vue documents.
White Listing
This can also be because of a need for Vue to be whitelisted as not one of the externals in webpack, for example.
It is worth noting that changes in Bootstrap Vue from 2.0 to a later version, definitely by 2.15 (and possibly earlier), caused this same problem to occur.
module.exports = {
// ...
externals: [
'fast-glob',
'jquery',
'bunyan',
'yaml',
'vue', // Remove this
'bootstrap-vue', // Remove this
// ...
}
After chasing this for an hour, I realized that a component that I had imported was also accessing Vue. At the top of that file was import Vue from 'vue/dist/vue.esm'. Every other file was simply doing import Vue from 'vue', which was the source of my double-import.
Different javascript packagers have different ways of resolving duplicates. For WebPack, the Resolve Configuration might be helpful in the case of dependencies importing different instances of Vue.
This was my case (https://stackoverflow.com/a/62262296/4202997) but I'll repeat it here to save you time: I was importing vue from a CDN . I simply removed the script and the problem was solved.
In my case the duplicated instances were caused by some Vue plugins importing the Vue instance differently than how I was doing in my project. I managed to fix it by adding the following to my Webpack config:
externals: {
// Stubs out `require('vue')` so it returns `global.Vue`
vue: 'Vue',
},
Hope it can help anyone struggling with the same issue :)