Git Product home page Git Product logo

vue-native-websocket's Introduction

vue-native-websocket · Build Status npm version

native websocket implementation for Vuejs 2 and Vuex

Install

yarn add vue-native-websocket

# or

npm install vue-native-websocket --save

Usage

Configuration

Automatic socket connection from an URL string

import VueNativeSock from 'vue-native-websocket'
Vue.use(VueNativeSock, 'ws://localhost:9090')

Enable Vuex integration, where './store' is your local apps store:

import store from './store'
Vue.use(VueNativeSock, 'ws://localhost:9090', { store: store })

Set sub-protocol, this is optional option and default is empty string.

import VueNativeSock from 'vue-native-websocket'
Vue.use(VueNativeSock, 'ws://localhost:9090', { protocol: 'my-protocol' })

Optionally enable JSON message passing:

Vue.use(VueNativeSock, 'ws://localhost:9090', { format: 'json' })

JSON message passing with a store:

import store from './store'
Vue.use(VueNativeSock, 'ws://localhost:9090', { store: store, format: 'json' })

Enable ws reconnect automatically:

Vue.use(VueNativeSock, 'ws://localhost:9090', {
  reconnection: true, // (Boolean) whether to reconnect automatically (false)
  reconnectionAttempts: 5, // (Number) number of reconnection attempts before giving up (Infinity),
  reconnectionDelay: 3000, // (Number) how long to initially wait before attempting a new (1000)
})

Manage connection manually:

Vue.use(VueNativeSock, 'ws://localhost:9090', {
  connectManually: true,
})
const vm = new Vue()
// Connect to the websocket target specified in the configuration
vm.$connect()
// Connect to an alternative websocket URL and Options e.g.
vm.$connect('ws://localhost:9090/alternative/connection/', { format: 'json' })
// do stuff with WebSockets
vm.$disconnect()

On Vuejs instance usage

var vm = new Vue({
  methods: {
    clickButton: function(val) {
        // $socket is [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) instance
        this.$socket.send('some data')
        // or with {format: 'json'} enabled
        this.$socket.sendObj({awesome: 'data'})
    }
  }
})

Dynamic socket event listeners

Create a new listener, for example:

this.$options.sockets.onmessage = (data) => console.log(data)

Remove existing listener

delete this.$options.sockets.onmessage

Vuex Store integration

Vuex integration works differently depending on if you've enabled a format

Without a format enabled

Socket events will commit mutations on the root store corresponding to the following events

SOCKET_ONOPEN

SOCKET_ONCLOSE

SOCKET_ONERROR

SOCKET_ONMESSAGE

Each callback is passed the raw websocket event object

Update state in the open, close and error callbacks. You can also check the socket state directly with the this.$socket object on the main Vue object.

Handle all the data in the SOCKET_ONMESSAGE mutation.

Reconect events will commit mutations SOCKET_RECONNECT and SOCKET_RECONNECT_ERROR.

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    socket: {
      isConnected: false,
      message: '',
      reconnectError: false,
    }
  },
  mutations:{
    SOCKET_ONOPEN (state, event)  {
      Vue.prototype.$socket = event.currentTarget
      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;
    },
  },
  actions: {
    sendMessage: function(context, message) {
      .....
      Vue.prototype.$socket.sendObj(message)
      .....
    }
  }
})
With custom mutation names
// mutation-types.js
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.js
import Vue from 'vue'
import Vuex from 'vuex'
import {
  SOCKET_ONOPEN,
  SOCKET_ONCLOSE,
  SOCKET_ONERROR,
  SOCKET_ONMESSAGE,
  SOCKET_RECONNECT,
  SOCKET_RECONNECT_ERROR
} from './mutation-types'

Vue.use(Vuex);

export default new Vuex.Store({
  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;
    }
  }
})

// index.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
}

Vue.use(VueNativeSock, 'ws://localhost:9090', {
  store: store,
  mutations: mutations
})
With format: 'json' enabled

All data passed through the websocket is expected to be JSON.

