npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@actualwave/messageport-dispatcher

v1.1.7

Published

Cross-domain EventDispatcher for MessagePort interface

Downloads

414

Readme

MessagePortDispatcher

Build Status Coverage Status

MessagePortDispatcher is extended API for cross-origin communication. It utilizes MessagePort API available on window object to send custom events into/from <IFRAME/> or other target that implements MessagePort interface. MessagePortDispatcher uses two EventDispatcher's for incoming and outgoing events internally.

Demo with two <iframe/>'s talking to each other

Installation

Easy to install with npm package manager

npm install --save @actualwave/messageport-dispatcher

with yarn package manager

yarn add @actualwave/messageport-dispatcher

Usage

Note: MessagePortDispatcher distribution package contains dist/ folder with package wrapped into UMD wrapper, so it can be used with any AMD module loader, nodejs require() or without any.

To start using EventDispatcher, just instantiate it

const dispatcher = new MessagePortDispatcher(iframe.contentWindow);

As first argument its constructor accepts object that implements messaging methods of MessagePort interface.

Window object or Dedicated Worker can be used, to communicate with other side of communication channel(send event to script in IFRAME or from IFRAME or to Worker). To have custom events working on both sides, MessagePortDispatcher instances should be created from both sides of communication channel. In outer document pass IFRAME's window object

const frameDispatcher = new MessagePortDispatcher(iframeNode.contentWindow);
frameDispatcher.addEventListener('initialized', () => {
	console.log('Ok, we can start communication.');
});

In IFRAME use window.self

const dispatcher = MessagePortDispatcher.self();
dispatcher.dispatchEvent('initialized');

Instances returned from MessagePortDispatcher.self(), MessagePortDispatcher.parent() and MessagePortDispatcher.top() are cached internally, so will always return same instance.

Its possible to write an adapter for any object and pass it into MessagePortDispatcher

const target = {
	postMessage: (data, origin) => {
		console.log('Message sent', data);
		window.postMessage(data, origin);
	},
	addEventListener: (eventType, handler) => {
		console.log('Event listener added to ', eventType);
		window.addEventListener(eventType, handler);
	},
	removeEventListener: (eventType, handler) => {
		console.log('Event listener removed from ', eventType);
		window.removeEventListener(eventType, handler);
	}
};
const dispatcher = new MessagePortDispatcher(target);

Once its instance was created, you can send events into iframe

dispatcher.dispatchEvent('someEvent', {someData: 'anything here'});

and catch it on other side

dispatcher.addEventListener('someEvent', (event) => {
console.log('Data received', event.data);
});

When MessagePortDispatcher.dispatchEvent() called, it actually calls postMessage() method to pass message to other side. So instead of using postMessage and listening to message event, with MessagePortDispatcher you can send and receive custom events.

When MessagePortDispatcher instantiated, it creates two EventDispatcher's, one for incoming events and second for outgoing. Since Window object fires same message event for both sides, under the hood MessagePortDispatcher adds own ID to each event and if received event has same ID, it will be fired viasender(outgoing event) EventDispatcher, otherwise via receiver(incoming event). This will not work, event someEvent will be fired on other side but not for this dispatcher:

dispatcher.addEventListener('someEvent', () => {
	console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

If you want to listen for outgoing events, use sender:

dispatcher.sender.addEventListener('someEvent', () => {
	console.log('Some Event Received!');
});
dispatcher.dispatchEvent('someEvent');

Using same event types on both sides of communication channel will not mix them, since they will be fired from different dispatchers.

MessagePortDispatcher has exposed methods from receiver EventDispatcher for easier usage and custom dispatchEvent() method that sends events using MessagePort.postMessage(). These two calls are equivalent:

dispatcher.addEventListener('someEvent', () => {});
dispatcher.receiver.addEventListener('someEvent', () => {});

But these lines do different things:

dispatcher.dispatchEvent('someEvent');
dispatcher.sender.dispatchEvent('someEvent');

sender.dispatchEvent() will just fire event from sender EventDispatcher, but MessagePortDispatcher.dispatchEvent() will actually send message to other side via postMessage().

Since MessagePortDispatcher passes data between origins, it can send only simple data(i.e. nothing can be sent by reference) that can be converted to JSON. Before sending event, it checks its data property value. If this value has method toJSON(), it will use it and send returned data as is. In other case the value will be converted to JSON string before being sent and converted back when received. When using toJSON() method its developer's responsibility to look for nested data objects and convert everything to transferable simple objects.

Project contains example in example folder, it shows how to use MessagePortDispatcher when communicating with frames.

API

MessagePortDispatcher constructor arguments

  • target:Object - Requred, target object, should have postMessage(), addEventListener(), removeEventListener() methods, asdescribed in MessagePort docs.
  • customPostMessageHandler:Function - will be used to call target.postMessage()
  • receiverEventPreprocessor:Function - Optional, allows pre-processing of events and their data before firing event.
  • senderEventPreprocessor:Function - Optional, , allows pre-processing of events and their data before passing them to postMessage or customPostMessageHandler.

MessagePortDispatcher instance members

  • targetOrigin:String
  • sender:EventDispatcher - fires outgoing events that are passed to postMessage()
  • receiver:EventDispatcher - fires incoming events received from other origin
  • target:Object - target object that is used for communication
  • dispatcherId:String - unique ID of current MessagePortDispatcher instance
  • addEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • hasEventListener(eventType:String):Boolean - method copied from receiver EventDispatcher for easier access
  • removeEventListener(eventType:String, listener:Function):void - method copied from receiver EventDispatcher for easier access
  • removeAllEventListeners(eventType:String):void - method copied from receiver EventDispatcher for easier access
  • dispatchEvent(event:Object):void - does not fire event, it sends event to postMessage(). Can be used with two arguments:
    • dispatchEvent(eventType:String, data?:Object):void

MessagePortTarget

A class that is used as a surrogate target for MessagePortDispatcher, it is useful when you have two objects for sending and receiving messages. For example, when you have an iframe with content from another origin and you can set iframe.contentWindow as sender object and own window as receiver. Sender object must contain postMessage() method and receiver object -- addEventListener() and removeEventListener() methods. Pass both sender and receiver into MessagePortTarget constructor, then it's instance can be provided for MessagePortDispatcher.

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget(iframeNode.contentWindow, window));

It also accepts lists of senders and receivers for mass sending and receiving.

const frameDispatcher = new MessagePortDispatcher(new MessagePortTarget([
  iframe1.contentWindow,
  iframe2.contentWindow,
  iframe3.contentWindow
  ], window));