Code Monkey home page Code Monkey logo

vue-socket.io-extended's Introduction

Stand With Ukraine


Vue-Socket.io-Extended

Build Status Version Downloads License Vue.js 2.x compatible Minified library size Code coverage (codecov) Join us Gitter

Socket.io bindings for Vue.js 2 and Vuex (inspired by Vue-Socket.io)

Edit Vue Socket IO Extended Twitter feed demo

Buy Me a Coffee at ko-fi.com

⚠️ The alpha version of v5 (with Vue 3 support) has been released. Your feedback would be appreciated here

πŸ’ Features

  • Lightweight and dependency free - only 2kb min gzip
  • Reactive properties $socket.connected and $socket.disconnected
  • Listening and emitting socket.io events inside components
  • Auto-dispatches actions and mutations in multiple namespaced Vuex modules on socket.io events
  • Good TypeScript support (decorator and typing)
  • Can be used with any version of socket.io-client
  • Custom options - tweak the library to better fit your project needs
  • etc...

βœ”οΈ Browser Support

Chrome Firefox Safari Opera Edge IE
38+ βœ”οΈ 13+ βœ”οΈ 8+ βœ”οΈ 25+ βœ”οΈ 12+ βœ”οΈ 11+ βœ”οΈ

We support only browsers with global usage statistics greater than 1% and last 2 version of each browser (but not dead browsers). Library may work in older browser as well, but we don't guarantee that. You may need addition polyfills to make it work.

🌱 Motivation

I was using Vue-Socket.io for few months. I've liked the idea, but the more I used it the more I faced with bugs, outdated documentation, lack of support, absence of tests, and a huge amount of issues 😞. That slowed down development of the product I was working on. So I ended up with a decision to create my own fork with all the desirable stuff (features/fixes/tests/support/CI checks etc). That's how vue-socket.io-extended was born.

If you'd like to help - create an issue or PR. I will be glad to see any contribution. Let's make the world a better place ❀️

❕ Prerequisites

You must have a running Socket.IO server before starting any Vue/Socket.IO project! Instructions on how to build a Node/Socket.IO server are found here.

❕ Software Requirements

πŸ’Ώ Installation

npm install vue-socket.io-extended socket.io-client

🏁 Initialization

ES2015 (Webpack/Rollup/Browserify/Parcel/etc)

import VueSocketIOExt from 'vue-socket.io-extended';
import { io } from 'socket.io-client';

const socket = io('http://socketserver.com:1923');

Vue.use(VueSocketIOExt, socket);

Note: you have to pass instance of socket.io-client as second argument to prevent library duplication. Read more here.

UMD (Browser)

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/socket.io-client/dist/socket.io.slim.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-socket.io-extended"></script>
<script>
  var socket = io('http://socketserver.com:1923');
  Vue.use(VueSocketIOExt, socket);
</script>

πŸš€ Usage

On Vue.js component

Define your listeners under sockets section, and they will listen corresponding socket.io events automatically.

new Vue({
  sockets: {
    connect() {
      console.log('socket connected')
    },
    customEmit(val) {
      console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)')
    }
  },
  methods: {
    clickButton(val) {
      // this.$socket.client is `socket.io-client` instance
      this.$socket.client.emit('emit_method', val);
    }
  }
})

Note: Don't use arrow functions for methods or listeners if you are going to emit socket.io events inside. You will end up with using incorrect this. More info about this here

Dynamic socket event listeners (changed in v4)

There is a way to create listeners dynamically, in case you need to start listening only on some condition.

// creating event listener
this.$socket.$subscribe('event_name', payload => {
  console.log(payload)
});

// removing existing listener
this.$socket.$unsubscribe('event_name');

As an alternative, feel free to attach events directly to socket.io client, but keep in mind that you'd need to pass the same function to .off(event_name, fn) that you passed to .on(event_name, fn) in order to unsubscribe properly. Otherwise, it won't work as you expect.

export default {
  methods: {
    onEventName(params) {
      console.log('`eventName` has fired with:', params)
    },
  },
  mounted() {
    // subscribe
    this.$socket.client.on('eventName', this.onEventName) // <-- this.onEventName here
  },
  beforeDestroy() {
    // unsubscribe
    this.$socket.client.off('eventName', this.onEventName) // <-- this.onEventName here
  },
}

Important: Every dynamic subscription should have appropriate unsubscription. Or else, you'd experience an event firing multiple times. Moreover, unsubscribed leftovers might cause memory leaks.

Reactive properties (new in v4)

$socket.connected and $socket.diconnected are reactive. That means you can use them in expressions

<template>
  <div>
    <span>{{ $socket.connected ? 'Connected' : 'Disconnected' }}</span>
  </div>
</template>

Or conditions

<template>
  <span
    class="notification"
    v-if="$socket.disconnected"
  >
    You are disconnected
  </span>
</template>

Or computed properties, methods and hooks. Treat them as computed properties that are available in all components

🌲 Vuex Store Integration

Setup

To set up Vuex integration just pass the store as the third argument. In a Vue CLI project, you might do this in the src/main.js file. Example:

import VueSocketIOExt from 'vue-socket.io-extended';
import { io } from 'socket.io-client';
import store from './store'

const socket = io('http://socketserver.com:1923');

Vue.use(VueSocketIOExt, socket, { store });

Receiving Events

