wormhole

Wormhole — it's better EventEmitter for communication between tabs with supporting Master/Slave.

Github stars Tracking Chart

Wormhole

It's better EventEmitter for communication between tabs with supporting Master/Slave.

npm i --save-dev wormhole.js

Features


Basic example

import wormhole from 'wormhole.js'; // yes, with ".js", it's not mistake

// All tabs
wormhole().on('coords', (x, y) => {
	console.log(x, y);
});

// Some tab
wormhole().emit('coords', [5, 10]);

// Master tab
if (wormhole().master) {
	// ..
}

wormhole().on('master', () => {
	console.log('Wow!');
});

One connection on WebSocket for all tabs

Module wormhole.js/ws implements WebSocket-like interface:
https://rubaxa.github.io/wormhole/?ws=y

import WS from 'wormhole.js/ws';

// Create WebScoket (wormhole-socket)
const socket = new WS('ws://echo.websocket.org'); // OR new WS('...', null, hole);

socket.onopen = () => console.log('Connected');
socket.onmessage = ({data}) => console.log('Received:', data);

// Unique event
socket.onmaster = () => {
	console.log('Yes, I\'m master!');
};

// Some tab
socket.send({foo: 'bar'})

// All tabs:
//  "Received:" {foo: 'bar'}

CORS example

  1. Create a subdomain, ex.: http://wormhole.youdomain.com/;
  2. Copy-paste universal.html and wormhole.js into root;
  3. Check access http://wormhole.youdomain.com/universal.html;
  4. Profit:
// http://foo.youdomain.com/
import {Universal} from 'wormhole.js';
const hole = new Universal('http://wormhole.youdomain.com/universal.html');

hole.on('data', (data) => {
	console.log(data);
});


// http://bar.youdomain.com/
import {Universal} from 'wormhole.js';
const hole = new Universal('http://wormhole.youdomain.com/universal.html');

hole.emit('data', 'any data');

Master/slave example

import wormhole from 'wormhole.js';

// All tabs (main.js)
// Define remote command (master)
wormhole()['get-data'] = (function (_cache) {
	return function getData(req, callback) {
		if (!_cache.hasOwnProperty(req.url)) {
			_cache[req.url] = fetch(req.url).then(res => res.json());
		}

		return _cache[key];
	};
})({});

// Get remote data method
function getData(url) {
	return new Promise((resolve, reject) => {
		// Calling command on master (from slave... or the master, is not important)
		wormhole().call(
			'get-data', // command
			{url}, // arguments
			(err, json) => err ? reject(err) : resolve(json) // callback(err, result)
		);
	});
};

// I'm master!
wormhole().on('master', () => {
	// some code
});

// Tab #X
getData('/path/to/api').then((json) => {
	// Send ajax request
	console.log(result);
});

// Tab #Y
getData('/path/to/api').then((result) => {
	// From master cache
	console.log(result);
});

Peers

wormhole()
	.on('peers', (peers) => {
		console.log('ids:', peers); // ['tab-id-1', 'tab-id-2', ..]
	})
	.on('peers:add', (id) => {
		// ..
	})
	.on('peers:remove', (id) => {
		// ..
	})
;

Executing the command on master

// Register command (all tabs)
wormhole()['foo'] = (data, next) => {
	// bla-bla-bla
	next(null, data.reverse()); // or `next('error')`
};


// Calling the command (some tab)
wormhole().call('foo', [1, 2, 3], (err, results) => {
	console.log(results); // [3, 2, 1]
})

Modules

  • Emitter — Micro event emitter
  • cors — Handy wrapper over postMessage.
  • store — Safe and a handy wrapper over localStorage.

wormhole.Emitter

Micro event emitter.

  • on(type:String, fn:Function):this
  • off(type:String, fn:Function):this
  • emit(type:String[, args:*, Array]):this
import {Emitter} from 'wormhole.js';

const obj = Emitter.apply({}); // or new wormhole.Emitter();

obj.on('foo', () => {
  console.log(arguments);
});

obj.emit('foo'); // []
obj.emit('foo', 1); // [1]
obj.emit('foo', [1, 2, 3]); // [1, 2, 3]

wormhole.cors

Handy wrapper over postMessage.

import {cors} from 'wormhole.js';

// Main-document
cors.on('data', (data) => {
	console.log('Received:', data);
});

cors['some:command'] = (value) => value * 2;

// IFrame
cors(parent).send({foo: 'bar'});
// [main-document] "Received:" {foo: 'bar'}

cors(parent).call('some:command', 3, (err, result) => {
	console.log('Error:', err, 'Result:', result);
	// [iframe] "Error:" null "Result:" 6
});

wormhole.store

Safe and a handy wrapper over localStorage.

  • get(key:String):*
  • set(key:String, value:*)
  • remove(key:String)
  • on(type:String, fn:Function)
  • off(type:String, fn:Function)
import {store} from 'wormhole.js';

store.on('change', (key, data) => {
	console.log('change -> ', key, data);
});

store.on('change:prop', (key, value) => {
	console.log('change:prop -> ', key, value);
});

store.set('foo', {bar: 'baz'});
// change -> foo {bar: 'baz'}

store.set('prop', {qux: 'ok'});
// change -> prop {qux: 'ok'}
// change:prop -> prop {qux: 'ok'}

Utils


wormhole.uuid():String

A universally unique identifier (UUID) is an identifier standard used in software construction,
standardized by the Open Software Foundation (OSF) as part of the Distributed Computing Environment (DCE)
(c) wiki.


wormhole.debounce(fn:Function, delay:Number[, immediate:Boolean]):Function

Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked.


Development

  • npm test
  • npm run dev — run dev watcher
  • npm run build

Main metrics

Overview
Name With OwnerRubaXa/wormhole
Primary LanguageJavaScript
Program languageJavaScript (Language Count: 3)
Platform
License:
所有者活动
Created At2014-09-03 20:12:48
Pushed At2023-06-27 05:47:15
Last Commit At2018-03-04 15:32:12
Release Count3
Last Release Name0.10.0 (Posted on 2018-03-01 14:45:59)
First Release Name0.6.0 (Posted on 2014-12-06 19:20:02)
用户参与
Stargazers Count390
Watchers Count21
Fork Count32
Commits Count94
Has Issues Enabled
Issues Count10
Issue Open Count2
Pull Requests Count3
Pull Requests Open Count1
Pull Requests Close Count0
项目设置
Has Wiki Enabled
Is Archived
Is Fork
Is Locked
Is Mirror
Is Private