How to create new component with #vue/composition-api in TS file? - vue.js

I have some components that I need to create in the TS file. Usually, I create by calling new Component because on our project we have vue-component-decorator but now I'm starting using #vue/composition-api and I can't call any component as new.
Working:
// SomeComponent.vue
import { Vue, Component } from 'vue-component-decorator';
#Component
export default SomeComponent extends Vue {}
// Any .ts file
const component = new SomeComponent();
Not working:
// SomeComponent.vue
import { defineComponent } from '#vue/composition-api';
export default defineComponent({});
// Any .ts file
const component = new SomeComponent();

You need to use createApp to create the component and mount it programmatically:
const myComponent = defineComponent({/* */})
createApp(myComponent, { /* Pass props here */ }).mount('#container');
Sources:
github vuejs issue#629
StackOverflow question #64251487

Related

Vue Test Utils with Jest - Mixins not working

I have created a local Vue app and I need to mix a method into all components. The problem is whenever I mount the app the method does not appear to be mixed for child components. Here is my code:
import { createLocalVue, mount } from '#vue/test-utils'
import {gc} from '.....';
import .... from ....
const App = createLocalVue()
App.use( .... )
App.mixin({
methods: {
gc: key => gc(key)
}
})
export const Wrapper = mount(AppComponent, {
App,
i18n,
router,
store,
...
})
Whenever I import "Wrapper" into any test it fails to the first mounted component with message:
TypeError: _vm.gc is not a function
How can I include mixins to propagate to all the child components?
mount has no App option. Instead, there's localVue to supply Vue copy.
It should be:
mount(AppComponent, {
localVue: App,
...

How I can access $data variable of a Mixin.js file from Store.js using Vue.Js?

I have a Mixin file like this:
export default {
data: function() {
return {
analysisTime: "nothing",
phantomPrefix: "One more",
}
},
methods: {
isGeneric: function() {
return this.phantomPrefix
},
}
}
Whenever I call Mixin.js its methods are accessible but the $data variable is returning undefined.
For example, Whenever I called isGeneric function it's returning undefined instead of 'one more' because it's returns this.phantomPrefix.
Ps: If I access the same method of Mixin.js file from another component let's say Example.Vue it's working fine for me.
I have imported the Mixin file in store.js like:
import Mixin from "./mixins/Mixin";
and calling method like this: Mixin.methods.isGeneric()
Store.js file contains:
import Vue from "vue";
import Vuex from "vuex";
import tmpMixin from "./mixins/tmpMixin";
Vue.use(Vuex);
let vue_plugins = [];
export default new Vuex.Store({
plugins: vue_plugins,
state:{},
action:{
get_snippet_data_using_tomograph: function(data) {
let output = tmpMixin.methods.isGeneric()
}
}
});
Vue mixins are made for Vue components, it's not compatible with a Vuex module.
A mixins expect a Vue component instance, which is not provided by Vuex when you import it like this.
If you need to have a reusable code between a Vuex store and Vue components, you still can create a simple js file that exports a functions. But it won't be reactive or have a current state because it's not a Vue component.

importing store to a vuejs nuxt project

I'm trying to write a simple plugin for my Vue.js(Nuxt) project. I came across this post Adding Mutations to Vuex store as part of Vue Plugin but still unable to get it working.
Here is my application structure.
~ is root
~/plugins/HTTP/index.js
~/plugins/HTTP/_store/ => index.js, actions.js, getters.js, mutations.js
~/plugins/HTTP/_api/ => index.js
**Global Store**
~/store/index.js
~/store/modules/
~/store/modules/testing => index.js, actions.js, getters.js, mutations.js
in my ~/plugins/HTTP/index.js, I have the following code
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP)
In my ~/store/index.js I have the following code:
import Vuex from 'vuex'
import testingModule from './modules/testing'
const state = () => {
return new Vuex.Store({
modules:{
testing: testingModule
}
})
}
export default state
When I try to run it, it gives me the following message:
Cannot destructure property `store` of 'undefined' or 'null'.
What did I do wrong here?
You aren't passing any properties so the error is correct. You need pass in an options object when you tell it to use. It can be empty, but it needs an object.
import Vue from 'vue';
import store from '~/store';
const HTTP = {
install(vue, { store }){ // Now you plugin depend on store
if(!store){
throw new Error('Please provide vuex plugin.')
}
// register your own vuex module
store.registerModule({store})
}
}
export default HTTP;
Vue.use(HTTP, {}) // <---------- Empty object to avoid allow destructuring.

Looking for a convenient way to import the frequently-used components in component?

Is there a convenient way to import the frequently-used components?
When I write the components, if it need import other components, I will import and register them one by one:
import MyButton from './myButton'
import MyInput from './myInput'
import MyIcon from './myIcon'
export default {
components: {
MyButton,
MyInput,
MyIcon
}
}
whether there is a simple way to import them?
You just need use the webpack function to create a context, then import automatically.
create a common_components.js file in the components directory:
import Vue from 'vue'
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
// find all the *.vue under the `components` directory
const requireComponent = require.context(
'.', false, /\.vue$/
)
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName)
const componentName = capitalizeFirstLetter(
fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')
)
Vue.component(componentName, componentConfig.default || componentConfig)
})
then in the main.js import the common_components.js, you can use all the components under the components directory now.

Vue.js / Mixins - Is there a way to get the global mixin-object outside of the vue component?

I am new with Vue.js
I am using Vue.js 2.4.4.
I have created the global mixin in my app.js file:
...
import router from './router'
...(some imports and plugins definitions)
Vue.use(VeeValidate);
Vue.component(VuePassword);
...
Vue.mixin({
data: function(){
return {
get auth(){
return Auth;
}
}
}
});
const app = new Vue({
el: '#root',
template: `<app></app>`,
components: { App },
router
});
This mixin imports some Auth object with validation methods e.t.c which needed to be in every component.
All of my components can check this mixin and it's working fine.
But I need to check the auth state after every route request, and I want to use my currently existing mixin, so I am trying to make something like this in my router.js file:
import Vue from 'vue'
import VueRouter from 'vue-router'
...
Vue.use(VueRouter);
const router = new VueRouter({
routes:[
...
]
});
router.beforeEach((to, from, next) => {
if(to.meta.requiresAuth) {
if(...call to mixin method) {
next();
} else {
next('/');
}
} else {
next();
}
});
export default router
Question:
Is there a way to get the global mixin object and change it's inner values or can you please give some small advise or example what is the right solution to this kind of tasks?
Or should I use the plugins instead of mixins?
I would rather create a seperate file for auth and not make it a mixin. Then using Vue.use() which will set auth on the vue object.
A sample of what the files might look like:
auth.js
export default function(Vue) {
Vue.auth = {
// do your auth logic
}
}
Then in your main js file
main.js
import Auth from './auth.js'
Vue.use(Auth);
Then you should be able to use Vue.auth
Another option would be keep using the mixin and pass the value to a store (like vuex) or create your own if your project is small...