Mutations and actions will be dispatched or committed automatically in the Vuex store when a socket event arrives. A mutation or action must follow the naming convention below to recognize and handle a socket event.

  • A mutation should start with SOCKET_ prefix and continue with an uppercase version of the event
  • An action should start with socket_ prefix and continue with camelcase version of the event
Server Event Mutation Action
chat message SOCKET_CHAT MESSAGE socket_chatMessage
chat_message SOCKET_CHAT_MESSAGE socket_chatMessage
chatMessage SOCKET_CHATMESSAGE socket_chatMessage
CHAT_MESSAGE SOCKET_CHAT_MESSAGE socket_chatMessage

Check the Configuration section if you'd like to use a custom transformation.

Check the Migration from VueSocketIO section if you want to keep actions names in UPPER_CASE.

// In this example we have a socket.io server that sends message ID when it arrives
// so to get entire body of the message we need to make AJAX call the server
import Vue from 'vue'
import Vuex from 'vuex'

// `MessagesAPI.downloadMessageById` is an async function (goes to backend through REST Api and fetches all message data)
import MessagesAPI from './api/message'

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    // we store messages as a dictionary for easier access and interaction
    // @see https://hackernoon.com/shape-your-redux-store-like-your-database-98faa4754fd5
    messages: {},
    messagesOrder: []
  },
  mutations: {
    NEW_MESSAGE(state, message) {
      state.messages[message.id] = message;
      state.messagesOrder.push(message.id);
    }
  },
  actions: {
    socket_userMessage ({ dispatch, commit }, messageId) { // <-- this action is triggered when `user_message` is emmited on the server
      return MessagesAPI.downloadMessageById(messageId).then((message) => {
       commit('NEW_MESSAGE', message);
      })
    }
  }
})

Emitting Events

Events can be sent to the Socket.IO server by calling this._vm.$socket.client.emit from a Vuex mutation or action. Mutation or action names are not subject to the same naming requirements as above. More then one argument can be included. All serializable data structures are supported, including Buffer.

  actions: {
    emitSocketEvent(data) {
      this._vm.$socket.client.emit('eventName', data);
      this._vm.$socket.client.emit('with-binary', 1, '2', { 3: '4', 5: new Buffer(6) });
    }
  }

Namespaced Vuex Modules

Namespaced modules are supported out-of-the-box. Any appropriately-named mutation or action should work regardless of whether it's in a module or in the main Vuex store.

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

Vue.use(Vuex);

const messages = {
  state: {
    messages: []
  },
  mutations: {
    SOCKET_CHAT_MESSAGE(state, message) {
      state.messages.push(message);
    }
  },
  actions: {
    socket_chatMessage() {
      console.log('this action will be called');
    }
  },
};

const notifications = {
  state: {
    notifications: []
  },
  mutations: {
    SOCKET_CHAT_MESSAGE(state, message) {
      state.notifications.push({ type: 'message', payload: message });
    }
  },
};

export default new Vuex.Store({
  modules: {
    messages,
    notifications,
  }
})

The above code will:

  • Commit the SOCKET_CHAT_MESSAGE mutation in the messages module
  • Commit the SOCKET_CHAT_MESSAGE mutation in the notification module
  • Dispatch the socket_chatMessage action in the messages module

🎍 ECMAScript / TypeScript decorator (added in v4)

Required: ECMAScript stage 1 decorators. If you use Babel, babel-plugin-transform-decorators-legacy is needed. If you use TypeScript, enable --experimentalDecorators flag.

It does not support the stage 2 decorators yet since mainstream transpilers still transpile to the old decorators.

We provide @Socket() decorator for users of class-style Vue components. By default, @Socket() decorator listens the same event as decorated method name but you can use custom name by passing a string inside decorator e.g. @Socket('custom_event').

Check the example below:

<!-- App.vue -->
<script>
import Vue from 'vue'
import Component from 'vue-class-component'
import { Socket } from 'vue-socket.io-extended'

@Component({})
export default class App extends Vue {
  @Socket() // --> listens to the event by method name, e.g. `connect`
  connect () {
    console.log('connection established');
  }

  @Socket('tweet')  // --> listens to the event with given name, e.g. `tweet`
  onTweet (tweetInfo) {
    // do something with `tweetInfo`
  }
}
</script>

🚡 Usage with Nuxt.js

The key point here is to disable SSR for the plugin as it will crash otherwise. It's a well-know issue and we are going to fix it. Thanks @ll931217 for investigation.

1. Create plugin:

// ~/plugins/socket.io.js
import Vue from 'vue';
import { io } from 'socket.io-client';
import VueSocketIOExt from 'vue-socket.io-extended';

const socket = io('http://localhost:3000');

export default ({ store }) => {
  Vue.use(VueSocketIOExt, socket, { store });
}

2. Then register it:

// nuxt.config.js
module.exports = {
  //...,
  plugins: [
    //...,
    {
      src: '~/plugins/socket.io.js',
      ssr: false,                    // <-- this line is required
    },
  ]
}

🚡 Usage with Quasar Framework

Register vue-socket.io-extended with a boot file and disable server side rendering

1. Create bootfile:

// ~/boot/socket.io.js
import { io } from 'socket.io-client';
import VueSocketIOExt from 'vue-socket.io-extended';

const socket = io('http://localhost:3000');

export default async ({ store, Vue }) => {
  Vue.use(VueSocketIOExt, socket, { store })
}

