Skip to content

Latest commit

 

History

History
499 lines (442 loc) · 16.1 KB

README-EN.md

File metadata and controls

499 lines (442 loc) · 16.1 KB

vue-native-websocket-vue3 · npm version yarn version

Only supports vue3 websocket plugin

Chinese documents please move: README.md

Compatible handling for Pinia(Thanks to [@chuck](https:github.com Front To End) for the compatible code)

Plug-in installation

yarn add vue-native-websocket-vue3

# or

npm install vue-native-websocket-vue3 --save

Plug-in use

If Type Script is enabled in your project, import and use the plugin in the main.ts file.

Import and use it in main.js if it is not enabled.

When using the plug-in, the second parameter is required and is your websocket server connection address.

import VueNativeSock from "vue-native-websocket-vue3";

// Use the Vue Native Sock plug-in and perform related configuration
app.use(VueNativeSock,"");

payAttention:The plugin depends on Vuex, your project must install vuex to use this plugin. For the relevant configuration of vuex, please refer to the content in the plug-in configuration item at the back of the document.

Similarly, the plugin also supports pinia, you can choose one of vuex and pinia. Please refer to the content in the plug-in configuration item at the back of the document for the related usage configuration of pinia.

Plug-in configuration items

The plug-in provides some configuration options, which improves the flexibility of the plug-in and better adapts to the business needs of developers.

Enable Vuex integration

Import the configuration file of vuex in main.ts | main.js. When using the plug-in, the third parameter is that the user can pass the configuration item. It is an object type, and the store attribute is added to the object. Value is imported vuex.

import store from "./store";

app.use(VueNativeSock,"",{
    store: store
});

If you still don't know how to use it, you can refer to my other open source projectchat-system

If vuex integration is enabled, state and mutations methods need to be defined in its configuration file. The methods defined in mutations are 6 monitors of websocket, and you can do corresponding operations in these monitors.

import { createStore } from "vuex";
import main from "../main";

export default createStore({
  state: {
    socket: {
      // Connection Status
      isConnected: false,
      // Message content
      message: "",
      // Reconnect error
      reconnectError: false,
      // Heartbeat message sending time
      heartBeatInterval: 50000,
      // Heartbeat timer
      heartBeatTimer: 0
    }
  },
  mutations: {
    // Connection open
    SOCKET_ONOPEN(state, event) {
      main.config.globalProperties.$socket = event.currentTarget;
      state.socket.isConnected = true;
      // When the connection is successful, start sending heartbeat messages regularly to avoid being disconnected by the server
      state.socket.heartBeatTimer = setInterval(() => {
        const message = "Heartbeat message";
        state.socket.isConnected &&
          main.config.globalProperties.$socket.sendObj({
            code: 200,
            msg: message
          });
      }, state.socket.heartBeatInterval);
    },
    // Connection closed
    SOCKET_ONCLOSE(state, event) {
      state.socket.isConnected = false;
      // Stop the heartbeat message when the connection is closed
      clearInterval(state.socket.heartBeatTimer);
      state.socket.heartBeatTimer = 0;
      console.log("The line is disconnected: " + new Date());
      console.log(event);
    },
    // An error occurred
    SOCKET_ONERROR(state, event) {
      console.error(state, event);
    },
    // Receive the message sent by the server
    SOCKET_ONMESSAGE(state, message) {
      state.socket.message = message;
    },
    // Auto reconnect
    SOCKET_RECONNECT(state, count) {
      console.info("Message system reconnecting...", state, count);
    },
    // Reconnect error
    SOCKET_RECONNECT_ERROR(state) {
      state.socket.reconnectError = true;
    }
  },
  modules: {}
});
Custom method name

You can also customize the default listener event name of custom websocket in mutations.

// mutation-types.ts
const SOCKET_ONOPEN = '✅ Socket connected!'
const SOCKET_ONCLOSE = '❌ Socket disconnected!'
const SOCKET_ONERROR = '❌ Socket Error!!!'
const SOCKET_ONMESSAGE = 'Websocket message received'
const SOCKET_RECONNECT = 'Websocket reconnected'
const SOCKET_RECONNECT_ERROR = 'Websocket is having issues reconnecting..'

export {
  SOCKET_ONOPEN,
  SOCKET_ONCLOSE,
  SOCKET_ONERROR,
  SOCKET_ONMESSAGE,
  SOCKET_RECONNECT,
  SOCKET_RECONNECT_ERROR
}

// store.ts
import { createStore } from "vuex";
import main from "../main";
import {
  SOCKET_ONOPEN,
  SOCKET_ONCLOSE,
  SOCKET_ONERROR,
  SOCKET_ONMESSAGE,
  SOCKET_RECONNECT,
  SOCKET_RECONNECT_ERROR
} from "./mutation-types"

