Implement Websocket Plugin for Vuex 4 under Vue 3 (socket library agnostic)

Viewed 385

I have a Vue 3 application working with Vuex 4 and what I'm trying to do is centralize all my websocket operations via Vuex. I'm Following this tutorial but I'm not being able to wire up my plugin to the Vuex store. Ref websockets I need to be as agnostic as possible so can't use any libraries or socket.io:

Here's my plugin code:

var store = null
var ws = null

function startWebsocket() {
    ws = new WebSocket('socketURL')
    ws.onmessage = function (event) {
        console.log('webSocket: on message: ', event.data)
        const wsData = JSON.parse(event.data)
        store.dispatch('websocket/processRemoteMessage', wsData)
    }
    ws.onopen = function (event) {
        console.log('webSocket: on open: ', event)
        store.dispatch('connectionOpened')
    }
    ws.onclose = function (event) {
        console.log('webSocket: on close: ', event)
        store.dispatch('connectionClosed')
        ws = null
        setTimeout(startWebsocket, 5000)
    }
    ws.onerror = function (event) {
        console.log('webSocket: on error: ', event)
    }
}

export default function createWebSocketPlugin() {
    return (store_param) => {
        store = store_param;
        startWebsocket();
    }
}

As you can see when the websocket brings a new message I parse the object and then I want to be able to dispatch an action from the websocket store (this module lives outside the plugin) passing the websocket message:

store.dispatch('websocket/processRemoteMessage', wsData)

This is my websocket Vuex module:

export const namespaced = true
export const state = {
    connected: false,
    error: null,
    connectionId: '',
    statusCode: '',
    incomingChatInfo: [],
    remoteMessage: [],
    messageType: '',
}
export const actions = {
    processRemoteMessage({ commit }, wsData) {
        commit('SET_REMOTE_DATA', wsData)
    },
    connectionOpened({ commit }) {
        commit('SET_CONNECTION', true)
    },
    connectionClosed({ commit }) {
        commit('SET_CONNECTION', false)
    },
    connectionError({ commit }, error) {
        commit('SET_ERROR', error)
    },
}
export const mutations = {
    SET_REMOTE_DATA(state, wsData) {
        state.messageType = wsData.type
        state.connectionId = wsData.connectionId
        state.incomingChatInfo = wsData.documents
    },
    SET_CONNECTION(state, message) {
        state.connected = message
    },
    SET_ERROR(state, error) {
        state.error = error
    },
}

And this is my store index where I import all the vuex modules and the plugin:

import { createStore } from 'vuex'
import * as chatQueue from '@/store/modules/chatQueue'
import * as messages from '@/store/modules/messages'
import * as notification from '@/store/modules/notification'
import * as shifts from '@/store/modules/shifts'
import * as tickets from '@/store/modules/tickets'
import * as token from '@/store/modules/token'
import * as user from '@/store/modules/user'
import * as websocket from '@/store/modules/websocket'
import * as createWebSocketPlugin from '@/store/plugins/createWebSocketPlugin'

export default createStore({
    modules: {
        chatQueue,
        messages,
        notification,
        shifts,
        tickets,
        user,
        token,
        websocket,
    },
    plugins: [createWebSocketPlugin],
    strict: false,
})

When I try to run the APP I inmediatly get this error:

vuex.esm-bundler.js:935 Uncaught TypeError: plugin is not a function
at vuex.esm-bundler.js:935:46
at Array.forEach (<anonymous>)
at new Store2 (vuex.esm-bundler.js:935:11)
at createStore (vuex.esm-bundler.js:880:10)
at index.js?t=1644319834874:12:16

I'm a total newbie when it comes to Vuex Plugins and websockets so pretty sure I'm messing something up when I try either to import or wire up my plugin to my Vuex store.

2 Answers

Could it be because of the createWebSocketPlugin() method declaration?

The framework might be expecting a socket parameter for createWebSocketPlugin(socket) in order to provide a socket object for you automatically. In the documentation, this method is presented with a socket parameter. Moreover, judging by the error message at Array.forEach (<anonymous>), Vuex.esm-bundler might be looping through the arguments array in order to provide a socket object.

I think you should import it like:

import createWebSocketPlugin from '@/store/plugins/createWebSocketPlugin'

because you are basically saying import all "exports" into createWebSocketPlugin. Run a console.log on createWebSocketPlugin and I suspect that the createWebSocketPlugin will show you a Module instance instead of the function of the export default

Related