2. Then register it:

// quasar.conf.js
module.exports = function (ctx) {
  return {
    //...,
    boot: [
      //...,
      {
        path: 'socket.io',
        server: false,
      },
    ]
  }
};

βš™οΈ Configuration

In addition to store instance, vue-socket.io-extended accepts other options. Here they are:

Option Type Default Description
store Object undefined Vuex store instance, enables vuex integration
actionPrefix String 'socket_' Prepend to event name while converting event to action. Empty string disables prefixing
mutationPrefix String 'SOCKET_' Prepend to event name while converting event to mutation. Empty string disables prefixing
eventToMutationTransformer Function string => string uppercase function Determines how event name converted to mutation
eventToActionTransformer Function string => string camelcase function Determines how event name converted to action
eventMapping Function socket => string Map your event from socket event data

FYI: You can always access default plugin options if you need it (e.g. re-use default eventToActionTransformer function):

import VueSocketIOExt from 'vue-socket.io-extended';
VueSocketIOExt.defaults // -> { actionPrefix: '...', mutationPrefix: '...', ... }

ℹ️ Migration from VueSocketIO

For everyone who has migrated from old package VueSocketIO to this new one on existing project. You need to re-define 2 parameters, in order to use existing store actions without changes (e.g. SOCKET_EVENT_NAME).

import VueSocketIO from 'vue-socket.io-extended';
import { io } from 'socket.io-client';

const ioInstance = io('https://hostname/path', {
  reconnection: true,
  reconnectionDelay: 500,
  maxReconnectionAttempts: Infinity
});

Vue.use(VueSocketIO, ioInstance, {
  store, // vuex store instance
  actionPrefix: 'SOCKET_', // (1) keep prefix in uppercase
  eventToActionTransformer: (actionName) => actionName // (2) cancel camelcasing
});

❓ FAQ

βš“ Semantic Versioning Policy

This plugin follows semantic versioning.

πŸ“° Changelog

We're using GitHub Releases.

🍻 Contribution

We're more than happy to see potential contributions, so don't hesitate. If you have any suggestions, ideas or problems feel free to add new issue, but first please make sure your question does not repeat previous ones.

πŸ”’ License

See the LICENSE file for license rights and limitations (MIT).

FOSSA Status

vue-socket.io-extended's People

Contributors

adamasantares avatar amiceli avatar capndave avatar dependabot[bot] avatar dimosthenisk avatar jnt0r avatar probil avatar renovate-bot avatar renovate[bot] avatar suspiciouslookingowl avatar totominc avatar venlious 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

vue-socket.io-extended's Issues

Server Address via user input

Hey there,

I want to develop a client in vue, where the user can input the server's address. So the server address is not available when vue is initialized. Is this even possible?

Thanks in advance!
Nick

Always Got Triggered Mutation.

Hi, I have been trying to fixing this issue for 2 days. It always Triggers Mutation but not actions.

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

Vue.use(Vuex);

const roommsgs = {
  state: {
    roommsgs: []
  },
  mutations: {
    SOCKET_CONNECT(state, status) {},
    SOCKET_ROOMCHAT(state, roomchat) {
      state.roommsgs.push(roomchat);
    }
  },
  actions: {
    socket_roomChat: async ({
      commit,
      dispatch
    }, message) => {
      dispatch('socket_roomChat', message);
      commit('SOCKET_ROOMCHAT', message);
    }
  },
  getters: {
    getChatByRoom: (state) => (room_name) => {
      return state.roommsgs.find(roommsgs => roommsgs.roomname === room_name)
    }
  }
};

const notifications = {
  state: {
    notifications: []
  },
  mutations: {
    SOCKET_NOTIFICATIONS(state, message) {
      state.notifications.push({
        type: 'notifications',
        payload: message
      });
    }
  },
}

export default new Vuex.Store({
  modules: {
    roommsgs,
    notifications,
  }
})

Is there anything else should I consider?

Syntax error in IE11

