My Vue components work fine when declared in the top level HTML file, like this
<body>
<div class='app' id='app'>
<header-bar id='headerBar'></header-bar>
<journal-page></journal-page>
</div>
<script src="js/app.js"></script>
</body>
but using a <journal-card> component inside the <journal-page> component gives me the error:
[Vue warn]: Failed to resolve component: journal-card at <JournalPage>.
How do I fix this please?
Here's my top level code that loads the Vue components, app.js:
import * as _vue from 'vue';
import _headerBar from './widgets/headerBar.vue';
import _journalCard from './widgets/journalCard.vue';
import _journalPage from './widgets/journalPage.vue';
import _store from './data/store.js';
const app = _vue.createApp
({
components:
{
'headerBar': _headerBar,
'journalCard': _journalCard,
'journalPage': _journalPage
},
data : _store,
methods: {}
});
const mountedApp = app.mount('#app');
and here's my journal-page.vue container
<template>
<ul>
<journal-card v-for="item in journal" :key="item.id" :entry=item></journal-card>
</ul>
</template>
<script lang="js">
import _store from '../data/store.js';
export default {
'data': _store
};
</script>
and journal-card.vue component
<template>
<div>
hi imma journal entry
</div>
</template>
<script lang="js">
export default {
'data': null,
'props': [ 'entry' ]
};
</script>
Registering components in the root component's components option doesn't make them global. Doing that just makes them available to the root component itself, not its children.
To register components globally, use app.component in your top-level code:
main.js
import { createApp } from 'vue';
import App from './App.vue';
import MyGlobalComponent from './components/MyGlobalComponent.vue';
const app = createApp(App);
app.component('MyGlobalComponent', MyGlobalComponent); ✅
const mountedApp = app.mount('#app');
In my scenario issue was different. I was trying to render a similar multi word Vue component in a laravel blade file.
If you're referring a Vue component in a non .Vue file (like HTML / Laravel Blade etc), you should use kebab-cased format to refer the component name. Like my-global-component
Vue documentation - https://vuejs.org/guide/essentials/component-basics.html#dom-template-parsing-caveats
Also as a side note since this page shows up when looking in search engines for some problems with "Vue 3 Failed to resolve component", there are a few things that were deprecated with Vue 3 / Quasar 2:
eg. q-side-link
that silently disappeared (previous doc here)
as per this comment:
QSideLink -- no longer required! Simply use a QItem or whatever
component you want and bind an #click="$router.push(...)" to it.
Sorry if it's not exactly on topic but it will bite some other people, so I prefer to help one person with this comment ;-)
make sure the mounting code comes at last so
app.mount('#app')
app.component('list-view', ListView2)
is wrong and it will not work but
app.component('list-view', ListView2)
app.mount('#app')
is correct.
Related
I am migrating a project from Vue 2 to Vue 3. I need to determine if a component is loaded and if it isn't, load a GenericComponent as a placeholder. In Vue 2 I was able to do it with the sample code. I have been reading the Vue 3 docs but I am unable to find anything about this.
import Vue from 'vue'
import GenericComponent from 'components/GenericComponent'
if (!Vue.options.components['custom-component']) {
Vue.component('custom-component', GenericComponent)
}
You can do like this:
import { getCurrentInstance } from 'vue';
const app = getCurrentInstance()
console.log('app component', app?.appContext.components['component-name'])
Note that appContext.components will only contain global components.
I am new to Vue and have previously used React to build small apps.
Now, I was going through through the boilerplate code for Vue
Consider this app.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
Here, I am unable to comprehend following things related to import and export.
Starting from the beginning
<HelloWorld msg="Welcome to Your Vue.js App"/>
here it seems we passing props to our child component.
In react, we used to import statements at the top of the app and then use it in our stateful or stateless component but in contrast, in the above code snippet we are importing it after inside the script tag so as JS compiles the code, how would it know what
<HelloWorld msg="Welcome to Your Vue.js App"/>
is HelloWorld? since it is declared afterwards.
Secondly, I have always worked with exporting and importing functions/classes and this is different and now for me to comprehend. Consider this children component
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
Here, I am unable to comprehend what is happening in export default? I know what export default does but like what is the significance of having properties like name and props inside it?
It's the way Vue is structured. The export default part that you write in the bottom is the part you import/export to the Vue ecosystem (and to your components), this is an ES6/ES2015 feature(module system), one thing to note that the structure you are using is called Single File Components (.vue files).
One great thing about single file components that I like is that you can import another component within the script tag (See: Component Registration), just above export default, then you can reference it in the export default object(exposing it to your component).
I am new to Vue and Vuetify. I just created quick app to check both of them. But I am a running into issues in beginning. The vue fails to identify vuetify components despite following all the steps outlined in document. The error is like below -
vue.runtime.esm.js?ff9b:587 [Vue warn]: Unknown custom element:
- did you register the component correctly? For recursive
components, make sure to provide the "name" option.
found in
---> at src\App.vue
You can access the entire code at sandbox https://codesandbox.io/s/40rqnl8kw
You're likely experiencing a problem with the order of your operations. You're defining your own App component that uses the v-app component before you've even told Vue to make use of it, so Vue assumes you're using your own custom v-app component.
Place Vue.use(Vuetify) before starting any Vue instances via new Vue() that require Vuetify components, or place it within the component definitions themselves right at the top of the <script> tag after importing Vue and Vuetify within the single file component. Don't worry if you have more than one Vue.use(Vuetify) statement because only the first one will do anything--all subsequent calls will simply do nothing.
Original - Vue.use() is called before new Vue(), resulting in an error.
new Vue({
el: "#app",
components: { App },
template: "<App/>"
});
Vue.use(Vuetify);
Fix - Calling new Vue() after Vue.use() allows Vue to resolve the dependency correctly.
Vue.use(Vuetify);
new Vue({
el: "#app",
components: { App },
template: "<App/>"
});
There is another reason for this error that I recently ran into.
I recently upgraded from Vuetify 1.5 to 2.x and even though I had the order of operations correct as in the currently accepted answer here I was still receiving the error about v-app being unknown:
Unknown custom element: <v-app> - did you register the component
correctly? For recursive components, make sure to provide the "name"
option.
Turns out that the upgrade process requires the following addition to package.json devDependencies section which didn't originally exist in my vuetify 1.5x package:
"vuetify-loader": "^1.3.0"
(1.3.0 current version as of this writing)
Once I added that the error went away.
If you are coming from Google: for me it was breaking changes from v1 to v2, that made most Codepen examples useless.
I had to change this to get a very simple Vuetify app with navigation drawers to run again:
remove toolbar from <v-app toolbar>
replace v-toolbar with v-app-bar
replace v-app-bar-side-icon with v-app-bar-nav-icon
replace v-app-bar-title with v-toolbar
replace v-list-tile to v-list-item
replace all flat with text
Maybe this helps someone.
(edited to include cong yu's remark)
Edit: it looks like VuetifyLoader will automatcially do that for you.
Old Answer: Another possible problem is if you have a la carte enabled you will need to also specify all the components that you want included:
import Vue from 'vue'
import App from './App.vue'
import Vuetify, {
VApp, // required
VNavigationDrawer,
VFooter,
VToolbar,
VFadeTransition
} from 'vuetify/lib'
import { Ripple } from 'vuetify/lib/directives'
Vue.use(Vuetify, {
components: {
VApp,
VNavigationDrawer,
VFooter,
VToolbar,
VFadeTransition
},
directives: {
Ripple
}
})
With vuetify v2.x you should register the vuetify plugin as follows :
import Vue from 'vue'
/** register vuetify plugin globally **/
import Vuetify from 'vuetify/lib'
Vue.use(Vuetify)
const opts = {}
const vuetify= new Vuetify(opts)
/****/
new Vue({
vuetify,
}).$mount('#app')
Vuetify v3
import { createApp } from 'vue'
import App from './App.vue'
/*****/
import '#mdi/font/css/materialdesignicons.css'
import 'vuetify/lib/styles/main.sass'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
const vuetify= createVuetify({
components,
directives,
})
/****/
const app = createApp(App)
app.use(vuetify)
app.mount('#app')
I experienced the same issue. It was caused by the cache of the browser make sure to clear the cache as well.
You will get this error even after installing the official Vuetify 3 (Alpha), due to the standard demo version generated during the install lacking adding components, i.e:
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
const vuetify = createVuetify({
components,
directives,
});
Thus the working version of main.ts for Vuetify 3 is:
import "vuetify/styles"; // Global CSS has to be imported
import { createApp } from "vue";
import { createVuetify } from "vuetify";
import App from "./App.vue";
import * as components from "vuetify/components";
import * as directives from "vuetify/directives";
const app = createApp(App);
const vuetify = createVuetify({
components,
directives,
});
app.use(vuetify).mount("#app");
// or app.use(vuetify); app.mount("#app");
In case someone like me new working on vue and nuxt. My mistake was that I did not put the s in the last. buildModule should be buildModules.
My nuxt.config.js:
export default {
buildModules:[
"#nuxtjs/vuetify"
],
module:[
"#nuxtjs/axios"
],
components:true
}
At this project I'm working on there is a legacy server-rendered web page and some components had problems I've been assigned to fix, and I convinced the team to rewrite those parts in Vue to kickstart our migration.
I wrote the whole mini-app using the Webpack template provided by Vue CLI and it works like a charm... in that specific environment.
If I npm run build the built index.html also works fine in a static server.
However, I can't seem to include the app in an existing page composed of many other elements. Shouldn't it be as simple as adding the <div id='myApp'></div> element to the HTML and loading the generated JS files?
If it helps, the legacy app is a Rails app using .erb templates and the JS files are being loaded through the main pipeline in application.js.
Does anyone know why nothing happens when I try this?
Edit: more information - this is how main.js looks before build:
/* eslint-disable */
import Vue from 'vue'
// UI components
import VueSelect from 'vue-select'
import DynamicForm from './components/DynamicForm/'
Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false
const DynamicForms = new Vue({
el: '.dynamic-form',
render: h => h(DynamicForm)
})
Edit: I managed to get Vue to work by integrating Webpack to Rails with Webpacker. However I still have some problems regarding context:
This is my main.js in one of the Vue components. It was working fine until I tried the PropData stunt so I could reuse the component with different data in a few places.
/* eslint-disable */
import Vue from 'vue'
// UI components
import VueSelect from 'vue-select'
// import 'nouislider'
import DynamicForm from './components/DynamicForm/'
import fields from './fields'
import fieldRules from './field-rules'
Vue.component('vue-select', VueSelect)
Vue.config.productionTip = false
document.addEventListener('DOMContentLoaded', () => {
const el = document.createElement('div')
document.querySelector('.dynamic-form').appendChild(el)
const vm = new DynamicForm({
propsData: {
fields,
fieldRules
},
el,
render: h => h(DynamicForm)
})
})
This is DynamicForm/index.vue
<template>
<div id='app'>
<ParamList :fields='paramFields' :fieldRules='paramRules'></ParamList>
<Output></Output>
</div>
</template>
<script>
import Vue from 'vue'
import ParamList from './ParamList'
import Output from './Output'
export default Vue.extend({
props: [ 'fields', 'fieldRules' ],
name: 'DynamicForm',
components: {
ParamList,
Output
},
data () {
return {
paramFields: this.fields,
paramRules: this.fieldRules
}
}
})
</script>
<style>
</style>
The field and fieldData props are merely JSON/JSONP with some data I'm going to use inside those components. The idea is that I could write another main.js changing just the field and fieldData when initing the Vue instance.
What am I doing wrong?
I've managed to fix everything in a three-step change to my components.
Integrate Webpack into Rails using Webpacker. There's even a Vue template!
Change the root component (the one mounted at a real DOM element) to a Vue subclass using Vue.extend (so the module line # the .vue file read export default Vue.extend({ instead of simply export default {
Remove the render function from the new DynamicForm (the name I assigned Vue.extend to) so it renders its own template.
I hope it helps as it was quite a pain to me!
I've just started working with Vue.JS and there's one small issue that's bugging me. My file structure similar to the following:
+ js
|--+ components
| |-- parent.vue
| |-- child.vue
|-- main.js
Then in my main.js I have the following:
window.Vue = require('vue');
require('vue-resource');
Vue.component('parent', require('./Components/parent'));
Vue.component('child', require('./Components/child'));
var app = new Vue({ el: "#app" });
(I'm not actually certain what vue-resource is, but this was set up for me by a fresh install of Laravel 5.3)
At a glance I immediately noticed that my main.js file was going to get unmanageable if I added too many components. I don't have this issue when working with ReactJS because main.js only needs to include the "parent" component, and the parent component includes the child component. I figured Vue.JS would have a similar trick to help me organize my components - but reading through the docs I didn't find one (maybe I missed it?)
Is there a way to either have a Vue component list its dependencies (for Browserify / Webpack to bundle) or recursively run a javascript statement on every file in a directory (so Browserify / Webpack just packs up the whole thing)?
I'm not concerned with async components at the moment - so if the solution breaks that functionality it will be okay. One day I would like to play around with using Webpack to create async components and only loading them as I need them, but today I'm more interested in just getting this up and running so I can play way Vuex.
The Vue.component syntax is for global components only, if you have a component that is being used inside another component use this:
import Parent from './components/Parent.vue';
import Child from './components/Child.vue';
new Vue({
el: "#app",
components: { Parent, Child }
});
Than inside this components you can use the other components.
The only advantage of using Vue.component(Parent) is that you can use this <parent></parent> component globaly in all your other components without declaring them implicitly.
Good Luck :)
You don't need to import everything at the top level.
In your main.js you can import the Parent component
import Parent from './components/Parent.vue'
new Vue({
el: "#app",
components: {
Parent
}
})
With your Parent.vue
<template>
<div>
<p>I am the parent</p>
<child></child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
mounted() {
console.log('mounted parent')
}
}
</script>
<style scoped>
// ...
</style>
Then in your Child.vue
<template>
<p>I am the child</p>
</template>
<script>
export default {
mounted() {
console.log('mounted child')
}
}
</script>
<style scoped>
// ...
</style>
And you should end up with
<div>
<p>I am the parent</p>
<p>I am the child</p>
</div>
I found a way, not sure if it's the best in terms of performance and webpack chunk size. I created an index.js file in the components root:
export const HelloWorld = require('./HelloWorld.vue').default
So, inside the components I would use:
const { HelloWorld } = require('#/components')
Due to babel issues I need to make a mix of require and export, also the use of default attribute after require — as I read in some babel use discussions.