export default createStore({
  state: {
  socket: {
      isConnected: false,
      message: '',
      reconnectError: false,
     }
  },
  mutations: {
    [SOCKET_ONOPEN](state, event)  {
      state.socket.isConnected = true
    },
    [SOCKET_ONCLOSE](state, event)  {
      state.socket.isConnected = false
    },
    [SOCKET_ONERROR](state, event)  {
      console.error(state, event)
    },
    // default handler called for all methods
    [SOCKET_ONMESSAGE](state, message)  {
      state.socket.message = message
    },
    // mutations for reconnect methods
    [SOCKET_RECONNECT](state, count) {
      console.info(state, count)
    },
    [SOCKET_RECONNECT_ERROR](state) {
      state.socket.reconnectError = true;
    }
  },
  modules: {}
});

// main.js
import store from './store'
import {
  SOCKET_ONOPEN,
  SOCKET_ONCLOSE,
  SOCKET_ONERROR,
  SOCKET_ONMESSAGE,
  SOCKET_RECONNECT,
  SOCKET_RECONNECT_ERROR
} from './mutation-types'

const mutations = {
  SOCKET_ONOPEN,
  SOCKET_ONCLOSE,
  SOCKET_ONERROR,
  SOCKET_ONMESSAGE,
  SOCKET_RECONNECT,
  SOCKET_RECONNECT_ERROR
}

app.use(VueNativeSock,"",{
  store: store,
  mutations: mutations
});

Enable Pinia integration

Import pinia's configuration file in main.js|main.ts.

// use Socket Store is pinia's socket configuration file
import { useSocketStoreWithOut } from './useSocketStore';

const store = useSocketStoreWithOut();

app.use(VueNativeSock, "", {
    store: store
});

I specially wrote a demo to demonstrate the integration of pinia, if you need a reference, please go to: pinia-websocket-project

The code of pinia's socket configuration file is as follows:

import { defineStore } from 'pinia';
import { store } from '/@/store';
import main from '/@/main';

interface SocketStore {
  // Connection Status
  isConnected: boolean;
  // Message content
  message: string;
  // Reconnect error
  reconnectError: boolean;
  // Heartbeat message sending time
  heartBeatInterval: number;
  // Heartbeat timer
  heartBeatTimer: number;
}

export const useSocketStore = defineStore({
  id: 'socket',
  state: (): SocketStore => ({
    // Connection Status
    isConnected: false,
    // Message content
    message: '',
    // Reconnect error
    reconnectError: false,
    // Heartbeat message sending time
    heartBeatInterval: 50000,
    // Heartbeat timer
    heartBeatTimer: 0,
  }),
  actions: {
    // Connection open
    SOCKET_ONOPEN(event) {
      main.config.globalProperties.$socket = event.currentTarget;
      this.isConnected = true;
      // When the connection is successful, start sending heartbeat messages regularly to avoid being disconnected by the server
      this.heartBeatTimer = window.setInterval(() => {
        const message = 'Heartbeat message';
        this.isConnected &&
          main.config.globalProperties.$socket.sendObj({
            code: 200,
            msg: message,
          });
      }, this.heartBeatInterval);
    },
    // Connection closed
    SOCKET_ONCLOSE(event) {
      this.isConnected = false;
      // Stop the heartbeat message when the connection is closed
      window.clearInterval(this.heartBeatTimer);
      this.heartBeatTimer = 0;
      console.log('The line is disconnected: ' + new Date());
      console.log(event);
    },
    // An error occurred
    SOCKET_ONERROR(event) {
      console.error(event);
    },
    // Receive the message sent by the server
    SOCKET_ONMESSAGE(message) {
      this.message = message;
    },
    // Auto reconnect
    SOCKET_RECONNECT(count) {
      console.info('Message system reconnecting...', count);
    },
    // Reconnect error
    SOCKET_RECONNECT_ERROR() {
      this.reconnectError = true;
    },
  },
});

// Need to be used outside the setup
export function useSocketStoreWithOut() {
  return useSocketStore(store);
}

In order to facilitate the use of pinia outside the component, useSocketStoreWithOut is additionally exported here, otherwise pinia will report an error indicating that the pinia instance cannot be found.

The store configuration code of pinia is as follows:

import type { App } from 'vue';
import { createPinia } from 'pinia';

const store = createPinia();

export function setupStore(app: App<Element>) {
  app.use(store);
}

export { store };

Other configuration

The following methods are all passable parameters of the plug-in and can be used with store

  • Set the websocket sub-protocol default, consider it as an empty string.
{
    "protocol": "my-protocol"
}
  • Enable JSON messaging. After enabling, data sending and receiving will use json as the data format.
{ 
    "format": "json"
}
  • Enable automatic reconnection reconnection, when enabled, you can configure the number of reconnections reconnection Attempts and the reconnection interval duration reconnection Delay
{
  "reconnection": true,
  "reconnectionAttempts": 5, 
  "reconnectionDelay": 3000
}
  • Manually manage connections
{
  "connectManually": true
}