There is an issue with the latest version (v3.2.0) in IE11. It seems as though the 'camelcase' module is no longer being transpiled correctly to ES5 (I'm seeing usages of 'fat arrows'). The previous version (v3.1.0) seems to be working just fine.

Thanks in advance!

Messages not received by application (Callback function not called for the event but websockets frames are received on the network )

sockets: {
    connect: function() {
      console.log("connected");
    },
    "myResponse": function(message) {
      console.log("message recv", message);
      // if message length is more than 17000 bytes this callback stop getting called , however i can see the websocket frames being received in chrome devtools 
      // When i keep decreasing the message length this events are fired but it increase overall latency of the application 
  }
}

Mutation emmited with value wrapped in array instead of value directly

Example

// store.js
export default {
  mutation: {
    SOCKET_GREETING_MESSAGE(state, message) {
      console.log(message);
    },
  },
}
// server.js
io.emit('GREETING_MESSAGE', 'Hi there');

Expected result: SOCKET_GREETING_MESSAGE receives message as 'Hi there'
Actual result: SOCKET_GREETING_MESSAGE receives message as ['Hi there']


Versions

vue-socket.io-extended: 2.0.0
vue: 2.5.13
vuex: 3.0.1

Prevent socket.io-client duplication by force user to provide an instance of it

I've made investigation today using vue cli, and that's what I got:

vue                                                    : 61.77 kb
vue + vue-socket.io-extended                           : 132.10 kb
vue + vue-socket.io-extended + custom socket.io-client : 190.87 kb

There is a duplication of socket.io-client library when you pass socket.io-client instance to the plugin.
So if you use it this way, you probably have extra ~70kb of useless data in your build.

The only way to fix it is to force library user to pass socket.io-client instance always.

Advantages:

  • less build size with custom socket.io-client (e.g. ~70Kb)
  • no force version of socket.io-client for user
  • no need to support socket.io-client inside the library (update library just because socket.io-client updated)
  • user can pass any library compatible with socket.io-client, for example, socket.io-client/dist/socket.io.slim.js which is ~8kb smaller than socket.io-client but drops IE6-8

Disadvantages:

  • little harder to setup

Q: Message not caught

Hi,
I have following mutations:

 import $socket from '../../socket';

const state = {
  isConnected: false,
  message: null,
}

const mutations = {
  SOCKET_CONNECT: (state, status) => {
    state.isConnected = true;
    console.log("Connected");
  },
  SOCKET_USER_MESSAGE: (state, message) => {
    state.message = message;
    console.log("Usermessage from server:" + message);
  },
  Login: (state, message) => {
    state.message = message;
    console.log(message);
    $socket.emit('Login',message);
  },
}

if I send a message from server to my client like so:
socket.emit('USER_MESSAGE', 'Logged in successfully')

the message gets not caught. But I can see the message in the WS-Debugger window.
I'm I wrong here? My understanding is, that the message should be caught.

I'm able to send messages via Login() mutation to the server.

I don't get a SOCKET_CONNECT neither. Is that a standard message and should be caught or is it a user message as well?

Let me know if you need further information.

Thx,
Sven

Event name is not recognized

Hi Probil!

Thanks for forking this project.
I try this and previous project (vue-socket.io) with vuex, but it's not working. SOCKET_CONNECT is working properly, but i can't trigger other event name such as SOCKET_RESPONSE

Any chance that i missing something?

Thanks!

TypeScript typings

Hi, pls provide typings initialization for typescript something like

npm install @types/vue-socket.io-extended

thank U

The message is not received, when server emitted

Hi!

My problem is:
I have a Vuex application with store and i have a simple socketio server.
If the server receives a message, it will broadcast it. The server logs that this has happened, the client does not received it.

SERVER:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

io.on('connection', function(socket) {
  console.log(`Client connected [id=${socket.id}]`);

  socket.on('server_message', function(data) {
    console.log(`server_message: `, JSON.stringify(data));
    socket.emit('server_message', { msg: data.msg });
  });

  socket.on('disconnect', function() {
    console.log(`Client disconnected [id=${socket.id}]`);
  });
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

FRONTEND:

main.js

import Vue from 'vue';
import App from './App.vue';
import socketio from 'socket.io-client';
import VueSocketIO from 'vue-socket.io-extended';
import store from './store';

Vue.use(VueSocketIO, socketio('http://localhost:3000', {
            store: store,
            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)
        }), store);

new Vue({
    store,
    render: h => h(App)
}).$mount('#app');

store/index.js

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

Vue.use(Vuex);

export default new Vuex.Store({
    state: {
        isConnected: false,
        message: '',
        reconnectError: false,
        event: null,
        count: 0,
        serverMessage: ''
    },
    mutations: {
        SOCKET_CONNECT(state) {
            state.reconnectError = false;
            state.isConnected = true;
            state.event = 'connected';
            state.serverMessage = 'socket connected';
        },
        SOCKET_ERROR (state)  {
            state.isConnected = false;
            state.event = 'error';
            state.serverMessage = 'socket error';
        },
        SOCKET_DISCONNECT(state) {
            state.isConnected = false;
            state.reconnectError = false;
            state.event = 'disconnect';
            state.serverMessage = 'socket disconnect';
        },
        SOCKET_RECONNECT(state) {
            state.reconnectError = false;
            state.serverMessage = 'socket reconnect';
        },
        SOCKET_RECONNECT_ERROR(state) {
            state.reconnectError = true;
            state.serverMessage = 'socket reconnect error';
        },
        SOCKET_RECONNECT_ATTEMPT(state) {
            state.reconnectError = true;
            state.count = state.count + 1 ;
            state.serverMessage = 'socket reconnect error';
        },
        SOCKET_CONNECT_ERROR (state)  {
            state.isConnected = false;
            state.event = 'connect error';
            state.serverMessage = 'socket connect error';
        },
        
        SOCKET_SERVER_MESSAGE (state, message)  {
            console.log(message);
            state.message = message;
            state.serverMessage = 'message received';
        },
    },
    actions: {
        socket_serverMessage: function(message) {
             console.log(message);
        }
    }
});

+1 event listener in a component:

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

What could be the problem?
THX!

Cannot read property 'emit' of undefined

I've a .vue file like this:

<template>
  <div class="home">
    <h1>Hello</h1>
  </div>
</template>
<script>
export default {
  sockets: {
    connect: () => {
      this.$socket.emit("join_room", "abc");
    },
  }
};
</script>

and I'm getting an error: Uncaught TypeError: Cannot read property 'emit' of undefined

main.js

import VueSocketio from 'vue-socket.io-extended';
import io from 'socket.io-client';
import Vue from 'vue';

import App from './App.vue';

Vue.use(VueSocketio, io('http://localhost:4000'));

new Vue({
  render: h => h(App),
}).$mount('#app');

The sequence of arguments in the server message is broken

We have a long running great app on Socket.io. And when we decided to move some of our clients to Vue.js faced such a problem.

server:

socket.on('tests.message', function() {
  // No errors:
  socket.emit('tests.message', [1, 2, 3]) 
  socket.emit('tests.message', {a:1})
  socket.emit('tests.message', 'data as string')
  // Send error:
  socket.emit('tests.message', false, 'Error data')
  socket.emit('tests.message', null, 'Error data')
  socket.emit('tests.message', undefined, 'Error data')
})

client:

const socketMutations = {
  'socket_tests.message' (state, data, error) {
    if (error) {
      throw new Error(error)
    }
    console.log('work with', data)
  }
...

But on reception the sequence of arguments is broken

work with  [1, 2, 3]
work with {a: 1}
work with data as string
work with [false, "Error data"]
work with [null, "Error data"]
work with [null, "Error data"]

Why spoiled the standard mechanism of Socket.io?

Data does not flow through the web socket until I refresh the page

I don't think this is a bug with vue-socket.io-extended, but I wanted to post this question in case someone has run into a similar problem and can possibly help me.

I am trying to use web sockets with a chart that displays live time series data. The chart posts a new data point every second and I have logs that display the information for each data point in both the server-side terminal and the browser console. I am using the component configuration (i.e., no Vuex integration) because I only need a web socket connection on the page with the chart.

When I start the app, a message gets logged to the terminal showing that a web socket connection was made with the server. (Actually, three messages get logged each time I start my app and each message shows a different socket ID. I don't know why that is.) No other logs get printed to the terminal. Then when I navigate to the page that contains the chart, I expect there to be logs printed for each new data point, but no logs are printed in either the terminal or the browser console. However, while still on the page with the chart, if I refresh the browser, then the data starts coming through in the terminal and the browser console and the chart even gets populated with the correct data points.

Has anyone had a similar experience or does anyone know why the data does not flow into my app until after I refresh the page that has both the socket configuration and the chart where the data is displayed?

I am using hapi.js as my Node server, in case that helps.

How to receive/emit to a particular user?

Hi @probil,

Hope you are doing good. Now, I have a use case for having a pushing notification to the particular user and also in future I might implement chat system.

In that case, I would have to emit/receive data to a particular user right. How would I achieve it with the package? If you could throw me some docs or examples, would be useful.

How to prevent connection until authed?

I have a home page where I'm not using sockets at all. I'm using this with Vuex. Is there a way to prevent the socket from trying to connect on my home page or until it at least has the auth info in my store? There might be something obvious, it's late.

Use with a reverse proxy

I try to use vue-socket.io-extended behind a nginx reverse proxy but I always end with a 502 error.
With socket.io I used the "path" option. Is it also available on vue-socket.io-extended ?
For instance: Vue.use(VueSocketIO, io('http://192.168.1.1', {path: '/ws'}), { store })

Thanks for your help

Cannot get events to trigger Vuex actions/mutations

I am still sort of new to creating issues to github so i apologize.
I am getting a connection to the server, but any server-side emits are not being captured by vuex. They do show up in my browser console.

*** SOLVED ***
Vue.use(VueSocketio, io('http://127.0.0.1:3000', {store}));
vs
Vue.use(VueSocketio, io('http://127.0.0.1:3000'), {store});

image

// store/modules/courier.js
const state = {
    isConnected : false
}
const mutations = {
    console: (state, status) => {
        console.log('lel')
    },
    SOCKET_UPDATE_OPEN_ORDERS(state,status){
        state.isConnected = true
        console.log('done')
    },
}
const getters = {
    getConnection:(state)=>{
        return state.isConnected
    }
}
const actions = {
    socket_updateOpenOrders(state) {
        console.log('EVENT RECEIVED: UPDATE_OPEN_ORDERS')
        state.commit('console')
    },
}
export default {
    namespaced: true,
    state,
    getters,
    mutations,
    actions
}
// store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import courier from './modules/courier'
Vue.use(Vuex)

const debug = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
    plugins: [createPersistedState()],
    modules: {
        courier,
    },
    strict: debug,
})
// main.js 
import store from './store'
Vue.use(VueSocketio, io('http://127.0.0.1:3000', {store}));
// BACKEND
// socket.js
const socket_io = require('socket.io');
const io = socket_io();

const socketApi = {};

socketApi.io = io;

io.on('connection', function (socket) {
    socket.emit('UPDATE_OPEN_ORDERS')
});
module.exports = socketApi;

If anyone can figure out where I went wrong please help. I had it working earlier, but i forgot to stash my changes.

ESLint requires Vuex actions to be "camelcased"

Hi,

I use EsLint to lint my code. EsLint requires actions to be "camelcased" but vue-socket.io(-extend) does not respect this requirement... How could I fix that?
SERVER:

socket.emit('myTestSocket', 'this is a test socket')

ACTIONS:

actions: {
  socket_myTestSocket (values) { // -> error: should be socketMyTestSocket ?
    console.log('this is the response of the server: ' + values)
  }
}

Backend not firing any event to frontend, though in connected state

Hi,

I'm using the same code as in #65. After solving that issue in 65, my frontend says, it's connected(identified using the console).

But, in my backend, the connect action is not working. Also, it's not listening to any function from the frontend.

What am I doing wrong?

Backend

io.on('connection', function(socket){
  console.log('An user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });  
  
  socket.on('emit_method', function(msg){
    console.log('message: ' + msg);
  }); 
  
});

Frontend

      this.$socket.emit('emit_method', 'handshake')

Client could not reach server in production

Hey @probil,
Hope you are doing good.

This is my code which helped me to run the app locally: #67 (comment)
When I have successfully deployed to the server, I changed the URL from localhost:3000 to mydomain.com, it throws an error as below. What should I do more?

GET http://localhost:3000/socket.io/?EIO=3&transport=polling&t=MHV7jPy 0 ()

image

This library doesn't merge it's property with a parent mixin

Hey There!

Shouldn't this library merge it's socket object with a potential mixin-defined sockets object?
If i want to factorise code between two components recieving the same events, but also specific ones, i can't put that in a mixin as of for now.

When i console.log this.$options.sockets, it only contains the callbacks of the child component, not the mixin.

Here's a sandbox to reproduce

https://codesandbox.io/s/lrmk8m5lmq

I haven't found any issue about this?

Cheers !

Accessing this.$socket from Vuex actions

Hi,

In my project's folder structure I splitted my Vuex actions (and also mutations, getters and state) into separate files, like suggested here.

Here is an example of an action.js file:

export const saveUserLog = ({ commit, rootState }, data) => {
  data.user = rootState.globalModule.userConnected._id
  commit('addUserLogToTempMemory', data)
  this.$socket.emit('saveUserLog', data) // this doesn't work
}

How can I access to the $socket instance from within my action ?

I tried

export const saveUserLog = ({ commit, rootState, Vue }, data) => { // adding Vue here
  data.user = rootState.globalModule.userConnected._id
  commit('addUserLogToTempMemory', data)
  Vue.$socket.emit('saveUserLog', data) // to access from here
}

and like suggested in this post

export const saveUserLog = ({ commit, rootState }, data) => {
  data.user = rootState.globalModule.userConnected._id
  commit('addUserLogToTempMemory', data)
  this._vm.$socket.emit('saveUserLog', data) // doesn't work
}

Can you help me?
Thanks

Connect event isn't sent to component

I have included Vue-socket.io with the following code:

import VueSocketIO from 'vue-socket.io-extended'
import io from 'socket.io-client'
const socketInstance = io('http://localhost:8080')
socketInstance.on('connect', client => {
  console.log('A')
}}

Vue.use(VueSocketIO, socketInstance)

And in my single-file component, I use the following to listen to a connected event:

<script>
export default {
  sockets: {
    connect: function () {
      console.log('B')
    }
  },

Unfortunately, while my socket.io-client instance itself does trigger a connect event (A is printed), the code in the component is not triggered (B is not printed). Any clue as to what I may be doing wrong here?

Socket.io namespace support

The only other library (vue-websocket) that claims to have websocket support I can't get to work.

Adding this feature would be awesome, though I imagine it wouldn't be trivial.

Reactive connected property

Hey, thanks for this plugin. Works great and the upgrade from vue-socket.io was much needed.

I've noticed that the $socket.connected and `$socket.disconnected`` properties are not reactive. Any way to do this or can I request this feature? :)

Thanks

Access to "global" socket connection

Thx for your library, if it's possible to have connection with socket, which I've registered as "global" through not Vue code, so if it's possible to have access to socket which I've registered not through your library?

Thx

question about emit

augmentMethod(Socket, 'onevent', (packet) => {
  const [eventName, ...args] = packet.data;
  GlobalEmitter.emit(eventName, ...args);
  passToStore(eventName, args);
});

Socket.onevent function already have emit call (emit.apply(...))
Above augmentMethod function you call emit again. I confused about this. Can you clarify

Dynamic Socket.io IP after build time

Hello,

So recently I created a StackOverflow post about the issue I am having. My socket.io URL is set during build time and I am somehow unable to change that. Do you know of a way where I can dynamically change the IP based on the current machine's IP? So lets say I am developing the app on 192.168.0.123 and I move the app to machine 192.168.0.234, it should detect that and connect the app to that machine.

emit from store

Hello. I have something like this. How i can make this working?

export const getters = {
    isAuthenticated(state) {
      return state.auth.loggedIn
    },
  
    loggedInUser(state) {
      return state.auth.user
    },
    isAdmin(state) {
      return state.auth.user.is_admin
    }
  }

  export const state = () => ({
    isConnected: false,
    coin: ''
  })
  
  export const mutations = {
    SOCKET_CONNECT(state, socket) {
      state.isConnected = true;
        

 **this.$socket.emit('deposit_withdraw')**

    },
    SOCKET_DISCONNECT(state){
      state.isConnected = false;
    },
    SOCKET_DEPOSIT_WITHDRAW(state, coins) {
      state.coin = coins;
    }
  }

Socket connect not triggering from Vue to Nodejs backend!

Hi,

I was very worried about the vue-socket.io as it seems to unmaintained. And you come for the rescue. Thanks a lot for this.

In my project, I'm using node.js for backend API running at localhost:3000 and Vue for frontend running at localhost:8080. I have added the basic socket code to print console on connecting. But it's not working.

Below is my code

Node backend: app.js

const http = require('http');
const io = require('socket.io')(http);

io.on('connection', function(socket){
  console.log('An user connected');
});

and Vue frontend: main.js

import VueSocketio from 'vue-socket.io-extended'
import io from 'socket.io-client'

Vue.use(VueSocketio, io('http://socketserver.com:1923'))


new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: { App },
  sockets: {
    connect () {
      console.log('socket connected')
    },
    customEmit (val) {
      console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)', val)
    }
  },
  methods: {
    clickButton (val) {
      // this.$socket is `socket.io-client` instance
      this.$socket.emit('emit_method', val)
    }
  }
})

What am I doing wrong?

SOCKET_CONNECT or any other event doesn't fire

The socket has been connected on the server but the SOCKET_CONNECT in my store.js is not firing. Copied example from docs. In fact it doesn't fire the connect or any other events. Connected event does fire on server. I tried adding the code to the main.js too but that doesn't work. At a loss.

main.js

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
import nav from './_nav'
import Vuex from 'vuex'

import io from 'socket.io-client';
import VueSocketIO from 'vue-socket.io-extended';

Vue.use(Vuex);

const socket = io(process.env.API_URL, { autoConnect: true });

Vue.use(VueSocketIO, socket, { store } );

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  template: '<App/>',
  components: {
    App
  },
  sockets: {
    connect() {
      debugger;  //doesn't get here
      console.log('socket connected')
    },
    customEmit(val) {
      console.log('this method was fired by the socket server. eg: io.emit("customEmit", data)')
    }
  }
})

