Tabsub: Creating a Simple Messaging Library
Tags: html, javascript, tutorial, opensource
Published: 2019-04-04 14:11:01

---
title: Tabsub: Creating a Simple Messaging Library
published: true
cover_image: https://thepracticaldev.s3.amazonaws.com/i/olmzzk9ixjrwmfekb11l.jpg
description: Creating a simple publish-subscribe bus using the Broadcast Channel API and localStorage.
tags: html5, javascript, tutorial, opensource
---
There are lots of cases where developers want to post or listen to messages within an application. Posting messages across different browser contexts can vastly improve performance and user experience. Displaying queues with messages and pop notifications, synchronizing stale web views or even simultaneously logging out users from all active windows are different use cases for this method.

## Demo

{% twitter 1113758606976061440 %}

## The Broadcast Channel API

The [Broadcast Channel API](https://html.spec.whatwg.org/multipage/web-messaging.html#broadcasting-to-other-browsing-contexts) was introduced as a native bus messaging interface for [modern browsers](https://caniuse.com/#feat=broadcastchannel).
It allows communication between different documents (in different windows, tabs, service workers, web workers, frames or iframes) of the same origin. Messages are broadcasted via a `message` event fired at all BroadcastChannel objects listening to the channel.

Using the BroadcastChannel API is as simple as creating a publisher and a subscriber listening to the same channel.

```javascript
// subscriber
const channel = new BroadcastChannel('radio-channel');
channel.onmessage = ({
  data
}) => {
  const msg = JSON.stringify({
    data
  });
  console.log(msg);
};


// publisher
const channel = new BroadcastChannel('radio-channel');
channel.postMessage('this is a message');
channel.postMessage('This is a another one');
```
You can play around with this example in [JSFiddle](https://jsfiddle.net/b9wspcmy/).

The BroadcastChannel API also exposes lots of information about the publisher, the source and the origin of the message, as everything is packed into the event that’s published.

## Using localStorage as an elegant fallback

Although the BroadcastChannel API is well supported, you can use the [localStorage API](https://html.spec.whatwg.org/multipage/webstorage.html#dom-localstorage) to provide better support for [older browsers](https://caniuse.com/#search=localstorage). When new items are added to the storage bucket, subscribers can be notified for updates.

A simple example using the localStorage looks like this:

```javascript
const channelName = 'radio-channel';

const post = msg => window.localStorage.setItem(
  channelName,
  JSON.stringify({
    date: new Date(),
    channelName,
    msg
  })
);

// Subscriber
window.addEventListener('storage', (data = {}) => {
  const {
    key = '__GIBBERISH__', newValue = '{}'
  } = data;
  if (key === channelName) {
    const value = JSON.parse(newValue);
    const {
      msg
    } = value;
    callback(`Message received: ${msg}`);
  }
});

// publisher
post('This is a message');
post({
  id: 1,
  foo: 'bar'
});
```

## Bringing everything together

The BroadcastChannel strategy for messaging can also be combined with the localStorage strategy, which can be used as a fallback. Checking if the BroadcastChannel is supported is as easy as:
```javascript
const isBroadcastSupported = window && window.BroadcastChannel;
```

## Introducing Tabsub

In order to reduce friction and create a solid solution to achieve internal communication, I have combined the examples above into tiny (~500 bytes) library called [tabsub](https://www.npmjs.com/package/tabsub).
The API is lean and minimal and the library can be used right away.

```javascript
import radio from 'tabsub';

const channel = radio('channel-name');

// Post to channel
channel.post('this is a message');

// Subscribe
channel.on(msg => {
  console.log(`Received: ${msg}`);
});

// Stop listening for a while
channel.stop();

// Resume listening for messages
channel.start();

// Close the channel
channel.close();
```

## Further resources

- [BroadcastChannel at MDN](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel)
- [BroadcastChannel at Google Developers](https://developers.google.com/web/updates/2016/09/broadcastchannel)
- [BroadcastChannel polyfill with support for Node.js](https://github.com/pubkey/broadcast-channel)
- [localStorage at MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)


You can also find this post on [vorillaz.com](https://vorillaz.com/tabsub)