Each message is JSON.parsed if there is a data (content) response.

If there is no data, the fallback SOCKET_ON* mutation is called with the original event data, as above.

If there is a .namespace on the data, the message is sent to this namespaced: true store (be sure to turn this on in the store module).

If there is a .mutation value in the response data, the corresponding mutation is called with the name SOCKET_[mutation value]

If there is an .action value in the response data ie. action: 'customerAdded', the corresponding action is called by name:

actions: {
    customerAdded (context) {
      console.log('action received: customerAdded')
    }
  }

Use the .sendObj({some: data}) method on the $socket object to send stringified json messages.

Custom socket event handling

Provide you own custom code to handle events received via the passToStoreHandler option. The function you provide will be passed the following arguments:

  1. event name
  2. event
  3. original/default handler code function function (eventName, event). This allows you to optionally do some basic preprocessing before handing the event over to the original handler.

The original passToStore code is used if no passToStoreHandler is configured.

Here is an example of passing in a custom handler. This has the original passToStore code to give you an example of what you can do:

Vue.use(VueNativeSock, 'ws://localhost:9090', {
  passToStoreHandler: function (eventName, event) {
    if (!eventName.startsWith('SOCKET_')) { return }
    let method = 'commit'
    let target = eventName.toUpperCase()
    let msg = event
    if (this.format === 'json' && event.data) {
      msg = JSON.parse(event.data)
      if (msg.mutation) {
        target = [msg.namespace || '', msg.mutation].filter((e) => !!e).join('/')
      } else if (msg.action) {
        method = 'dispatch'
        target = [msg.namespace || '', msg.action].filter((e) => !!e).join('/')
      }
    }
    this.store[method](target, msg)
  }
})

Here is an example of do some preprocessing, then pass the event onto the original handler code:

Vue.use(VueNativeSock, 'ws://localhost:9090', {
  passToStoreHandler: function (eventName, event, next) {
    event.data = event.should_have_been_named_data
    next(eventName, event)
  }
})

Examples

TODO: post your example here!

Credits

Derived from https://github.com/MetinSeylan/Vue-Socket.io

vue-native-websocket's People

Contributors

anatoly314 avatar codeofsumit avatar dengdan99 avatar dennisreimann avatar denzow avatar dependabot[bot] avatar gbtux avatar jeystaats avatar justerror avatar metinseylan avatar michgeek avatar mikhailian avatar mmacneil avatar n5leon avatar nathantsoi avatar nmeylan avatar nsano-rururu avatar omgimalexis avatar panicisreal avatar pieterjandesmedt avatar pmarais avatar rigwild avatar saspallow avatar sergak01 avatar sharkykh avatar thomasklessen avatar vankerkom avatar weglov avatar whitekkk avatar wsmcnaughton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vue-native-websocket's Issues

Websocket won't reconnect after vue router call

When a page where a vue component is using the vue native websocket is loaded, it connects and works without any problem. After switching to another page and coming back by using vue router, the websocket do not reconnect.

ERROR in build.js from UglifyJs

Got the following error when run webpack:

Hash: d1a9ada4be8154684b8b
Version: webpack 3.6.0
Time: 158ms
       Asset     Size  Chunks             Chunk Names
    build.js  7.63 kB       0  [emitted]  main
build.js.map  8.16 kB       0  [emitted]  main
   [0] ./src/Emitter.js 1.15 kB {0} [built]
   [1] multi ./src/Main.js 28 bytes {0} [built]
   [2] ./src/Main.js 1.19 kB {0} [built]
   [3] ./src/Observer.js 1.44 kB {0} [built]

ERROR in build.js from UglifyJs
Unexpected token: name (Emitter) [build.js:81,6]

After reconnect, socket is in readyState 3

Hi.

I am having problems using the socket after it is closed and (successfully) reconnected.
Although after the reconnect I get the ONOPEN event, the readyState of the socket is 3, meaning CLOSED or CLOSING.