store.js:

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

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    isConnected: false
  }
  mutations: {
    SOCKET_CONNECT(state) {
      debugger;  //doesn't get here
    }
  }
});

Vuex module decorators and action functions

Hi, I am trying to use vue-socket.io-extended with the Vuex Module Decorators library, with the following setup:

store/DataStream.ts

import { Module, VuexModule, MutationAction, Mutation, Action} from 'vuex-module-decorators';
import axios from 'axios';

@Module({ namespaced: true, name: 'DataStream'})
export default class DataStream extends VuexModule {
  public num: number = 1;

  @Mutation
  public SOCKET_RANDOM(num: number) {
    this.num = num;
    console.log('Mutation', this.num);
  }

  @Action({ rawError: true })
  public socket_random(num: number) {
    console.log(num);
  }
}

store/store.ts

import Vue from 'vue';
import Vuex from 'vuex';
import DataStream from './dataStream';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {},
  mutations: {},
  actions: {},
  modules: {
    DataStream,
  },
});

main.ts

import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store/store';
import VueSocketio from 'vue-socket.io-extended';
import io from 'socket.io-client';

const baseURL = 'http://localhost:5000';

Vue.config.productionTip = false;
Vue.use(VueSocketio, io(baseURL), { store });

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount('#app');

I have a web server emitting random numbers, and for the mutation function everything is working fine. The socket_random function outputs Mutation 1 etc. as expected. The action function on the other hand, does not work and outputs the following error (with rawError: true):

