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

@r_wohl/web-channel-message

v3.0.2

Published

A light weight type-safe library for communicating via the Channel Message Web API

Downloads

3

Readme

Web Channel Message

A light-weight library that lets multiple browser sessions interact with each other, through one or more Shared Workers.


Note: Package name might change soon as -unlike initially intended- it does not directly use the Web Channel Message API. Instead, the package functions as an abstraction layer around the SharedWorker API


Example

const channel = new SharedWebChannel();

channel.registerCallback("logout", logoutUser);

function handleClick() {
    channel.sendMessage({
      type: "callback",
      action: "all",
      callbackKey: "logout",
    });
}

For a working example check out this demo of a NextJS application that uses this library to synchronize state between instances of the same application in different tabs/windows.

Install

NPM

npm i @r_wohl/web-channel-message

YARN

yarn add @r_wohl/web-channel-message

Usage

To use this library, first instantiate a new SharedWebChannel, which is a wrapper around the SharedWorker API:

import { SharedWebChannel } from "@r_wohl/web-channel-message";

...

const channel = new SharedWebChannel();

If you -for some reason- want to use more then one shared worker, you can instantiate SharedWebChannel with a name argument:

const anotherChannel = new SharedWebChannel('second-channel');

Tracking open connections


As of version 3.0.0 you can keep track of the number of open connections when the SharedWebChannel is instantiated, as well as register a callback that is called when this number changes:

const numberOfConnections = channel.connections;

...

channel.onConnectionsUpdate(myCustomHandler);

If a callback is registered to be executed when the number of open connections changes, it will receive the new number of connections as input.

NOTE: Updating channel.connections when a page/session is closed relies on beforeunload/unload/pagehide events, which do not fire in some browsers/circumstances. See caveats.

Sending messages


You can now send a message to all instances of your application with the sendMessage method:

  function handleClickColor(color: BackgroundColor) {
    channel.sendMessage({
      type: "callback",
      action: "all",
      payload: color,
      callbackKey: "set-bg-color",
    });
  }

For the type property, you can choose between callback mode and observer mode, which determines how the message is handled when it is received.

For the action property, you can choose between "all" and "broadcast". Messages with "all" will be sent to all open connections, including the instance from which it was sent. Messages with "broadcast" will be sent to all other connections.

The payload property is optional. In "callback" mode this will be the input for your registered callback function. The same is true for "observer" mode, but in this case you have more control over what happens with the data in this property (see observer section)

Furthermore, in "callback" mode you'll need to specify a callbackKey. In "observer" mode you can specify a key as well, if you want the message to be received by specific ChannelObservers only:

    channel.sendMessage({
      type: "observer",
      action: "broadcast",
      key: "my-custom-event"
    });

Handling messages


When messages are received in the SharedWebChannel you can either handle them with a registered callback, or with a ChannelObserver.

Callback


The easiest way to handle message is to register a callback function, together with a specific key:


channel.registerCallback("set-bg-color", setBgColor);

Whenever a message is received with that specific key in the callbackKey property, the registered callback function is executed with the value of the received payload property as input.

Observer


Handling incoming messages with ChannelObserver instances gives you more control over data flow between different instances of your application.

Start with importing the ChannelObserver:

import { ChannelObserver } from "@r_wohl/web-channel-message";

You can now make a ChannelObserver instance:

    const observer = new ChannelObserver(channel, (data) => {
      const payload = data.payload as SomeCustomType;

      doSomethingWithPayload(payload)
    });

Optionally, you can specify a key when instantiating the ChannelObserver:

    const observer = new ChannelObserver(channel, (data) => {
      const payload = data.payload as SomeCustomType;

      handlePayload(payload)
    }, "my-custom-key");

For any ChannelObserver with a key, it will only be updated when messages are received with either that specific key, or with the message key property set to "all".

Please note that for this reason, you shouldn't set the message key to either "all" or "default" for messages in "observer" mode (the "default" key is set for ChannelObserver instances where no key is specified).

Finally, you can unsubscribe a ChannelObserver from the SharedWebChannel subject when appropriate, for instance in React.useEffect's return:

  useEffect(() => {
    const observer = new ChannelObserver(channel, (data) => {
      const payload = data.payload as SomeCustomType;
      if (payload) {
        handlePayload(payload);
      }
    });

    return () => {
      channel.subject.unsubscribe(observer);
    };

  }, []);

Caveats

Shared Worker modules compatibility

Not every browser supports Shared Worker modules at the moment. If instantiating a Shared Worker fails in the SharedWebChannel constructor, the SharedWebChannel will detect this and fall back to executing callbacks and updating ChannelObserver instances for that application instance only.

Updating connection status

It is not possible to accurately keep track of the number of active application sessions in all circumstances and on all browsers in a straightforward manner. In almost all environments closing a tab/navigating away/reloading the page will cause the connection count to be updated properly. However, on iOS -for example-, terminating a page with a close button does not cause a unique event to fire that can be identified to close that connection port inside the shared worker. So until I come up with a better solution, the connection count cannot be fully trusted in environments where closing/reloading pages can be done without firing beforeunload/unload/pagehide events.

Contributors

This is my first NPM library, and I'd would be delighted if anyone would like to comment on the code or contribute in any way. Whether it be a long list of my failures or compliments on the idea/implementation, your input is more than welcome!