I am using the sockets with the Vuex store, and I am assigning the Vue.prototype.$socket to store.$socket, to be able to access the socket in the store.

Sample of the code

        // socket mutations
        SOCKET_ONOPEN (state, event) {
            state.socket.isConnected = true
            console.log('connected ...', this.$socket)
        },

The first time the code is ran the socket is ok, in readyState 1, after reconnect the readyState remains 3

Any ideas?

Simultaneously, two websockets

Please tell me whether it is possible using vue-native-websocket to simultaneously use two web sites with different url. I tried to create two different components for each of the two websocket, but they do not work. And if I leave only one websocket then everything works fine.
Please, help...

Separate on open event handling for each vue component

I want to separate onopen events for each vue component. Now I see alerts with 1 and 2 two times.
Is there a way to avoid this duplication?

Vue.use(VueNativeSock.default, wsPath, {
  reconnection: true,
  reconnectionAttempts: 5,
  reconnectionDelay: 3000,
  format: 'json',
});

var app1 = new Vue({
  created: function () {
    var vm = this;
    this.$options.sockets.onmessage = function (message) {
      vm.listen(message);
    };
    this.$options.sockets.onopen = function () {
      alert(1);
    }
  }
});

var app1 = new Vue({
  created: function () {
    var vm = this;
    this.$options.sockets.onmessage = function (message) {
      vm.listen(message);
    };
    this.$options.sockets.onopen = function () {
      alert(2);
    }
  }
});

Nuxtjs store support?

Hi there,
this is more like a question than a bug.
I just wanted to integrate this in my NuxtJs store and ran into the following error
screen shot 2018-05-12 at 01 14 54
NuxtJs is forcing you to export the store as a function and I dont know when the store is available for the client (this might be the problem) really because its this Nuxt Server/Client thingy.
In my plugin its defined like this:

import Vue from 'vue'
import VueNativeSocket from 'vue-native-websocket'

import store from '~/store'
console.log(store)
Vue.use(VueNativeSocket, process.env.WS_URL, {
  store: store,
  reconnection: true,
  reconnectionDelay: 1000,
  format: 'json'
})

the console.log(store) returns this

ƒ Store() {
  return new __WEBPACK_IMPORTED_MODULE_0_vuex__["default"].Store({
    state: {},
    getters: {},
    mutations: {},
    actions: {}
  });
}

How can an action wait for a server reply?

How would I do a simple login with this package. What is the preferred way?

  1. Send my login data with an action and wait for the server reply (mutation) with watch inside the login component.
computed: {
  ...mapGetters([
    'user',
  ])
},
watch: {
  user(user) {
    if (user) {
      window.location = '/home';
    }
  },
},
methods: {
  login() {
    this.$socket.sendObj({ type: 'login', user: this.username, password: this.password });
    this.username = '';
    this.password = '';
  }
},
  1. Send my login data and wait for the answer of the server to set the user (mutation) and redirect him in .then() of the action Promise.
    What I am looking for is this case would be the waitForAnswer part, that should be triggered after the client received the message (mutation executed?).
const actions = {
  [LOGIN]({ commit }, { user, password }) {
    return new Promise((resolve) => {
      // send login request with user and password
      this.$socket.sendObj({ type: 'login', user, password });

      // wait for answer. maybe watch mutations change?
      waitForAnswer('auth:login', ({ user }) => {
        resolve(user);
      });
    });
  }
};

Error in beforeDestroy hook

I'm using this module inside created() component method, but when I destroy the component always got this error message:

Error in beforeDestroy hook: "TypeError: Cannot read property 'sockets' of undefined"

Here is my code:

<template>
  ...
</template>

<script>
  export default {
    data(){
      return {
        productos: [],
      }
    },
   created() {
    // listener
     this.$options.sockets.onmessage = (messageEvent) => {
     // logic here
     };

   },
   destroyed(){
      console.log('destroyed');
   },
   beforeDestroy(){
     console.log('beforeDestroy');
   }
  }
</script>

<style>

</style>