index.js?6fc5:232 Uncaught (in promise) Error: ERR_STORE_NOT_PROVIDED: To use getModule(), either the module
should be decorated with store in decorator, i.e. @module({store: store}) or
store should be passed when calling getModule(), i.e. getModule(MyModule, this.$store)
at value (index.js?6fc5:232)
at getModule (index.js?6fc5:20)
at Store.eval (index.js?6fc5:295)
at step (index.js?6fc5:107)
at Object.eval [as next] (index.js?6fc5:88)
at eval (index.js?6fc5:81)
at new Promise ()
at __awaiter (index.js?6fc5:77)
at Store.action (index.js?6fc5:287)
at Array.wrappedActionHandler (vuex.esm.js?2f62:704)

Do you have any suggestions on how to fix this error? I don't know it this belongs more here or in Vuex Module Decorators, so let me know if it does not.

Thanks!

Clarification of README

I think in the README documentation, it should be "Prepend to event name while converting event to action." instead of "Append to event name while converting event to action." in order to make it clear that the prefixes are in fact put before the mutation/action names and not after.

not able to communicate from vuejs to nodejs

i'm able to receive emitted data from nodejs to vuejs via mutators.

how to emit data from vuejs to nodejs?
Please let me know. i'm not able to find any docs related to this.

