Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Electron, Flux + React

2,794 views

Published on

How we built Speak (https://speak.io), a realtime team communication platform using an event sourced architecture and Electron, plus some of the challenges we faced.

Presented at the Electron Meetup at Github HQ on 29th September 2015: http://blog.atom.io/2015/09/17/electron-meetup.html

Published in: Technology
  • Be the first to comment

Electron, Flux + React

  1. 1. Electron, Flux + React Tom Moor (@tommoor)
  2. 2. What is Speak? Instant audio, video and screen share for remote teams
  3. 3. A Quick Demo What could go wrong?
  4. 4. App & Dock
  5. 5. Ring ring...
  6. 6. Audio & Video
  7. 7. Why Electron?! Are we sure this is a good idea...
  8. 8. Chromi ummmm Cross platform full stack AV implementation WebRTC as a first class citizen, always being improved upstream Node Access to underlying system Speed Lean startup, MVP Known technologies, CSS & Javascript, NW.js Cross platform a must for communication tools
  9. 9. Our Architecture It’s events all the way down
  10. 10. Microservices RabbitMQ message bus Distinct services for calls, authentication, websockets, audio mixing, api… Mixture of Ruby and Go languages Realtime API Events with payloads over websockets Transactions for responses
  11. 11. The Client Electron, Flux & React
  12. 12. Flux Data Flow Unidirectional data flow Action Dispatcher Store View
  13. 13. Flux Data Flow Unidirectional data flow Action Dispatcher Store View Libs
  14. 14. DockMain Call Node Process
  15. 15. Renderers Main, Dock, Call, (Preferences, Teams, Invites …) Each renderer has it’s own React entry point Each renderer has it’s own Flux Dispatcher and copy of all stores Events are forwarded bi-directionally through IPC Main Renderer We have one main renderer that communicates with server, renders audio etc Because complex objects can’t be passed over IPC Ensure this is never closed, only hidden
  16. 16. The lifetime of an event data flow with multiple renderers
  17. 17. User clicks dock renderer user- menu.jsx var React = require('react/addons'); var UserActions = require('../actions/user-actions'); var UserMenu = React.createClass({ call: function() { UserActions.call(this.props.item); }, render: function(){ return <ul className="actions user-actions"> <li key="call"><a onClick={this.call} className="positive"><i className=" icon-call"></i></a></li> </ul>; } }); module.exports = UserMenu;
  18. 18. Event Dispatched dock renderer user-actions.js var AppDispatcher = require('../dispatcher/app-dispatcher'); var UserStore = require('../stores/user-store'); var UserActions = { call: function(user) { AppDispatcher.dispatch('channel.invite', { user_id: user.id, sender_id: UserStore.get('id') }); } ... }; module.exports = UserActions;
  19. 19. IPC Send dock renderer app-dispatcher.js var ipc = require('ipc'); var browserWindow = require('remote').getCurrentWindow(); var AppDispatcher = Flux.createDispatcher({...}); // receive events from main process ipc.on('event', function(action, payload, opt, browser_id) { if (browser_id != browserWindow.id) { AppDispatcher.dispatch(action, payload, opt, browser_id); } }); // send events from this renderer to main process AppDispatcher.register(function(action, payload, opt, browser_id) { if (!browser_id) { ipc.send('event', action, payload, opt, browserWindow.id); } }); module.exports = AppDispatcher;
  20. 20. IPC Receive node process dispatcher.js class AppDispatcher { constructor(windows) { ipc.on('event', function(ev, action, payload, opts, browser_id){ this.dispatch(action, payload, opts, browser_id); }.bind(this)); } dispatch(action, payload, opts, browser_id) { browser_id = browser_id || 'node'; _.each(global.application.windows, function(window, window_id){ if (window_id != browser_id) { window.browserWindow.webContents.send('event', action, payload, opts, browser_id); } }); } }
  21. 21. IPC Receive main renderer app-dispatcher.js var ipc = require('ipc'); var browserWindow = require('remote').getCurrentWindow(); var AppDispatcher = Flux.createDispatcher({...}); // receive events from main process ipc.on('event', function(action, payload, opt, browser_id) { if (browser_id != browserWindow.id) { AppDispatcher.dispatch(action, payload, opt, browser_id); } }); // send events from this renderer to main process AppDispatcher.register(function(action, payload, opt, browser_id) { if (!browser_id) { ipc.send('event', action, payload, opt, browserWindow.id); } }); module.exports = AppDispatcher;
  22. 22. WebSockets main renderer socks.js var Socks = { actions: { 'channel.invite': 'send', ... }, send: function(action, params, options) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { var data = {key: action}; if (params) data.params = params; if (options) data.transaction_id = options; this.ws.send(JSON.stringify(data)); return true; } } }; module.exports = Socks;
  23. 23. What about new windows? Synchronising the state of the system
  24. 24. Local storage to the rescue! Automatically in sync between pages on the same domain
  25. 25. Extend the flux store var Store = function(definition) { return Flux.createStore(_.extend({ initialize: function() { this.rehydrateStore(); this.onChange(function(){ LocalStorage.set(this.storeName, this.state); }.bind(this)); }, rehydrateStore: function() { var data = LocalStorage.get(this.storeName); if (data) { this.state = _.extend(this.state, data); this.emit('change'); } } }, definition)); }; Using Delorean
  26. 26. Challenges Think within the box
  27. 27. Design We come up with a lot of wild and wacky ideas… Build on the advantages of Electron, not the disadvantages Don’t dupe native styles and controls if possible Complex objects limit designs (e.g streams)
  28. 28. Performance Javascript is FAST IPC is slow, avoid at all costs Starting windows is slow, we keep some open and hidden (hibernate?) Each renderer and crash reporter is a process (it adds up quickly!)
  29. 29. Windows & Linux Care of platform differences, conventions, wording Chromium still renders css differently occasionally Updates for each platform are quite different Virtual machines, VMWare for developing on Windows NPM3 for long file paths Github for Windows recommended!
  30. 30. Questions? speak.io / @speak_io / @tommoor

×