Error stack: https://imgur.com/a/krORJ

Unique websocket key?

Hi there,

Is there a way to get the sec-websocket-key? or some kind of unique id?

Thanks,
Danny

JSON Web Token

Can vue-native-websocket be used in combination with JSON Web Token for authentication?

Dual websocket connection

Is it possible to create simultaneous websocket connections to two different servers? For redundancy purposes, I want to create two connections at once and then use which ever one connects first (in case one of the two servers is offline). I'm using ConnectManually = true and the VUEX store to handle all communication. If dual is not an option, is it at least possible to dynamically change the URL that ws.$connect is going to use?

Event listeners without store

How exactly can I listen to events if I do not have a store?

I've tried this in my created method if my main component, but it's not firing:

this.$options.sockets.SOCKET_ONMESSAGE = (data) => {console.log("a message")}

Android 4.4 on Coolpad

Hi,

Line 3 in ./src/Emitter.js is giving me error on Android 4.4.

this.listeners = new Map()

Is there a polyfill or another way than using "new Map()" so it works on Android 4.4?

Thanks !

How to dynamic change the websocket url?

In some case , I need to monitor different websocket url when I change vue router or click some button. The websocket url in the “main.js” whether or not dynamic change

Namespace support and SOCKET_*

When I want to use namespaces, how can I handle the SOCKET_* mutations?
I got namespaced messages to work, but I am getting messages like [vuex] unknown mutation type: SOCKET_ONOPEN.. Where do I store the SOCKET_* mutations?

How to disconnect properly?

Can someone please point me to the proper way to disconnect - I suppose $socket.close() should be used. But if reconnect is enabled - how to disable it. Thank you.

Store/vuex can not find mutation in sub module

import VueNativeSock from 'vue-native-websocket'
Vue.use(VueNativeSock, 'ws://localhost:3000', {store: store, format: 'json'})

vuex.esm.js?358c:383 [vuex] unknown mutation type: SOCKET_ONMESSAGE

this mutations is defined in the sub module socket:
/socket/mutations.js

  SOCKET_ONMESSAGE (state, message) {
    for (var property in message) {
      console.log(property + ' = ' + message[property])
    }
  }

In index.js:

import socketModule from '@/store/modules/socket

Vue.use(Vuex)