Connection in the local network

Hello @probil,

I am wondering if I wrote this incorrectly but I can't get the socket to connect to my server. My server address is http://0.0.0.0:3000 and this is the socket.io.js code I have:

import Vue from 'vue'
import io from 'socket.io-client'
import VueSocketIO from 'vue-socket.io-extended'

export default ({ store }) => {
  Vue.use(VueSocketIO, io("http://0.0.0.0:3000"), { store })
}

watching $route to trigger $socket.emit fires error

Hi,
I need help because I cant't find answers on the internet...
I'm trying to synchronize 2 clients via sockets. So when client A changes $route (e.g clicking on a menu that changes the $route), it should trigger a $socket call to client B. But when I'm calling socket it turns into error.

Here's my watcher in my component:

  watch: {
    $route (to, from) {
      console.log('CHANGING ROUTE') // -> this is working
      this.$socket.emit('syncRoutes', {from: from, to: to}) // -> error "Maximum call stack size exceed
    }
  }

Here's the error

[Vue warn]: Error in callback for watcher "$route": "RangeError: Maximum call stack size exceeded"

RangeError: Maximum call stack size exceeded
    at Function.[Symbol.hasInstance] (<anonymous>)
    at hasBinary (index.js?e7e2:46)
    at hasBinary (index.js?e7e2:46)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)

