After look at the nuxt plugins documentation, I found a possible solution to this problem. I defined my plugin as follow
plugins/hello.ts
import { Context } from '@nuxt/types';
import Vue from 'vue';
export default function (_ctx: Context, inject: Function) {
const hello = function (this: Vue, msg: string) {
console.log('emitting', msg);
if (process.server) {
console.log('server side');
} else {
console.log('client side');
}
setInterval(() => {
this.$nuxt.$emit('hello', msg);
}, 5000);
} // Event Bus
.bind(new Vue());
inject('hello', hello);
}
Pay attention that I used anonymous function(...){} and not an arrow function () => {...}. Updated don't forget to bind(new Vue()) the event bus otherwise if you call this.$alert in your vuex store this will be an instance of Store and not Vue as expected.
And I'm using it as the follow
page/something.vue
...
mounted() {
this.$hello('test');
this.$nuxt.$on('hello', (val: string) => {
alert(val);
});
},
...
And it works as expected! As I'm using typescript I need to defined this as Vue to avoid this.$nuxt is not defined error.
And in my nuxt.config.js
...
plugins: [
// '~/plugins/axios'
{ src: '~plugins/vuedraggable.ts' },
{ src: '~plugins/hello.ts' },
],
...
I hope this help you somehow.
Updated:
If you are using typescript and wants to merge (Module Augmentation) $hello so it becomes visible in both Vue instance, Context and Vuex store, you can include this piece of code in the same file of your plugin in our case plugins/hello.ts
declare module 'vue/types/vue' {
// Vue instance this.$hello
interface Vue {
$hello(msg: string): void;
}
}
declare module '@nuxt/types' {
// NuxtAppOtions this.app.$hello
interface NuxtAppOptions {
$hello(msg: string): void;
}
// Accessible by Context
interface Context {
$hello(msg: string): void;
}
}
declare module 'vuex/types/index' {
// this.$hello inside Vuex stores
interface Store<S> {
$hello(msg: string): void;
}
}
And that is it.