VueJS nested components fail in an NPM package - javascript

The example below are using simplified examples.
Both components work separately, however when one is nested within the other neither render on the page.
index.js (entry point)
// Test components
import TestComponent from '../src/TestComponent.vue'
import Test2Component from '../src/Test2Component.vue'
export {
TestComponent,
Test2Component
}
Both TestComponent and Test2Component will render this way:
<template>
<div class="container">
<TestComponent></TestComponent>
<Test2Component></Test2Component>
</div>
</template>
<script>
import Vue from 'vue'
import { TestComponent, Test2Component } from 'myPackage'
Vue.component('TestComponent', TestComponent);
Vue.component('Test2Component', Test2Component);
However if I move the Test2Component tag into Test1Component.Vue:
<template>
<p>This is the TestComponent</p>
<Test2Component></Test2Component>
</template>
<script>
import Vue from 'vue'
import Test2Component from './Test2Component';
Vue.component('Test2Component', Test2Component);
console.log( Test2Component)
export default {
name: 'TestComponent',
components: {
Test2Component
}
}
</script>
Not even the TestComponent.vue parent component renders.

I found the solution. Do not import Vue from 'vue' and modify it, this is a duplicate of the Vue instance. This syntax seems especially restrictive to get it to work when packaging.
Instead add it as a component to export default:
<script>
import { TestComponent, Test2Component} from 'myPackage'
export default {
components: {
'test-component': TestComponent,
'test2-component': Test2Component
},
...
</script>

Related

VueJS 3 Warn export compoment was not found in '#/components/...vue'

I'm using VueJS 3 applications using vue-router, vue and core-js applications where I want using compoments. I have in views dirrectory Home.vue file which looks like this:
<template>
<div class="wrapper">
<section v-for="(item, index) in items" :key="index" class="box">
<div class="infobox">
<PictureBox image="item.picture" />
<PropertyBox itemProperty="item.properties" />
</div>
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { data } from '#/data.js'
import { PictureBox } from '#/components/PictureBox.vue'
import { PropertyBox } from '#/components/PropertyBox.vue'
export default {
components: {
PictureBox,
PropertyBox,
},
methods: {
addRow() {
console.log('This add new row into table')
},
},
setup() {
const items = ref(data)
return {
items,
}
},
}
</script>
I have 2 compoments in compoments directory
src/compoments
|- PictureBox.vue
|- PropertyBox.vue
and for example in PictureBox.vue I have this content:
<template>
<div class="infobox-item-picturebox">
<img class="infobox-item-picturebox-image" :src="require(`#/static/${image}`)" alt="item.title" />
</div>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
props: {
image: {
type: String,
},
},
setup() {
const state = reactive({
count: 0,
})
return {
...toRefs(state),
}
},
}
</script>
But I have Warning at compiling:
WARNING Compiled with 2 warnings 10:58:02 PM
warning in ./src/views/Home.vue?vue&type=script&lang=js
"export 'PictureBox' was not found in '#/components/PictureBox.vue'
warning in ./src/views/Home.vue?vue&type=script&lang=js
"export 'PropertyBox' was not found in '#/components/PropertyBox.vue'
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.187.102:8080/
Also in Browser Developer mode I have same warnings:
My Directory structure looks like this:
And my main.js looks like here:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './assets/style.css'
createApp(App).use(router).mount('#app')
And router page (I'm not using router actually looks like here)
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
export default router
Please, can you help me why I have this warning and my content from <template> in PictureBox or in PropertyBox was not loaded? Thank you so much for any advice
The component instance is exported as default (export default {...) in its single file and it should be imported like :
import PictureBox from '#/components/PictureBox.vue'
instead of:
import { PictureBox } from '#/components/PictureBox.vue'

Vue.js with TypeScript getting data from Twig error Property does not exist

I'm having trouble printing out the data from Twig template on my Symfony app. I am using Vue.js with TypeScript enabled.
main.ts:
import HeaderNav from './components/HeaderNav.vue'
new HeaderNav({el: '.headnav'});
HeaderNav.vue:
<template>
<div class="headnav headnav-fixed z-depth-1">
{{test}}
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { Component, Emit, Prop, Watch } from 'vue-property-decorator';
#Component({
props: {
test: {
type: String,
default: "{}"
}
},
mounted: function () {
console.log(this.test);
}
})
export default class HeaderNav extends Vue {}
</script>
header.html.twig:
<div class="headnav" data-test="hello"></div>
I get this error while compiling:
Property 'test' does not exist on type 'Vue'.
Any ideas that am I doing wrong? I am thinking that calling the component HeaderNav first might be the problem, because it instantly overrides the element with class 'headnav', but I am trying to create the components only for separate elements on my site, I don't want to put whole application into Vue.js.
I hope the problem is with you defined props.
In Vue with typescript you need to use props like this:
import { Component, Prop, Vue } from 'vue-property-decorator';
#Component({
name: "HeaderNav"
})
export default class HeaderNav extends Vue {
#Prop({ default: '' }) test!: string;
created(){
console.log(this.test)
}
}
I hope this will help you.
For more information checkout this article: https://blog.logrocket.com/how-to-write-a-vue-js-app-completely-in-typescript/

