Introducing Eiphop — An electron IPC wrapper [good fit for React apps]
Eiphop helps you simplify electron inter process communications. It abstracts the multi channel model to an HTTP like interface. It’s a great fit if you use Redux like state management. It can be used otherwise as well. The name is a combination of electron + hip hop.
Why another wrapper ?
The builtin electron IPC model is based on channels & callbacks. You fire a request and forget about it. When the response arrives, the callback is called.
I develop apis and frontends all day. Although multiple channel based architecture is more fluid, I’m more inclined to use a single channel. This helps me model renderer ← → main communications like the HTTP protocol calls.
How to use Eiphop ?
Eiphop is available as an open sourced, 0 dependancy, 2.4 kb npm package. It’s fairly easy to use. Think of Eiphop as electron equivalent of fetch
. I’ll walk through how to use Eiphop, by creating a simple server.
If you are wondering how I structure electron-react apps, you might want to read : A gluten free Electron React setup [ft. live reload]
Step 0: Install Eiphop
I prefer yarn, but you can use npm.
yarn add eiphop
Step 1: Create two action handlers
Eiphop’s main goal is to make electron development feel like web development, where the main process is the api and the renderer process is the frontend.
We’ll create two files actions/ping.js
and actions/hip.js
. Think of actions folder as a collection of your api sub modules. We have two submodules:
// actions/ping.js
const actions = {
ping: (req, res) => {
const {payload} = req;
res.send({msg: 'pong'});
// or res.error({msg: 'failed'}) }
}module.exports = actions;
The req
parameter is an object that includes the payload
sent by the client. The res
parameter is an object that includes two methods: send
and error
. Action methods can be async too.
// actions/hip.jsfunction sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}const actions = {
hip: async (req, res) => {
const {payload} = req;
await sleep(1000);
res.send({msg: 'hop'}); // or res.error({msg: 'failed'})
}
}module.exports = actions;
Step 2: Setup api
Now create a file called api.js
, and add the following to it:
// api.js
const electron = require('electron');
const {setupMainHandler} = require('eiphop');const hipActions = require('./actions/hip.js');
const pingActions = require('./actions/ping.js');setupMainHandler(electron, {...hipActions, ...pingActions}, true);
setupMainHandler
takes three arguments:
- The electron module to use
- The actions map to expose (the above example exposes two actions :
{ping: function(), hip: function()}
) - Enable logging flag (false by default).
Observe that all actions are exposed as a flattened map, so no two actions can have the same name. This is coherent with simplified a rest api. One route can only point to one resource.
Step 3: Import api in main process
You need to import the api module in your main.js. This is the file where you create the BrowserWindow.
...
const api = require('./api.js'); // <----- Add this line
...function createWindow () {
...
}app.on('ready', createWindow)
...
Step 4: Setup renderer process
In your renderer’s index.js file, setup the listener as follows:
import {setupFrontendListener} from 'eiphop';// listen to ipc responses
const electron = window.electron; // or require('electron')
setupFrontendListener(electron);
setupFrontendListener
takes only an electron module. There is no support for logging on frontend (I realised it’s easier to console log manually in renderer).
Now your channels are ready. All you need to do is trigger actions.
Step 5: Call actions
Use the emit
function to call actions defined in the main action map.
import {emit} from 'eiphop';emit('ping', {you: 'can', pass: 'data', to: 'main'})
.then(res => console.log(res)) // will log {msg: 'pong'}
.catch(err => console.log(err))
;emit('hip', {empty: 'payload'})
.then(res => console.log(res)) // will log {msg: 'hop'}
.catch(err => console.log(err))
;
emit
takes two arguments:
- The name of the action to call (this was defined is api.js actions map)
- The payload to send (this can be anything, an object, string, list etc)
Usage with React
This module was built for react and redux applications. Here is a simple React example :
import React from 'react';
import {emit} from 'eiphop';class App extends React.Component {
constructor() {
this.state = {pingRes: '', hipRes: ''}
}render() {
const {pingRes, hipRes} = this.state;
return (<div>
Ping Res = {JSON.stringify(pingRes)}
<br/>
Hip Res = {JSON.stringify(hipRes)}
<br/><button onClick={() => {
emit('ping')
.then(res => this.setState({pingRes: res}))
;
}}>
Ping
</button><button onClick={() => {
emit('hip')
.then(res => this.setState({pingRes: res}))
;
}}>
Hip
</button>
</div>);
}
}
You can similarly use this with Redux (and other solutions).
Find Eiphop on github.
Hi, if you liked this article and want to stay updated, follow me on: Medium, Github or Twitter
You might also like:
- How to embed a database in your electron app
- Shipping executables with your Electron app
- Fractal — A react app structure for infinite scale
Ta.