├── .gitignore ├── README.md ├── dist ├── build.js └── build.js.map ├── package.json ├── vue-echo.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | .idea/ 4 | .DS_Store 5 | .idea 6 | yarn.lock -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-echo 2 | Vue 2 integration for the Laravel Echo library. 3 | 4 | This Vue plugin injects a Laravel Echo instance into all of your vue instances, allowing for a simple channel subscription on each instance, or using Laravel Echo through `this.$echo`. 5 | 6 | ## Install 7 | 8 | ``` bash 9 | npm install vue-echo --save 10 | ``` 11 | 12 | ## Usage 13 | 14 | ### Initialize 15 | First you'll need to register the plugin and, optionally, initialize the Echo instance. 16 | 17 | ``` js 18 | import VueEcho from 'vue-echo'; 19 | 20 | Vue.use(VueEcho, { 21 | broadcaster: 'pusher', 22 | key: 'PUSHER KEY' 23 | }); 24 | 25 | /** 26 | * Alternatively you can pass an echo instance: 27 | * ******************************************** 28 | * import Echo from 'laravel-echo'; 29 | * 30 | * const EchoInstance = new Echo({ 31 | * broadcaster: 'pusher', 32 | * key: 'PUSHER KEY' 33 | * }); 34 | * Vue.use(VueEcho, EchoInstance); 35 | */ 36 | ``` 37 | 38 | ### Using Echo 39 | Once vue-echo is registered, every vue instance is able to subscribe to channels and listen to events through the `this.$echo` property on the connection you specified earlier. 40 | 41 | ```js 42 | var vm = new Vue({ 43 | mounted() { 44 | // Listen for the 'NewBlogPost' event in the 'team.1' private channel 45 | this.$echo.private('team.1').listen('NewBlogPost', (payload) => { 46 | console.log(payload); 47 | }); 48 | } 49 | }); 50 | ``` 51 | 52 | ### Subscribe your Vue instance to a single channel 53 | You can subscribe a vue instance to a single standard channel if needed and define your events. 54 | 55 | ```js 56 | var vm = new Vue({ 57 | channel: 'blog', 58 | echo: { 59 | 'BlogPostCreated': (payload, vm) => { 60 | console.log('blog post created', payload); 61 | }, 62 | 'BlogPostDeleted': (payload, vm) => { 63 | console.log('blog post deleted', payload); 64 | } 65 | } 66 | }); 67 | ``` 68 | 69 | Since the scope of `this` would be the same as the scope where you declare your Vue instance a second parameter is added to these locally registered events. This parameter is a direct reference to your Vue instance, you can make any changes you need through there. 70 | 71 | #### Subscribing to channels 72 | 73 | Laravel Echo allows you to subscribe to: normal, private and presence channels. 74 | 75 | In the example above, we subscribed to a standard channel. 76 | 77 | ##### Private channel 78 | If you would like to subscribe to a private channel instead, prefix your channel name with `private:` 79 | 80 | ```js 81 | var vm = new Vue({ 82 | channel: 'private:team.1', 83 | echo: { 84 | 'BlogPostCreated': (payload, vm) => { 85 | console.log('blog post created', payload); 86 | }, 87 | 'BlogPostDeleted': (payload, vm) => { 88 | console.log('blog post deleted', payload); 89 | } 90 | } 91 | }); 92 | ``` 93 | 94 | ##### Presence channel 95 | 96 | If you would like to subscribe to presence channel instead, prefix your channel name with `presence:` 97 | 98 | ```js 99 | var vm = new Vue({ 100 | channel: 'presence:team.1.chat', 101 | echo: { 102 | 'NewMessage': (payload, vm) => { 103 | console.log('new message from team', payload); 104 | } 105 | } 106 | }); 107 | ``` 108 | 109 | ### Manually listening to events 110 | 111 | If there's a scenario where you want to listen to events after certain conditions are met, you can do so through `this.channel`: 112 | 113 | ```js 114 | var vm = new Vue({ 115 | channel: 'private:team.1', 116 | echo: { 117 | 'BlogPostCreated': (payload, vm) => { 118 | console.log('blog post created', payload); 119 | }, 120 | 'BlogPostDeleted': (payload, vm) => { 121 | console.log('blog post deleted', payload); 122 | } 123 | }, 124 | mounted(){ 125 | if(window.user.role == 'admin'){ 126 | this.channel.listen('BlogPostEdited', (payload) => { 127 | console.log('As admin I get notified of edits', payload); 128 | }); 129 | } 130 | } 131 | }); 132 | ``` 133 | -------------------------------------------------------------------------------- /dist/build.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.VueEcho=t():e.VueEcho=t()}(this,function(){return function(e){function t(i){if(n[i])return n[i].exports;var o=n[i]={exports:{},id:i,loaded:!1};return e[i].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r=n(2),s=i(r);t.default={install:function(e,t){if(!t)throw new Error("[Vue-Echo] cannot locate options");if("object"!==("undefined"==typeof t?"undefined":o(t)))throw new Error("[Vue-Echo] cannot initiate options");"function"==typeof t.socketId?e.prototype.$echo=t:e.prototype.$echo=new s.default(t),e.mixin({mounted:function(){var e=this.$options.channel;if(e){e.startsWith("private:")?this.channel=this.$echo.private(e.replace("private:","")):e.startsWith("presence:")?this.channel=this.$echo.join(e.replace("presence:","")):this.channel=this.$echo.channel(e);var t=this.$options.echo;t&&Object.keys(t).forEach(function(e){var n=this;this.channel.listen(e,function(i){t[e](i,n)})},this)}},beforeDestroy:function(){var e=this.$options.channel;e&&(e.startsWith("private:")?e=e.replace("private:",""):e.startsWith("presence:")&&(e=e.replace("presence:","")),this.$echo.leave(e))}})}}},function(e,t){var n=(function(){function e(e){this.value=e}function t(t){function n(e,t){return new Promise(function(n,o){var u={key:e,arg:t,resolve:n,reject:o,next:null};s?s=s.next=u:(r=s=u,i(e,t))})}function i(n,r){try{var s=t[n](r),u=s.value;u instanceof e?Promise.resolve(u.value).then(function(e){i("next",e)},function(e){i("throw",e)}):o(s.done?"return":"normal",s.value)}catch(e){o("throw",e)}}function o(e,t){switch(e){case"return":r.resolve({value:t,done:!0});break;case"throw":r.reject(t);break;default:r.resolve({value:t,done:!1})}r=r.next,r?i(r.key,r.arg):s=null}var r,s;this._invoke=n,"function"!=typeof t.return&&(this.return=void 0)}return"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(e){return this._invoke("next",e)},t.prototype.throw=function(e){return this._invoke("throw",e)},t.prototype.return=function(e){return this._invoke("return",e)},{wrap:function(e){return function(){return new t(e.apply(this,arguments))}},await:function(t){return new e(t)}}}(),function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}),i=function(){function e(e,t){for(var n=0;n {\n events[key](payload, this);\n });\n }, this);\n }\n }\n },\n beforeDestroy(){\n let channel = this.$options['channel'];\n\n if(channel){\n if(channel.startsWith('private:'))\n {\n channel = channel.replace('private:', '');\n }\n else if(channel.startsWith('presence:'))\n {\n channel = channel.replace('presence:', '');\n }\n\n this.$echo.leave(channel);\n }\n }\n })\n }\n}\n\n\n// WEBPACK FOOTER //\n// ./vue-echo.js","var asyncGenerator = function () {\n function AwaitValue(value) {\n this.value = value;\n }\n\n function AsyncGenerator(gen) {\n var front, back;\n\n function send(key, arg) {\n return new Promise(function (resolve, reject) {\n var request = {\n key: key,\n arg: arg,\n resolve: resolve,\n reject: reject,\n next: null\n };\n\n if (back) {\n back = back.next = request;\n } else {\n front = back = request;\n resume(key, arg);\n }\n });\n }\n\n function resume(key, arg) {\n try {\n var result = gen[key](arg);\n var value = result.value;\n\n if (value instanceof AwaitValue) {\n Promise.resolve(value.value).then(function (arg) {\n resume(\"next\", arg);\n }, function (arg) {\n resume(\"throw\", arg);\n });\n } else {\n settle(result.done ? \"return\" : \"normal\", result.value);\n }\n } catch (err) {\n settle(\"throw\", err);\n }\n }\n\n function settle(type, value) {\n switch (type) {\n case \"return\":\n front.resolve({\n value: value,\n done: true\n });\n break;\n\n case \"throw\":\n front.reject(value);\n break;\n\n default:\n front.resolve({\n value: value,\n done: false\n });\n break;\n }\n\n front = front.next;\n\n if (front) {\n resume(front.key, front.arg);\n } else {\n back = null;\n }\n }\n\n this._invoke = send;\n\n if (typeof gen.return !== \"function\") {\n this.return = undefined;\n }\n }\n\n if (typeof Symbol === \"function\" && Symbol.asyncIterator) {\n AsyncGenerator.prototype[Symbol.asyncIterator] = function () {\n return this;\n };\n }\n\n AsyncGenerator.prototype.next = function (arg) {\n return this._invoke(\"next\", arg);\n };\n\n AsyncGenerator.prototype.throw = function (arg) {\n return this._invoke(\"throw\", arg);\n };\n\n AsyncGenerator.prototype.return = function (arg) {\n return this._invoke(\"return\", arg);\n };\n\n return {\n wrap: function (fn) {\n return function () {\n return new AsyncGenerator(fn.apply(this, arguments));\n };\n },\n await: function (value) {\n return new AwaitValue(value);\n }\n };\n}();\n\nvar classCallCheck = function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n};\n\nvar createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n}();\n\nvar _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n};\n\nvar inherits = function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n};\n\nvar possibleConstructorReturn = function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n};\n\nvar Connector = function () {\n function Connector(options) {\n classCallCheck(this, Connector);\n\n this._defaultOptions = {\n auth: {\n headers: {}\n },\n authEndpoint: '/broadcasting/auth',\n broadcaster: 'pusher',\n csrfToken: null,\n host: null,\n key: null,\n namespace: 'App.Events'\n };\n this.setOptions(options);\n this.connect();\n }\n\n createClass(Connector, [{\n key: 'setOptions',\n value: function setOptions(options) {\n this.options = _extends(this._defaultOptions, options);\n if (this.csrfToken()) {\n this.options.auth.headers['X-CSRF-TOKEN'] = this.csrfToken();\n }\n return options;\n }\n }, {\n key: 'csrfToken',\n value: function csrfToken() {\n var selector = void 0;\n if (typeof window !== 'undefined' && window['Laravel'] && window['Laravel'].csrfToken) {\n return window['Laravel'].csrfToken;\n } else if (this.options.csrfToken) {\n return this.options.csrfToken;\n } else if (typeof document !== 'undefined' && (selector = document.querySelector('meta[name=\"csrf-token\"]'))) {\n return selector.getAttribute('content');\n }\n return null;\n }\n }]);\n return Connector;\n}();\n\nvar Channel = function () {\n function Channel() {\n classCallCheck(this, Channel);\n }\n\n createClass(Channel, [{\n key: 'notification',\n value: function notification(callback) {\n return this.listen('.Illuminate\\\\Notifications\\\\Events\\\\BroadcastNotificationCreated', callback);\n }\n }, {\n key: 'listenForWhisper',\n value: function listenForWhisper(event, callback) {\n return this.listen('.client-' + event, callback);\n }\n }]);\n return Channel;\n}();\n\nvar EventFormatter = function () {\n function EventFormatter(namespace) {\n classCallCheck(this, EventFormatter);\n\n this.setNamespace(namespace);\n }\n\n createClass(EventFormatter, [{\n key: 'format',\n value: function format(event) {\n if (event.charAt(0) === '.' || event.charAt(0) === '\\\\') {\n return event.substr(1);\n } else if (this.namespace) {\n event = this.namespace + '.' + event;\n }\n return event.replace(/\\./g, '\\\\');\n }\n }, {\n key: 'setNamespace',\n value: function setNamespace(value) {\n this.namespace = value;\n }\n }]);\n return EventFormatter;\n}();\n\nvar PusherChannel = function (_Channel) {\n inherits(PusherChannel, _Channel);\n\n function PusherChannel(pusher, name, options) {\n classCallCheck(this, PusherChannel);\n\n var _this = possibleConstructorReturn(this, (PusherChannel.__proto__ || Object.getPrototypeOf(PusherChannel)).call(this));\n\n _this.name = name;\n _this.pusher = pusher;\n _this.options = options;\n _this.eventFormatter = new EventFormatter(_this.options.namespace);\n _this.subscribe();\n return _this;\n }\n\n createClass(PusherChannel, [{\n key: 'subscribe',\n value: function subscribe() {\n this.subscription = this.pusher.subscribe(this.name);\n }\n }, {\n key: 'unsubscribe',\n value: function unsubscribe() {\n this.pusher.unsubscribe(this.name);\n }\n }, {\n key: 'listen',\n value: function listen(event, callback) {\n this.on(this.eventFormatter.format(event), callback);\n return this;\n }\n }, {\n key: 'stopListening',\n value: function stopListening(event) {\n this.subscription.unbind(this.eventFormatter.format(event));\n return this;\n }\n }, {\n key: 'on',\n value: function on(event, callback) {\n this.subscription.bind(event, callback);\n return this;\n }\n }]);\n return PusherChannel;\n}(Channel);\n\nvar PusherPrivateChannel = function (_PusherChannel) {\n inherits(PusherPrivateChannel, _PusherChannel);\n\n function PusherPrivateChannel() {\n classCallCheck(this, PusherPrivateChannel);\n return possibleConstructorReturn(this, (PusherPrivateChannel.__proto__ || Object.getPrototypeOf(PusherPrivateChannel)).apply(this, arguments));\n }\n\n createClass(PusherPrivateChannel, [{\n key: 'whisper',\n value: function whisper(eventName, data) {\n this.pusher.channels.channels[this.name].trigger('client-' + eventName, data);\n return this;\n }\n }]);\n return PusherPrivateChannel;\n}(PusherChannel);\n\nvar PusherPresenceChannel = function (_PusherChannel) {\n inherits(PusherPresenceChannel, _PusherChannel);\n\n function PusherPresenceChannel() {\n classCallCheck(this, PusherPresenceChannel);\n return possibleConstructorReturn(this, (PusherPresenceChannel.__proto__ || Object.getPrototypeOf(PusherPresenceChannel)).apply(this, arguments));\n }\n\n createClass(PusherPresenceChannel, [{\n key: 'here',\n value: function here(callback) {\n this.on('pusher:subscription_succeeded', function (data) {\n callback(Object.keys(data.members).map(function (k) {\n return data.members[k];\n }));\n });\n return this;\n }\n }, {\n key: 'joining',\n value: function joining(callback) {\n this.on('pusher:member_added', function (member) {\n callback(member.info);\n });\n return this;\n }\n }, {\n key: 'leaving',\n value: function leaving(callback) {\n this.on('pusher:member_removed', function (member) {\n callback(member.info);\n });\n return this;\n }\n }, {\n key: 'whisper',\n value: function whisper(eventName, data) {\n this.pusher.channels.channels[this.name].trigger('client-' + eventName, data);\n return this;\n }\n }]);\n return PusherPresenceChannel;\n}(PusherChannel);\n\nvar SocketIoChannel = function (_Channel) {\n inherits(SocketIoChannel, _Channel);\n\n function SocketIoChannel(socket, name, options) {\n classCallCheck(this, SocketIoChannel);\n\n var _this = possibleConstructorReturn(this, (SocketIoChannel.__proto__ || Object.getPrototypeOf(SocketIoChannel)).call(this));\n\n _this.events = {};\n _this.name = name;\n _this.socket = socket;\n _this.options = options;\n _this.eventFormatter = new EventFormatter(_this.options.namespace);\n _this.subscribe();\n _this.configureReconnector();\n return _this;\n }\n\n createClass(SocketIoChannel, [{\n key: 'subscribe',\n value: function subscribe() {\n this.socket.emit('subscribe', {\n channel: this.name,\n auth: this.options.auth || {}\n });\n }\n }, {\n key: 'unsubscribe',\n value: function unsubscribe() {\n this.unbind();\n this.socket.emit('unsubscribe', {\n channel: this.name,\n auth: this.options.auth || {}\n });\n }\n }, {\n key: 'listen',\n value: function listen(event, callback) {\n this.on(this.eventFormatter.format(event), callback);\n return this;\n }\n }, {\n key: 'on',\n value: function on(event, callback) {\n var _this2 = this;\n\n var listener = function listener(channel, data) {\n if (_this2.name == channel) {\n callback(data);\n }\n };\n this.socket.on(event, listener);\n this.bind(event, listener);\n }\n }, {\n key: 'configureReconnector',\n value: function configureReconnector() {\n var _this3 = this;\n\n var listener = function listener() {\n _this3.subscribe();\n };\n this.socket.on('reconnect', listener);\n this.bind('reconnect', listener);\n }\n }, {\n key: 'bind',\n value: function bind(event, callback) {\n this.events[event] = this.events[event] || [];\n this.events[event].push(callback);\n }\n }, {\n key: 'unbind',\n value: function unbind() {\n var _this4 = this;\n\n Object.keys(this.events).forEach(function (event) {\n _this4.events[event].forEach(function (callback) {\n _this4.socket.removeListener(event, callback);\n });\n delete _this4.events[event];\n });\n }\n }]);\n return SocketIoChannel;\n}(Channel);\n\nvar SocketIoPrivateChannel = function (_SocketIoChannel) {\n inherits(SocketIoPrivateChannel, _SocketIoChannel);\n\n function SocketIoPrivateChannel() {\n classCallCheck(this, SocketIoPrivateChannel);\n return possibleConstructorReturn(this, (SocketIoPrivateChannel.__proto__ || Object.getPrototypeOf(SocketIoPrivateChannel)).apply(this, arguments));\n }\n\n createClass(SocketIoPrivateChannel, [{\n key: 'whisper',\n value: function whisper(eventName, data) {\n this.socket.emit('client event', {\n channel: this.name,\n event: 'client-' + eventName,\n data: data\n });\n return this;\n }\n }]);\n return SocketIoPrivateChannel;\n}(SocketIoChannel);\n\nvar SocketIoPresenceChannel = function (_SocketIoPrivateChann) {\n inherits(SocketIoPresenceChannel, _SocketIoPrivateChann);\n\n function SocketIoPresenceChannel() {\n classCallCheck(this, SocketIoPresenceChannel);\n return possibleConstructorReturn(this, (SocketIoPresenceChannel.__proto__ || Object.getPrototypeOf(SocketIoPresenceChannel)).apply(this, arguments));\n }\n\n createClass(SocketIoPresenceChannel, [{\n key: 'here',\n value: function here(callback) {\n this.on('presence:subscribed', function (members) {\n callback(members.map(function (m) {\n return m.user_info;\n }));\n });\n return this;\n }\n }, {\n key: 'joining',\n value: function joining(callback) {\n this.on('presence:joining', function (member) {\n return callback(member.user_info);\n });\n return this;\n }\n }, {\n key: 'leaving',\n value: function leaving(callback) {\n this.on('presence:leaving', function (member) {\n return callback(member.user_info);\n });\n return this;\n }\n }]);\n return SocketIoPresenceChannel;\n}(SocketIoPrivateChannel);\n\nvar NullChannel = function (_Channel) {\n inherits(NullChannel, _Channel);\n\n function NullChannel() {\n classCallCheck(this, NullChannel);\n return possibleConstructorReturn(this, (NullChannel.__proto__ || Object.getPrototypeOf(NullChannel)).apply(this, arguments));\n }\n\n createClass(NullChannel, [{\n key: 'subscribe',\n value: function subscribe() {}\n }, {\n key: 'unsubscribe',\n value: function unsubscribe() {}\n }, {\n key: 'listen',\n value: function listen(event, callback) {\n return this;\n }\n }, {\n key: 'stopListening',\n value: function stopListening(event) {\n return this;\n }\n }, {\n key: 'on',\n value: function on(event, callback) {\n return this;\n }\n }]);\n return NullChannel;\n}(Channel);\n\nvar NullPrivateChannel = function (_NullChannel) {\n inherits(NullPrivateChannel, _NullChannel);\n\n function NullPrivateChannel() {\n classCallCheck(this, NullPrivateChannel);\n return possibleConstructorReturn(this, (NullPrivateChannel.__proto__ || Object.getPrototypeOf(NullPrivateChannel)).apply(this, arguments));\n }\n\n createClass(NullPrivateChannel, [{\n key: 'whisper',\n value: function whisper(eventName, data) {\n return this;\n }\n }]);\n return NullPrivateChannel;\n}(NullChannel);\n\nvar NullPresenceChannel = function (_NullChannel) {\n inherits(NullPresenceChannel, _NullChannel);\n\n function NullPresenceChannel() {\n classCallCheck(this, NullPresenceChannel);\n return possibleConstructorReturn(this, (NullPresenceChannel.__proto__ || Object.getPrototypeOf(NullPresenceChannel)).apply(this, arguments));\n }\n\n createClass(NullPresenceChannel, [{\n key: 'here',\n value: function here(callback) {\n return this;\n }\n }, {\n key: 'joining',\n value: function joining(callback) {\n return this;\n }\n }, {\n key: 'leaving',\n value: function leaving(callback) {\n return this;\n }\n }, {\n key: 'whisper',\n value: function whisper(eventName, data) {\n return this;\n }\n }]);\n return NullPresenceChannel;\n}(NullChannel);\n\nvar PusherConnector = function (_Connector) {\n inherits(PusherConnector, _Connector);\n\n function PusherConnector() {\n var _ref;\n\n classCallCheck(this, PusherConnector);\n\n for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var _this = possibleConstructorReturn(this, (_ref = PusherConnector.__proto__ || Object.getPrototypeOf(PusherConnector)).call.apply(_ref, [this].concat(args)));\n\n _this.channels = {};\n return _this;\n }\n\n createClass(PusherConnector, [{\n key: 'connect',\n value: function connect() {\n this.pusher = new Pusher(this.options.key, this.options);\n }\n }, {\n key: 'listen',\n value: function listen(name, event, callback) {\n return this.channel(name).listen(event, callback);\n }\n }, {\n key: 'channel',\n value: function channel(name) {\n if (!this.channels[name]) {\n this.channels[name] = new PusherChannel(this.pusher, name, this.options);\n }\n return this.channels[name];\n }\n }, {\n key: 'privateChannel',\n value: function privateChannel(name) {\n if (!this.channels['private-' + name]) {\n this.channels['private-' + name] = new PusherPrivateChannel(this.pusher, 'private-' + name, this.options);\n }\n return this.channels['private-' + name];\n }\n }, {\n key: 'presenceChannel',\n value: function presenceChannel(name) {\n if (!this.channels['presence-' + name]) {\n this.channels['presence-' + name] = new PusherPresenceChannel(this.pusher, 'presence-' + name, this.options);\n }\n return this.channels['presence-' + name];\n }\n }, {\n key: 'leave',\n value: function leave(name) {\n var _this2 = this;\n\n var channels = [name, 'private-' + name, 'presence-' + name];\n channels.forEach(function (name, index) {\n if (_this2.channels[name]) {\n _this2.channels[name].unsubscribe();\n delete _this2.channels[name];\n }\n });\n }\n }, {\n key: 'socketId',\n value: function socketId() {\n return this.pusher.connection.socket_id;\n }\n }, {\n key: 'disconnect',\n value: function disconnect() {\n this.pusher.disconnect();\n }\n }]);\n return PusherConnector;\n}(Connector);\n\nvar SocketIoConnector = function (_Connector) {\n inherits(SocketIoConnector, _Connector);\n\n function SocketIoConnector() {\n var _ref;\n\n classCallCheck(this, SocketIoConnector);\n\n for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var _this = possibleConstructorReturn(this, (_ref = SocketIoConnector.__proto__ || Object.getPrototypeOf(SocketIoConnector)).call.apply(_ref, [this].concat(args)));\n\n _this.channels = {};\n return _this;\n }\n\n createClass(SocketIoConnector, [{\n key: 'connect',\n value: function connect() {\n var io = this.getSocketIO();\n this.socket = io(this.options.host, this.options);\n return this.socket;\n }\n }, {\n key: 'getSocketIO',\n value: function getSocketIO() {\n if (typeof io !== 'undefined') {\n return io;\n }\n if (this.options.client !== 'undefined') {\n return this.options.client;\n }\n throw new Error('Socket.io client not found. Should be globally available or passed via options.client');\n }\n }, {\n key: 'listen',\n value: function listen(name, event, callback) {\n return this.channel(name).listen(event, callback);\n }\n }, {\n key: 'channel',\n value: function channel(name) {\n if (!this.channels[name]) {\n this.channels[name] = new SocketIoChannel(this.socket, name, this.options);\n }\n return this.channels[name];\n }\n }, {\n key: 'privateChannel',\n value: function privateChannel(name) {\n if (!this.channels['private-' + name]) {\n this.channels['private-' + name] = new SocketIoPrivateChannel(this.socket, 'private-' + name, this.options);\n }\n return this.channels['private-' + name];\n }\n }, {\n key: 'presenceChannel',\n value: function presenceChannel(name) {\n if (!this.channels['presence-' + name]) {\n this.channels['presence-' + name] = new SocketIoPresenceChannel(this.socket, 'presence-' + name, this.options);\n }\n return this.channels['presence-' + name];\n }\n }, {\n key: 'leave',\n value: function leave(name) {\n var _this2 = this;\n\n var channels = [name, 'private-' + name, 'presence-' + name];\n channels.forEach(function (name) {\n if (_this2.channels[name]) {\n _this2.channels[name].unsubscribe();\n delete _this2.channels[name];\n }\n });\n }\n }, {\n key: 'socketId',\n value: function socketId() {\n return this.socket.id;\n }\n }, {\n key: 'disconnect',\n value: function disconnect() {\n this.socket.disconnect();\n }\n }]);\n return SocketIoConnector;\n}(Connector);\n\nvar NullConnector = function (_Connector) {\n inherits(NullConnector, _Connector);\n\n function NullConnector() {\n var _ref;\n\n classCallCheck(this, NullConnector);\n\n for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n var _this = possibleConstructorReturn(this, (_ref = NullConnector.__proto__ || Object.getPrototypeOf(NullConnector)).call.apply(_ref, [this].concat(args)));\n\n _this.channels = {};\n return _this;\n }\n\n createClass(NullConnector, [{\n key: 'connect',\n value: function connect() {}\n }, {\n key: 'listen',\n value: function listen(name, event, callback) {\n return new NullChannel();\n }\n }, {\n key: 'channel',\n value: function channel(name) {\n return new NullChannel();\n }\n }, {\n key: 'privateChannel',\n value: function privateChannel(name) {\n return new NullPrivateChannel();\n }\n }, {\n key: 'presenceChannel',\n value: function presenceChannel(name) {\n return new NullPresenceChannel();\n }\n }, {\n key: 'leave',\n value: function leave(name) {}\n }, {\n key: 'socketId',\n value: function socketId() {\n return 'fake-socket-id';\n }\n }, {\n key: 'disconnect',\n value: function disconnect() {}\n }]);\n return NullConnector;\n}(Connector);\n\nvar Echo = function () {\n function Echo(options) {\n classCallCheck(this, Echo);\n\n this.options = options;\n if (typeof Vue === 'function' && Vue.http) {\n this.registerVueRequestInterceptor();\n }\n if (typeof axios === 'function') {\n this.registerAxiosRequestInterceptor();\n }\n if (typeof jQuery === 'function') {\n this.registerjQueryAjaxSetup();\n }\n if (this.options.broadcaster == 'pusher') {\n this.connector = new PusherConnector(this.options);\n } else if (this.options.broadcaster == 'socket.io') {\n this.connector = new SocketIoConnector(this.options);\n } else if (this.options.broadcaster == 'null') {\n this.connector = new NullConnector(this.options);\n }\n }\n\n createClass(Echo, [{\n key: 'registerVueRequestInterceptor',\n value: function registerVueRequestInterceptor() {\n var _this = this;\n\n Vue.http.interceptors.push(function (request, next) {\n if (_this.socketId()) {\n request.headers.set('X-Socket-ID', _this.socketId());\n }\n next();\n });\n }\n }, {\n key: 'registerAxiosRequestInterceptor',\n value: function registerAxiosRequestInterceptor() {\n var _this2 = this;\n\n axios.interceptors.request.use(function (config) {\n if (_this2.socketId()) {\n config.headers['X-Socket-Id'] = _this2.socketId();\n }\n return config;\n });\n }\n }, {\n key: 'registerjQueryAjaxSetup',\n value: function registerjQueryAjaxSetup() {\n var _this3 = this;\n\n if (typeof jQuery.ajax != 'undefined') {\n jQuery.ajaxSetup({\n beforeSend: function beforeSend(xhr) {\n if (_this3.socketId()) {\n xhr.setRequestHeader('X-Socket-Id', _this3.socketId());\n }\n }\n });\n }\n }\n }, {\n key: 'listen',\n value: function listen(channel, event, callback) {\n return this.connector.listen(channel, event, callback);\n }\n }, {\n key: 'channel',\n value: function channel(_channel) {\n return this.connector.channel(_channel);\n }\n }, {\n key: 'private',\n value: function _private(channel) {\n return this.connector.privateChannel(channel);\n }\n }, {\n key: 'join',\n value: function join(channel) {\n return this.connector.presenceChannel(channel);\n }\n }, {\n key: 'leave',\n value: function leave(channel) {\n this.connector.leave(channel);\n }\n }, {\n key: 'socketId',\n value: function socketId() {\n return this.connector.socketId();\n }\n }, {\n key: 'disconnect',\n value: function disconnect() {\n this.connector.disconnect();\n }\n }]);\n return Echo;\n}();\n\nmodule.exports = Echo;\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/laravel-echo/dist/echo.js\n// module id = 2\n// module chunks = 0"],"sourceRoot":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-echo", 3 | "version": "1.0.1", 4 | "description": "Vue integration for the Laravel Echo library.", 5 | "main": "dist/build.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/happyDemon/vue-echo" 9 | }, 10 | "keywords": [ 11 | "laravel", 12 | "pusher", 13 | "socket.io", 14 | "vue" 15 | ], 16 | "author": { 17 | "name": "Maxim Kerstens" 18 | }, 19 | "license": "MIT", 20 | "homepage": "https://github.com/happyDemon/vue-echo", 21 | "scripts": { 22 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules" 23 | }, 24 | "dependencies": { 25 | "laravel-echo": "^1.0.5", 26 | "pusher-js": "^3.2.1" 27 | }, 28 | "devDependencies": { 29 | "babel-cli": "^6.18.0", 30 | "babel-loader": "^6.2.7", 31 | "babel-preset-es2015": "^6.18.0", 32 | "babel-preset-stage-0": "^6.16.0", 33 | "cross-env": "^3.1.3", 34 | "webpack": "^1.13.3" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /vue-echo.js: -------------------------------------------------------------------------------- 1 | import Echo from 'laravel-echo'; 2 | 3 | export default { 4 | install(Vue, options) { 5 | if (!options) { 6 | throw new Error("[Vue-Echo] cannot locate options"); 7 | } 8 | 9 | if (typeof options !== 'object') { 10 | throw new Error("[Vue-Echo] cannot initiate options"); 11 | } 12 | 13 | if(typeof options.socketId == 'function') 14 | { 15 | Vue.prototype.$echo = options; 16 | } 17 | else 18 | { 19 | Vue.prototype.$echo = new Echo(options); 20 | } 21 | 22 | Vue.mixin({ 23 | mounted() { 24 | let channel = this.$options['channel']; 25 | 26 | if(channel) 27 | { 28 | if(channel.startsWith('private:')) 29 | { 30 | this.channel = this.$echo.private(channel.replace('private:', '')) 31 | } 32 | else if(channel.startsWith('presence:')) 33 | { 34 | this.channel = this.$echo.join(channel.replace('presence:', '')) 35 | } 36 | else 37 | { 38 | this.channel = this.$echo.channel(channel); 39 | } 40 | 41 | let events = this.$options['echo']; 42 | 43 | if(events) 44 | { 45 | Object.keys(events).forEach(function(key){ 46 | // Bind the VM as second parameter 47 | this.channel.listen(key, (payload) => { 48 | events[key](payload, this); 49 | }); 50 | }, this); 51 | } 52 | } 53 | }, 54 | beforeDestroy(){ 55 | let channel = this.$options['channel']; 56 | 57 | if(channel){ 58 | if(channel.startsWith('private:')) 59 | { 60 | channel = channel.replace('private:', ''); 61 | } 62 | else if(channel.startsWith('presence:')) 63 | { 64 | channel = channel.replace('presence:', ''); 65 | } 66 | 67 | this.$echo.leave(channel); 68 | } 69 | } 70 | }) 71 | } 72 | } -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | module.exports = { 4 | entry: ['./vue-echo.js'], 5 | output: { 6 | path: path.resolve(__dirname, './dist'), 7 | filename: 'build.js', 8 | library: ['VueEcho'], 9 | libraryTarget: 'umd' 10 | }, 11 | resolveLoader: { 12 | root: path.join(__dirname, 'node_modules'), 13 | }, 14 | module: { 15 | loaders: [ 16 | { 17 | test: /\.js$/, 18 | loader: 'babel', 19 | exclude: /node_modules/, 20 | query: { 21 | presets: ['es2015'] 22 | } 23 | }, 24 | { 25 | test: /\.json$/, 26 | loader: 'json' 27 | } 28 | ] 29 | }, 30 | devtool: 'eval-source-map' 31 | } 32 | 33 | if (process.env.NODE_ENV === 'production') { 34 | module.exports.devtool = 'source-map' 35 | 36 | module.exports.plugins = (module.exports.plugins || []).concat([ 37 | new webpack.DefinePlugin({ 38 | 'process.env': { 39 | NODE_ENV: '"production"' 40 | } 41 | }), 42 | new webpack.optimize.UglifyJsPlugin({ 43 | compress: { 44 | warnings: false 45 | } 46 | }), 47 | new webpack.optimize.OccurenceOrderPlugin() 48 | ]) 49 | } --------------------------------------------------------------------------------