Vue plugin with Typescript - Cannot read property '_init' of null

I need to create Vue plugin containing a few reusable components. I want to create this using TypeScript. There are my files:
components/SampleButton.vue
<template>
<button>Sample button</button>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
name: 'sample-button',
});
</script>
main.ts
import SampleButton from './components/SampleButton.vue';
export {
SampleButton,
};
export default {
install(Vue: any, _options: object = {}): void {
Vue.component(SampleButton.name, SampleButton);
},
};
shims-vue.d.ts
declare module '*.vue' {
import Vue from 'vue';
export default Vue;
}
Plugin building is successful, but when I try to user the plugin in my app I get an error:
import MyPlugin from 'my-plugin'
Vue.use(MyPlugin)
Please help me find a mistake :)

How to register component in vue+ts correctly?

I have this code:
App.vue
<template>
<v-container>
<div>
<schedule-table
v-if = "schedule.length > 0"
:exercises="schedule[0].exercises"
/>
</div>
</v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Component } from "vue-property-decorator";
import ScheduleTable from '#/components/ScheduleTable.vue'
#Component({
components: {
ScheduleTable,
}
})
</script>
ScheduleTable.vue
<template>
<v-container>
<schedule-week
:exercises="exercises"
/>
</v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Component, Prop } from "vue-property-decorator";
import { IExercise } from "#/interfaces"
import ScheduleWeek from '#/components/ScheduleWeek.vue'
#Component({
name: 'ScheduleWeek',
components: {
ScheduleWeek,
}
})
#Component
export default class ScheduleTable extends Vue {
#Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>
ScheduleWeek.vue
<template>
<v-container
:ex="exercises"
>
here is tables (but this tables dosn't show and any other text dosn't show)
</v-container>
</template>
<script lang="ts">
import Vue from "vue";
import { Component, Prop } from "vue-property-decorator";
import { IExercise } from "#/interfaces"
#Component
export default class ScheduleWeek extends Vue {
#Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>
And have vue warn:
Unknown custom element: < schedule-week > - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.
How to fix this problem? How to register component correctly?
There are multiple ways to declare a vue-component when you use typescript. The class-based SFC approach (the one you are using) needs to follow a slightly different syntax. You used the typescript decorator twice in your schedule-week component
App.vue
<v-container>
<div>
<schedule-table
v-if = "schedule.length > 0"
:exercises="schedule[0].exercises"
/>
</div>
</v-container>
</template>
<script lang="ts">
import { Component, Vue } from "vue-property-decorator"; // you can import vue here
import ScheduleTable from '#/components/ScheduleTable.vue'
#Component({
components: {
ScheduleTable,
}
})
export default class App extends Vue {} // the #Component() decorator needs to be followed by the exported class
Correspondingly your other components:
ScheduleTable.vue
<template>
<v-container>
<schedule-week
:exercises="exercises"
/>
</v-container>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"; // see above
import { IExercise } from "#/interfaces"
import ScheduleWeek from '#/components/ScheduleWeek.vue'
#Component({
name: 'ScheduleTable',
components: {
ScheduleWeek,
}
}) // >>>don't use the decorator twice<<<
export default class ScheduleTable extends Vue {
#Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>
ScheduleWeek.vue
<template>
<v-container
:ex="exercises"
>
here is tables (but this tables dosn't show and any other text dosn't show)
</v-container>
</template>
<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"; // see above
import { IExercise } from "#/interfaces"
#Component
export default class ScheduleWeek extends Vue {
#Prop( {required: true, type: Array } ) readonly exercises!: IExercise;
}
</script>
##EDIT:
From the officiel TypeScript Documentation:
With the introduction of Classes in TypeScript and ES6, there now exist certain scenarios that require additional features to support annotating or modifying classes and class members. Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members.
Decorators are basically TypeScript(JavaScript) functions which are used to add additional information to the following class (your component) or class members. This also means a decorator cannot stand alone. The #Component() decorator takes an Object as parameter which is 'as-is' translated into component-options.
TL;DR
To register the components SubOne and SubTwo in MyComponent, pass it to the #Component decorator:
import { Component, Vue } from "vue-property-decorator";
#Component({
components: {
SubOne,
SubTwo,
}
})
export default class MyComponent extends Vue {
…
}
And make sure you also decorate the SubComponents like so;
import { Component, Vue } from "vue-property-decorator";
#Component
export default class SubOne extends Vue {
…
}
Error in #MarcRo's answer
Setup and resulting Error
In the Component ScheduleTable.vue, the decorator #Component gets the parameter name set to the Component it is about to import. This leads to a recursive call of said Component and hence an Error.
Fix
Set name: 'ScheduleTable' - or even drop it. The class name seems to be used (which is what we are doing).
Aside
I could not find a doc on what can actually passed to the decorator, but it's used like this in #MarcRo's answer in App.vue as well as here. (The link in the comments there seems to be old).
I don't have enought reputation to comment and a fixing edit got rejected, so sorry for the extra post.
Thank you #MarcRo for teaching me how to use this and the facepalm moment after solving the recursion error after a way too long time ;)