export const store = new Vuex.Store({
  modules: {
    socket: socketModule
  },

If the mutations is defined in index.js everything works

Mock?

How would be the best way to mock sockets with this library in order to have tests and to develop without the need of the actual WS peer sending and receiving messages?

Use namespace also for actions

I do not know wether this is desired behavior, but i use namespaced stores und vue-native-websocket is not able to call actions accordingly.

It is because you do not include the namespace when generating the action:
if (msg.mutation) { target = [msg.namespace || '', msg.mutation].filter((e) => !!e).join('/') } else if (msg.action) { method = 'dispatch' target = msg.action }

In my opinion this is a bug and i could create a pull-request if you want to?

Error in created hook: "TypeError: Cannot set property 'onmessage' of undefined"

Hi,
I have to load vue-native-websocket throught script like

  <script src="{% static 'js/vue.js' %}"></script>
  <script src="{% static 'js/vue-native-websocket.min.js' %}"></script>
  <script src="{% static 'js/vue_components/OrdersCurrent.js' %}"></script>

here's my OrdersCurrent.js

Vue.use(VueNativeSock, 'wss://localhost/ws/current-orders/1', {
  reconnection: true,
  reconnectionAttempts: 5,
  reconnectionDelay: 3000,
  format: 'json',
});

var app = new Vue({
  el: '#orders-current-app',
  delimiters: ['{*', '*}'],
  created: function () {
    var vm = this;
    this.$options.sockets.onmessage = function (data) {
      vm.messageReceived(data);
    }
  },
  data: {
    message: 'hi Vue!'
  },
  methods: {
    sendMessage: function(event) {
      message = event.target.value;
      this.$socket.sendObj({message: message});
      event.target.value = ''
    },
    receiveMessage: function(websocketMessage) {
      var data = JSON.parse(websocketMessage.data);
      this.messages.push(data.message);
    }
  }
});

Looks like Vue.use not working in this case. I got the following error

vue.js:597 [Vue warn]: Error in created hook: "TypeError: Cannot set property 'onmessage' of undefined"

(found in <Root>)
warn @ vue.js:597
logError @ vue.js:1739
globalHandleError @ vue.js:1734
handleError @ vue.js:1723
callHook @ vue.js:2923
Vue._init @ vue.js:4617
Vue @ vue.js:4716
(anonymous) @ OrdersCurrent.js:8
vue.js:1743 TypeError: Cannot set property 'onmessage' of undefined
    at Vue.created (OrdersCurrent.js:13)
    at callHook (vue.js:2921)
    at Vue._init (vue.js:4617)
    at new Vue (vue.js:4716)
    at OrdersCurrent.js:8

Proxy is not defined - IE 11

Hello,

In Main.js file you use Proxy object and it's causes that my app not work in IE 11, because in IE 11 there is no Proxy object.

How can I resolve it? Maybe some Polyfill?

working examples

Can we get some working examples. Both with and without using store?

how change web socket url

Vue.use(VueNativeSock, 'ws://localhost:9090')

Plugin can't install over and over times , so How can I change the socket url.

Changing websocket url

How do I change the websocket url string? The component needs to connect to a different websocket url depending on the current url.

Here is an example of my component:

<script>
import VueNativeSock from 'vue-native-websocket'
Vue.use(VueNativeSock, 'ws://myserver:8080/logs?id=' + this.$route.params.id);

export default {
...
}
</script>

So if the current url is http://example/results/1234, then I need to open the connection to ws://myserver:8080/logs?id=1234.

onsend event

together with onmessage handler I want to define onsend handler. Is it possible?

    var vm = this;
    this.$options.sockets.onmessage = function (message) {
      vm.loading = false;
      vm.listen(message);
    };
    this.$options.sockets.onsend = function () {
      vm.loading = true;
    }

README has a typo

    SOCKET_ONMESSAGE (event, message)  {

should be

    SOCKET_ONMESSAGE (state, message)  {

change binary data type

How can I set the binaryType?

I need to do something like this?

ws.binaryType = 'arraybuffer';

Reconnection still not working

I've been struggling with this for a while and was hoping the update would sort it but I'm still having the same problem and perhaps I'm missing some understanding.

In main.js:

import Vue from 'vue';
import VueNativeSock from 'vue-native-websocket';
import App from './App';
import router from './router';

Vue.use(VueNativeSock, process.env.WEBSOCKET_ADDR, {
  format: 'json',
  reconnection: true, // (Boolean) whether to reconnect automatically (false)
  reconnectionAttempts: 5, // (Number) number of reconnection attempts before giving up (Infinity),
  reconnectionDelay: 3000, // (Number) how long to initially wait before attempting a new (1000)
});

/* eslint-disable no-new */
new Vue({
  components: { App },
  router,
  template: '<App/>',
}).$mount('#app');

In App.vue (minimal):

<script>
  export default {
    name: 'app',
    created() {
      this.$socket.onopen = () => {
        console.log('connected');
      };
      this.$socket.onclose = () => {
        console.log('disconnected');
      };
    },
  };
</script>

If I start with the WS server is running, it's connected, when I kill the server process, disconnected.
Then I start the server again, I would expect it to reconnect. Am I wrong in thinking this? Is my implementation wrong?

Can't send anything.

I have an issue.

When i try to send a message i get the following error:

Uncaught TypeError: Cannot read property '$socket' of undefined

this.$socket.send('some data') Seem not to work? Or am i doing it wrong?

It does work outside the store... But it would be handy to call it inside a store actions to send it of to the server. Can I call it somehow there?

How to reconnect ?

If we switch the network connection off then it changes the states to ONCLOSE and socket gets disconnected. But its not coming back to ONOPEN when network connection comes back?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.