Why is my Vue component automatically named invalidly? - vue.js

I have a Vue component that I just converted to class syntax. I have done this to three other components in my project with no problem. My component looks like this after reducing it to just the problematic code and no cruft:
<template>
<v-container>
blah
</v-container>
</template>
<script>
import { Vue, Component } from 'vue-property-decorator'
#Component({
})
export default class extends Vue {
}
</script>
And I get this error message dynamically in the browser console.
[Vue warn]: Invalid component name: "_class2". Component names should conform to valid custom element name in html5 specification.
I obviously haven't named anything _class2 here. Vue must have done that for me. Why is the name invalid? How do I pick a valid name?

The class needs to have a name given to it.
export default class Foo extends Vue {
Apparently if you don't do this, it'll work just fine, but randomly give it a name that quite possibly won't work. This is a case of frameworks building on top of Javascript and not being able to report errors at the level the programmer is writing code at, but the level of the generated Javascript instead.

Related

Vue3: Component isn’t correctly resolved

Goodmorning everyone,
I currently have the following package structure:
A design system all written in Vue3
A common package that imports the design system and is shared between all the different apps I have to mantain
The apps, which import the common library and include the additional features
Now the problem is that I have a component in the common library that should be imported in the apps, and the structure is like the following:
// common component
<template>
<div class="template">
<Navigation></Navigation>
</div>
</template>
and, as you can see, the component is imported from the design system in the following way
import { Navigation } from '#personal/design-system';
and used in the components section of the file
components: { Navigation }
However, when I import the common component above in an app, it’s resolved, but the <Navigation> component isn’t rendered itself. Here is the unexpected behavior:
// WRONG render
<div class="template">
<navigation></navigation>
</div>
so the component isn’t rendered and only the tag is printed in the DOM. In addition to this I have the following warning in console
[Vue warn]: resolveComponent can only be used in render() or setup().
Please, could you help me to understand what’s the problem and what’s the correct way to render component like this if we’re working with libraries?
Thank you very much in advance.

Is it component definition in vue? How do I find whether it is a component by looking at the code?

When I search for something I came across this post
Here, something, I believe it is component, is defined as below.
export default {
name: 'app',
methods: {
testFunction: function (event) {
console.log('test clicked')
}
},
components: {
Test
}
}
As per the documentation, I came across this
import BaseButton from './BaseButton.vue'
import BaseIcon from './BaseIcon.vue'
import BaseInput from './BaseInput.vue'
export default {
components: {
BaseButton,
BaseIcon,
BaseInput
}
}
I really not sure, whether app is a component which contains Test. Is it the component definition in export? How do we understand that is a component from vue code?
Is it only by the below ways?
Vue.component
components in Vue instance
Not sure - the export default way?
I understand that I sound different because it is Javascript. Could someone help me with this?
There are conventionally, three different types of components in Vue JS.
Root Component
View Component
Normal Component
In a conventional structure the Root component is named 'app' and is passed to the Vue instance when initializing the App for the first time. This component can not be imported and reused inside other components as it will cause a recursive effect. For example this App.vue file is a Root component. It is used inside this main.js file and passed to the Vue instance using new Vue.
The View components are dynamically added or removed from the Root component based on the route. They are written and act as normal component and are only used for Vue router component property. For example the Home and Comments components inside this Router index file are known as View components. They are passed inside the route objects as components inside individual routes. When the app navigates to that particular route, the <router-view> template inside the App.vue file gets replace with the template of the corresponding View component.
Normal components can be used anywhere and are imported by other components. They can be imported inside the View components as well as the Root components. For example, in root component App.vue we see the component Navbar is used. In View component Comments.vue the Replies component is used.
All these components are identical in declaration and behavior but differ in usage.

In Vue.js why do we have to export components after importing them?

In PHP when we include code from another file, we include it and that's it, the code is now available to us within the file in which we performed the include. But in Vue.js, after importing a component we must also export it.
Why? Why don't we simply import it?
in Vue.js, after importing a component we must also export it.
I think you might be referring to the following lines in User.vue and wondering why UserDetail and UserEdit are imported into the file and then exported in the script export's components property:
import UserDetail from './UserDetail.vue';
import UserEdit from './UserEdit.vue';
export default {
components: {
appUserDetail: UserDetail,
appUserEdit: UserEdit
}
}
vue-loader expects the script export of a .vue file to contain the component's definition, which effectively includes a recipe to assemble the component's template. If the template contained other Vue components, the definition of the other components would need to be provided, otherwise known as component registration. As #Sumurai8 indicated, the import of the .vue files itself does not register the corresponding single-file-components; rather those components must be explicitly registered in the importer's components property.
For example, if App.vue's template contained <user /> and User.vue were defined as:
<template>
<div class="user">
<app-user-edit></app-user-edit>
<app-user-detail></app-user-detail>
</div>
</template>
<script>
export default {
name: 'user'
}
</script>
...the User component would be rendered blank, and you would see the following console errors:
[Vue warn]: Unknown custom element: <app-user-edit> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
[Vue warn]: Unknown custom element: <app-user-detail> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
demo 1
When Vue attempts to render <user /> inside App.vue's template, Vue doesn't know how to resolve the inner <app-user-detail> and <app-user-edit> because their component registrations are missing. The errors can be resolved by local component registration in User.vue (i.e., the components property shown above).
Alternatively, the errors can be resolved with global component registration of UserDetail and UserEdit, which would obviate the local registration in User.vue. Note that global registration must be done before creating the Vue instance. Example:
// main.js
import Vue from 'vue';
import UserDetail from '#/components/UserDetail.vue';
import UserEdit from '#/components/UserEdit.vue';
Vue.component('app-user-detail', UserDetail);
Vue.component('app-user-edit', UserEdit);
new Vue(...);
demo 2
Components in vue can be tricky. If you haven't yet, I would highly recommend reading the documentation on the vue.js website on how component registration works, specifically, as tony19 mentions global and local registration. The code example you show in your screenshot is actually doing a couple of things. For one, it is making the components available locally, and only locally (as in that .vue file) for use. In addition, it is making it available to the template as the key you provide in the components object, in this case, app-user-detail and app-user-edit instead of user-detail and user-edit.
Importantly, it should be mentioned that an import is not actually required for this component registration to function. You could have multiple components defined in a single file. The components key gives a way to identify what that component is using. So that import isn't required, so vue does require the components key to understand what you are using as a component, and what is just other code.
Finally, as some of the other answers have alluded to, the components key is not actually an export. The default signature of a vue component requires an export but this is not exporting the components listed under the components key. What it is doing is letting vue build in a top down manner. Depending on what the rest of your application setup looks like, you may be using single file components, or not. Either way, vue will start with the top level vue instance and work its way down through components, with the exception of global registration, no top level component knows which components are being used below it.
This means for vue to render things properly, each component has to include a reference to the extra components it uses. This reference is exported as part of the higher level component (in your case User.vue), but is not the component itself (UserDetail.vue).
So it may appear that vue requires a second export after import, but it is actually doing something else to allow the root vue instance to render your component.
As an aside, the vue documentation on this subject really is quite good, if you haven't already please take a look at the sections I linked above. There is an additional section on module import/export systems that seems highly relevant to what you are asking, you can find that here: Module-systems.
import imports code into the current file, but it does not do anything on its own. Imagine the following non-vue code:
// File helpers.js
export function tickle(target) {
console.log(`You tickle ${target}`)
}
// File main.js
import { tickle } from 'helpers'
You have imported the code, but it does not do anything. To actually tickle something, you need to call the function.
tickle('polar bear');
In Vue this works the same. You define a component (or actually just an Object), but the component does not do anything on it's own. You export this component so you can import it in other places where the Vue library can do something with this object.
In a Vue component you export your current component, and import components you use in your template. You generally do the following:
<template>
<div class="my-component">
<custom-button color="red" value="Don't click me" #click="tickle" />
</div>
</template>
<script>
import CustomButton from './CustomButton';
export default {
name: 'my-component',
components: {
CustomButton
}
}
</script>
Your component mentions a component named "custom-button". This is not a normal html element. It does not know what to do with it normally. So what do we do? We import it, then put it in components. This maps the name CustomButton to the component you imported. It now knows how to render the component.
The "magic" happens when you mount the root component using Vue, usually in your main.js.
import Vue from "vue";
import App from "./App";
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: "#app",
components: { App },
template: "<App/>"
});
What does this do? You tell Vue to render <App/> in a html element identified by #app, and you tell that it should find this element in ./App.vue.
But can't we just omit export if the Vue compiler was 'smarter'? Yes, and no. Yes, because a compiler can transform a lot of things into valid javascript, and no because it makes no sense and severely limits what you can do with your component, while also making the compiler more bug-prone, less understandable and overall less useful.
In order for App.vue to be able to use the User-component you need to export the default object of the User.vue-file.
In the export default { you don't actually export the newly imported components. You are just exporting a completely normal JavaScript Object. This object just happens to have a reference to another Object.
When you import an object (or function or array or ...) it does not actually load the content of that file in to your component like PHP. It simply makes sure that your compiler (probably webpack) knows how to structure the program. It basically creates a reference so webpack knows where to look for functionality.
TL;DR
The import and export here are conceptually different and unrelated things, and both have to be used.
Importing a Vue component is the same with any other importing in JavaScript:
// foo.mjs
export function hello() {
return "hello world!";
}
// bar.mjs
import { hello } from './foo.mjs';
console.log(hello());
Now run node bar.mjs, you will get a feeling how the importing works -- you want to use something that is defined/implemented somewhere else, then you have to import it, regardless of whether it is a Vue component or not.
With regard to export, you are not exporting the components you imported. The only thing you are exporting is the current component. However, this current component may use some other subcomponents in its <template>, so one has to register those subcomponents, by specifying them in the components field in the exported object.

vue.js 2 how use components in ES2015 webpack

I am trying to use vue-components in a webpack Typescript project but it doesn't seem to be working. I don't get any errors during the build and run, but the component HTML is never inserted into the output - I can just see the HTML source of the component instead i.e. .
My project is an ES2015 using Vue2 in VS.Net 2017. My component looks like this:
import Vue from 'vue'
import Component from 'vue-class-component'
// The #Component decorator indicates the class is a Vue component
#Component({
// All component options are allowed in here
template: '<button #click="onClick">Click!</button>'
})
export default class MyHeader extends Vue {
// Initial data can be declared as instance properties
message: string = 'Hello!'
// Component methods can be declared as instance methods
onClick(): void {
window.alert(this.message)
}
}
I have tried the official reference guide to register the component and use it. When I look at the vue-component example, it uses the same format as my project so I added the markup and properties to my Typescript class definition:
import Vue from 'vue';
import Component from 'vue-class-component';
import MyHeader from './MyHeader';
#Component({
components: {
MyHeader
}
})
export default class GetDataComponent extends Vue {
<...rest of class...>
}
but in my project the "components:" section is squiggly-underline-red with the message:
Object literal may only specify known properties, but 'components'
does not exist in type 'VueClass'. Did you mean to write
'component'?
Every example I have seen with vue-component (such as this one) uses the "components:" option in the #Component to register and use their Vue component, but in my project it doesn't seem to like it. I have also tried global registration of the component (such as this one) which includes the line:
// Register the component globally
Vue.component(my-header', MyHeader)`
but in that case I get an error like this:
Type 'typeof MyHeader' is not assignable to type 'AsyncComponent'
The Vue file works (without the Component added) and all content is rendered correctly. It's getting the Component included that doesn't work - I either get Design-time errors per above, or nothing appears in the output at all.
Is my import wrong? Or the format of the #Component? I get the feeling I am doing something that is very basic, very wrong...

did you register the component correctly? For recursive components, make sure to provide the "name" option

I configured 'i-tab-pane': Tabpane but report error,the code is bellow:
<template>
<div class="page-common">
<i-tabs>
<i-tab-pane label="wx">
content
</i-tab-pane>
</i-tabs>
</div>
</template>
<script>
import {
Tabs,
Tabpane
} from 'iview'
export default{
name:"data-center",
data(){
return {msg: 'hello vue'}
},
components: {
'i-tabs' : Tabs,
'i-tab-pane': Tabpane
}
}
</script>
Error traceback:
[Vue warn]: Unknown custom element: <i-tab-pane> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <DataCenter> at src/views/dc/data-center.vue
<Index> at src/views/index.vue
<App> at src/app.vue
I have tried in the main.js to global configuration:
Vue.component("Tabpane", Tabpane);
but still do not work.
How to resolve this issue?
If you're using a component within a component (e.g. something like this in the Vue DOM):
App
MyComponent
ADifferentComponent
MyComponent
Here the issue is that MyComponent is both the parent and child of itself. This throws Vue into a loop, with each component depending on the other.
There's a few solutions to this:
 1. Globally register MyComponent
vue.component("MyComponent", MyComponent)
2. Using beforeCreate
beforeCreate: function () {
this.$options.components.MyComponent = require('./MyComponent.vue').default
}
3. Move the import into a lambda function within the components object
components: {
MyComponent: () => import('./MyComponent.vue')
}
My preference is the third option, it's the simplest tweak and fixes the issue in my case.
More info: Vue.js Official Docs — Handling Edge Cases: Circular References Between Components
Note: if you choose method's 2 or 3, in my instance I had to use this method in both the parent and child components to stop this issue arising.
Since you have applied different name for the components:
components: {
'i-tabs' : Tabs,
'i-tab-pane': Tabpane
}
You also need to have same name while you export: (Check to name in your Tabpane component)
name: 'Tabpane'
From the error, what I can say is you have not defined the name in your component Tabpane. Make sure to verify the name and it should work fine with no error.
Wasted almost one hour, didn't find a solution, so I wanted to contribute =)
In my case, I was importing WRONGLY the component.. like below:
import { MyComponent } from './components/MyComponent'
But the CORRECT is (without curly braces):
import MyComponent from './components/MyComponent'
One of the mistakes is setting components as array instead of object!
This is wrong:
<script>
import ChildComponent from './ChildComponent.vue';
export default {
name: 'ParentComponent',
components: [
ChildComponent
],
props: {
...
}
};
</script>
This is correct:
<script>
import ChildComponent from './ChildComponent.vue';
export default {
name: 'ParentComponent',
components: {
ChildComponent
},
props: {
...
}
};
</script>
Note: for components that use other ("child") components, you must also specify a components field!
For recursive components that are not registered globally, it is essential to use not 'any name', but the EXACTLY same name as your component.
Let me give an example:
<template>
<li>{{tag.name}}
<ul v-if="tag.sub_tags && tag.sub_tags.length">
<app-tag v-for="subTag in tag.sub_tags" v-bind:tag="subTag" v-bind:key="subTag.name"></app-tag>
</ul>
</li>
</template>
<script>
export default {
name: "app-tag", // using EXACTLY this name is essential
components: {
},
props: ['tag'],
}
I had this error as well. I triple checked that names were correct.
However I got this error simply because I was not terminating the script tag.
<template>
<div>
<p>My Form</p>
<PageA></PageA>
</div>
</template>
<script>
import PageA from "./PageA.vue"
export default {
name: "MyForm",
components: {
PageA
}
}
Notice there is no </script> at the end.
So be sure to double check this.
If you have path to the component (which causes a cycle) to index.js, cycle will be begin. If you set path directly to component, cycle will be not. For example:
// WRONG:
import { BaseTable } from #/components/Base'; // link to index.js
// SUCCESS:
import BaseTable from #/components/Base/Table.vue';
I had this error and discovered the issue was because the name of the component was identical to the name of a prop.
import Control from '#/Control.vue';
export default {
name: 'Question',
components: {
Control
},
props: ['Control', 'source'],
I was using file components. I changed the Control.vue to InputControl.vue and this warning disappeared.
The high votes answer is right. You can checkout that you have applied different name for the components. But if the question is still not resolved, you can make sure that you have register the component only once.
components: {
IMContainer,
RightPanel
},
methods: {},
components: {
IMContainer,
RightPanel
}
we always forget that we have register the component before
This is very common error that we face while starting any Project Vue. I spent lot of time to search this error and finally found a Solution.
Suppose i have component that is "table.vue",
i.e components/table.vue
In app.js
Vue.component('mytablecomp', require('./components/table.vue').default);
So in in your index.blade file call component as
<mytablecomp></mytablecomp>
Just you need to keep in mind that your component name is in small not in large or camel case.
Then my above code will surely work for you.
Thanks
We've struggled with this error twice now in our project with different components. Adding name: "MyComponent" (as instructed by the error message) to our imported component did not help. We were pretty sure our casing was correct, as we used what is in the documentation, which worked fine for the other 99% of our components.
This is what finally worked for us, just for those two problematic components:
Instead of this (which, again, works for most of our components):
import MyComponent from '#/components/MyComponent';
export default {
components: {
MyComponent
}
We changed it to ONLY this:
export default {
components: {
MyComponent: () => import('#/components/MyComponent')
}
I can't find the documentation we originally found for this solution, so if anyone has any references, feel free to comment.
If you are using Vue Class Component, to register a component "ComponentToRegister" you can do
import Vue from 'vue'
import Component from 'vue-class-component'
import ComponentToRegister from '#/components/ComponentToRegister.vue'
#Component({
components: {
ComponentToRegister
}
})
export default class HelloWorld extends Vue {}
Adding my scenario. Just in case someone has similar problem and not able to identify ACTUAL issue.
I was using vue splitpanes.
Previously it required only "Splitpanes", in latest version, they made another "Pane" component (as children of splitpanes).
Now thing is, if you don't register "Pane" component in latest version of splitpanes, it was showing error for "Splitpanes". as below.
[Vue warn]: Unknown custom element: <splitpanes> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
In my case it was the order of importing in index.js
/* /components/index.js */
import List from './list.vue';
import ListItem from './list-item.vue';
export {List, ListItem}
and if you use ListItem component inside of List component it will show this error as it is not correctly imported. Make sure that all dependency components are imported first in order.
This is WRONG:
import {
Tabs,
Tabpane
} from 'iview'
This is CORRECT:
import Iview from "iview";
const { Tabs, Tabpane} = Iview;
In my case (quasar and command quasar dev for testing), I just forgot to restart dev Quasar command.
It seemed to me that components was automatically loaded when any change was done. But in this case, I reused component in another page and I got this message.
Make sure that the following are taken care of:
Your import statement & its path
The tag name of your component you specified in the components {....} block
i ran into this problem and below is a different solution. I were export my components as
export default {
MyComponent1,
MyComponent2
}
and I imported like this:
import { MyComponent1, MyComponent2} from '#/index'
export default {
name: 'App',
components: {
MyComponent1,
MyComponent2
},
};
And it gave this error.
The solution is:
Just use export { ... } don't use export default
In my case, i was calling twice the import...
#click="$router.push({ path: 'searcherresult' })"
import SearcherResult from "../views/SearcherResult"; --- ERROR
Cause i call in other component...
The error usually arises when we have used the Component (lets say VText) but it has not been registered in the components declaration of the Parent Component(lets say Component B).
The error is more likely to occur when using components in a recursive manner. For example using tag=VText in an tag, as importing the component in a such case will result in error from Eslint as the component is not directly being used in the template. While not importing the component will cause an error in the console saying the component has not been registered.
In this case, it is a better approach to suppress the ESLinter on registration line of the Component(VText in this case). This suppression is done through writing // eslint-disable-next-line vue/no-unused-components
Example code is below
<template>
<i18n path="AssetDict.Companies" tag="VText">
<template>
<span class="bold-500">Hi This is a text</span>
</template>
</i18n>
</template>
<script>
import { VButton, VIcon, VTooltip, VText } from 'ui/atoms'
export default {
name: 'ComponentB',
components: {
VButton,
VIcon,
CompaniesModifyColumn,
VTooltip,
// eslint-disable-next-line vue/no-unused-components
VText,
},
}
</script>
I just encountered this. Easy solution when you know what to look for.
The child component was the default export in it's file, and I was importing using:
import { child } from './filename.vue'
instead of
import child from './filename.vue'.
What happened to me was I had correctly registered the component in components but I had another components key defined at the bottom of my component, so I had two components definitions and it looked like the latter one overrode the previous one. Removing it made it work.
I encounter same error msg while using webpack to async load vue component.
function loadVMap() {
return import(/* webpackChunkName: "v-map" */ './components/map.vue')
.then(({ default: C }) => {
Vue.component('ol-map',C);
return C;
})
.catch((error) => 'An error occurred while loading the map.vue: '+error);
}
I found that the then function never executed.
so I reg this component out of webpack import
import Map from './components/map.vue'
Vue.component('ol-map',Map);
Then I could gain the detailed error msg which said I used a var which is not imported yet.
I ran into this problem when:
I had components defined twice.
Used component instead of components.
I hope this helps others.
The question has been answered very well by #fredrivett here, but I wanted to add some context for other encountering the Circular Reference error when dealing with variables in general.
This error happens with any exported object not just components.
Exporting a variable from parent and importing it in a nested child:
🌐 EXAMPLE
<script>
// parent
export const FOO = 'foo';
...
</script>
❌ WRONG
<script>
// child
import { FOO } from 'path/to/parent'
export default {
data() {
return {
FOO
}
}
}
</script>
✅ CORRECT
<script>
// child
export default {
data() {
return {
FOO: require('path/to/parent').FOO
}
}
}
</script>
Note: in case you are dealing with objects you might want to create a global state which might serve you better.
I'm curious to know if this approach makes sense or it's an anti pattern.
In my case the child component name was "ABCChildComponent" and I was referring in the HTML as assuming it to work correctly. But, the correct name should be or . Hence, changed the name to "AbcChildComponent" and referring in the HTML works fine.
WRONG WAY :
import completeProfile from "#/components/modals/CompleteProfile";
export default {
components: completeProfile
};
RIGHT WAY :
import completeProfile from "#/components/modals/CompleteProfile";
export default {
components: {completeProfile} // You need to put the component in brackets
};