Where to import component in Vue?

New to Vue, working off a scaffolded project from the command line. Currently I have:
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home
from '../components/home'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
}
]
})
main.js
import Vue from 'vue'
import App from './App'
import router from './router'
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style>
#app {
// default styles are here
}
</style>
And home.vue
<template>
<chart-component></chart-component>
</template>
// rest of home
I am trying to create and import chart-component.vue to use inside home.vue but not sure where to import it at. I've tried adding it in main.js and App.vue unsuccessfully.
chart-component.vue
<template>
<div>
<h1>Testing Chart Component</h1>
</div>
</template>
<script>
export default {
name: 'chart',
data() {
return {
}
}
}
</script>
This seems like a simple problem but unsure how to solve it. My best guess was importing it inside App.vue and adding a components { ChartComponent } underneath the name. Second attempt was importing it into main.js and putting ChartComponent inside components: { App, ChartComponent }.
I would rename your component to ChartComponent from chart-component, as the dash is not a supported character. Vue will properly convert the name to dashes as needed, but when you're searching your code for components, it helps to have consistent names.
anyway. for using a component, you need to import it and define it first
home.vue:
<template>
<ChartComponent></ChartComponent>
</template>
<script>
import ChartComponent from './ChartComponent';
export default {
components: {
ChartComponent
}
}
</script>
Got it to work. Since I only need it locally inside the home.vue component I imported it inside there under data I added
components: {
'chart-component': ChartComponent
}
Importing component becomes much easier in Vue 3 script setup SFCs
<script setup>
import ChartComponent from './components/ChartComponent.vue'
</script>
<template>
<ChartComponent />
</template>

Categories