If instead of calling $socket.emit I call another function (e.g a Vuex store action) it works. But each time I insert a socket call, it goes wrong.

I also tried this

  beforeRouteUpdate (to, from, next) {
    // react to route changes...
    console.log('CHANGING ROUTE')
    this.$socket.emit('syncRoutes', {from: from, to: to})
    // don't forget to call next()
    next()
  }

... ant the error:

[vue-router] uncaught error during route navigation

RangeError: Maximum call stack size exceeded
    at Function.[Symbol.hasInstance] (<anonymous>)
    at hasBinary (index.js?e7e2:46)
    at hasBinary (index.js?e7e2:46)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)
    at hasBinary (index.js?e7e2:58)

Any idea ?
Thanks

Usage with Nuxt

Thanks so much for the library! It looks very promising. Unfortunately, I can’t get this running with Nuxt. This is what my store looks like:

import Vue from 'vue'
import Vuex from 'vuex'
import VueSocketio from 'vue-socket.io-extended'
import io from 'socket.io-client'

Vue.use(Vuex)

const store = () => new Vuex.Store({
  state: {
    connect: false,
    message: null
  },
  mutations: {
    SOCKET_CONNECT (state, status) {
      console.log('mutations: SOCKET_CONNECT')
      state.connect = true
    },
    SOCKET_USER_MESSAGE (state, message) {
      console.log('mutations: SOCKET_USER_MESSAGE')
      state.message = message
    }
  },
  actions: {
    socket_userMessage (context, message) {
      console.log('Action: socket_userMessage')
    }
  }
})

Vue.use(VueSocketio, io('http://localhost:8080'), { store })

export default store

Whenever I open the website it crashes with this message:

project/node_modules/vue-socket.io-extended/dist/vue-socket.io-ext.min.js:1
(function (exports, require, module, __filename, __dirname) { !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.VueSocketIOExt=e()}(this,function(){"use strict";var t=function(t){return"function"==typeof t},e=function(){for(var t=arguments.length,e=Array(t),n=0;n<t;n++)e[n]=arguments[n];return function(t){return e.reduce(function(t,e){return e(t)},t)}},n=function(t){return function(e){return t+e}},r=function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")},o=function(){function t(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}return function(e,n,r){return n&&t(e.prototype,n),r&&t(e,r),e}}(),i=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var r 

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at t.value (project/node_modules/vue-socket.io-extended/dist/vue-socket.io-ext.min.js:1:4003)
    at Socket.<anonymous> (project/node_modules/vue-socket.io-extended/dist/vue-socket.io-ext.min.js:1:3687)
    at Socket.Emitter.emit (project/node_modules/socket.io-client/node_modules/component-emitter/index.js:131:20)
    at Socket.emit (project/node_modules/socket.io-client/lib/socket.js:136:10)
    at Manager.emitAll (project/node_modules/socket.io-client/lib/manager.js:81:27)
    at Socket.<anonymous> (project/node_modules/socket.io-client/lib/manager.js:230:10)
    at Socket.Emitter.emit (project/node_modules/engine.io-client/node_modules/component-emitter/index.js:134:20)
    at Socket.onError (project/node_modules/engine.io-client/lib/socket.js:673:8)
    at XHR.<anonymous> (project/node_modules/engine.io-client/lib/socket.js:264:10)
    at XHR.Emitter.emit (project/node_modules/engine.io-client/node_modules/component-emitter/index.js:134:20)
    at XHR.Transport.onError (project/node_modules/engine.io-client/lib/transport.js:65:8)
    at Request.<anonymous> (project/node_modules/engine.io-client/lib/transports/polling-xhr.js:127:10)
    at Request.Emitter.emit (project/node_modules/engine.io-client/node_modules/component-emitter/index.js:134:20)
    at Request.onError (project/node_modules/engine.io-client/lib/transports/polling-xhr.js:300:8)
    at Timeout._onTimeout (project/node_modules/engine.io-client/lib/transports/polling-xhr.js:247:18)

I’m not sure if that is connected in any way, but I would be grateful for any help.

EDIT: It does work without the store inside a component.

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Error type: undefined. Note: this is a nested preset so please contact the preset author if you are unable to fix it yourself.

Enable debug

Hi,

How can I set debug enable on start config?

import Vue from 'vue'
import VueSocketIO from 'vue-socket.io-extended'
import io from 'socket.io-client'

const socket = io('http://localhost:4000')

Vue.use(VueSocketIO, socket)

Thanks

Full-featured examples

It would be nice to have a demonstration of how library can be used.
By "full-featured example" I mean application that has both front-end and back-end part, user can interact with it interactively, check the code.

I think we should start with a simple example and move to more complex.
It seems like codesandbox suits well for that but further investigation is needed.

  • Investigate hosting providers
  • Build "Echo server"
  • Build "Simple Chat"
  • Build "Twitter stream" (like on socket.io, or reuse their API)
  • Update README

How to use "sockets" property?

@probil thx for extension version for VueSocket.io and great support!
I want to know how sockets property really works?

I use library like that for handle events:
this.$socket.on(event, data => {})

I think like sockets property do the same, my event is dynamic variable and depends on id

How I can use sockets property in that case?

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.