After enabling manual connection management, the connection will not be automatically connected when the project starts. You can call the connection method on a specific component of the project to connect. Call the close method when the component is destroyed to close the connection.

If you enable manual connection, you must enable vuex, otherwise this setting will not take effect.

  // Connect to the websocket server, the parameter is the websocket service address
  this.$connect("");
  // Close the connection
  this.$disconnect();
  
  // CompositionAPI
  proxy.$connect("");
  proxy.$disconnect("");
  • Custom socket event handling When triggering the mutations event in vuex, you can choose to write your own function processing, do what you want to do, pass in the pass To Store Handler parameter when using the plug-in, and if you don’t pass it, use the default processing function. The definition of the default function is as follows:
export default class {
  /**
   * The default event handler
   * @param eventName
   * @param event
   */
  defaultPassToStore(
    eventName: string,
    event: {
      data: string;
      mutation: string;
      namespace: string;
      action: string;
    }
  ): void {
    // If the beginning of the event name is not SOCKET_ then terminate the function
    if (!eventName.startsWith("SOCKET_")) {
      return;
    }
    let method = "commit";
    // Turn the letter of the event name to uppercase
    let target = eventName.toUpperCase();
    // Message content
    let msg = event;
    // data exists and the data is in json format
    if (this.format === "json" && event.data) {
      // Convert data from json string to json object
      msg = JSON.parse(event.data);
      // Determine whether msg is synchronous or asynchronous
      if (msg.mutation) {
        target = [msg.namespace || "", msg.mutation].filter((e: string) => !!e).join("/");
      } else if (msg.action) {
        method = "dispatch";
        target = [msg.namespace || "", msg.action].filter((e: string) => !!e).join("/");
      }
    }
    if (this.mutations) {
      target = this.mutations[target] || target;
    }
    // Trigger methods in storm
    if (this.store._p) {
      // pinia
      target = eventName.toUpperCase();
      this.store[target](msg);
    } else {
      // vuex
      this.store[method](target, msg);
    }
  }
}

When you want to customize a function, this function receives 3 parameters:

  • event name
  • event
  • Default event handling, which gives you the option to perform some basic preprocessing before handing over the event to the original handler

Below is an example

app.use(VueNativeSock, "", {
  passToStoreHandler: function (eventName, event, next) {
      event.data = event.should_have_been_named_data
      next(eventName, event)
  }
})

functions exposed by the plugin

  • send Send non-json type data (JSON messaging cannot be enabled when using plugins)
  • sendObj Send data of type json (JSON messaging must be enabled when using the plugin)
  • $connect Connect to the websocket server (manually manage connections option must be enabled when using the plugin)
  • onmessage listening when receiving server push messages
  • $disconnect disconnectWebsocketConnection

payAttention: The above methods are supported in the options API and Composition API. For specific usage, please refer to the documentation of the related functions.

Use in components

After finishing the above configuration, it can be used in the component. The following shows an example of sending data.

export default defineComponent({
  methods: {
    clickButton: function(val) {
        // Call the send method to send data as a string
        this.$socket.send('some data');
        // If fomat is configured as json, you can call the send Obj method to send data
        this.$socket.sendObj({ awesome: 'data'} );
    }
  }
})

Message monitoring means receiving messages pushed by the websocket server. The sample code for message monitoring is shown below.

// optionsAPI
this.$options.sockets.onmessage = (res: { data: string }) => {
  console.log(data);
}

// CompositionAPI
import { getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
proxy.$socket.onmessage = (res: {
  data: string;
}) => {
  console.log(data);
}

Send messages, push messages to the server

// optionsAPI
this.$socket.sendObj({msg: 'msgText'});

// compositionAPI
const internalInstance = data.currentInstance;
internalInstance?.proxy.$socket.sendObj({
  msg: "msgText"
});

The composition API is written because the vue instance cannot be obtained in the setup, so the instance needs to be stored in the global object after the page is mounted, and then the instance is taken out when it is used. For detailed usage, please refer to the writing in my chat-system: InitData.ts#L91EventMonitoring.ts#L50SendMessage.ts#L73contact-list.vue#L620

Remove message monitoring

delete this.$options.sockets.onmessage
// compositionAPI  writing
delete proxy.$socket.onmessage

Write at the end

So far, all the methods of using the plug-in have been introduced.

If you want to know more about the plug-in source code, please move to the project's Git Hub repository:vue-native-websocket-vue3

Please move to the original plugin for Vue 2 version: vue-native-websocket