• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..18-Dec-2021-

.github/H18-Dec-2021-9675

dist/H18-Dec-2021-

src/methods/H03-May-2022-

LICENSEH A D18-Dec-20211 KiB2217

READMEH A D18-Dec-20211 KiB3421

README.mdH A D18-Dec-20219.9 KiB254185

package.jsonH A D18-Dec-20215.9 KiB133132

README

1<!--
2    This is a different readme file which will be published to npm
3    @link https://stackoverflow.com/a/52683086
4
5    The problem was that google indexed the npm-site instead of the github site
6-->
7
8<p align="center">
9  <a href="https://github.com/pubkey/broadcast-channel">
10    <img src="./docs/files/icon.png" width="150px" />
11  </a>
12</p>
13
14<h1 align="center">BroadcastChannel</h1>
15<p align="center">
16  <strong>A BroadcastChannel that works in old browsers, new browsers, WebWorkers and NodeJs</strong>
17  <br/>
18  <span>+ LeaderElection over the channels</span>
19</p>
20
21<p align="center">
22    <a href="https://twitter.com/pubkeypubkey">
23        <img src="https://img.shields.io/twitter/follow/pubkeypubkey.svg?style=social&logo=twitter"
24            alt="follow on Twitter"></a>
25</p>
26
27![demo.gif](docs/files/demo.gif)
28
29* * *
30
31A BroadcastChannel that allows you to send data between different browser-tabs or nodejs-processes.
32And a LeaderElection over the channels.
33
34# [Read the full documentation on github](https://github.com/pubkey/broadcast-channel)

README.md

1
2<p align="center">
3  <a href="https://github.com/pubkey/broadcast-channel">
4    <img src="./docs/files/icon.png" width="150px" />
5  </a>
6</p>
7
8<h1 align="center">BroadcastChannel</h1>
9<p align="center">
10  <strong>A BroadcastChannel to send data between different browser-tabs or nodejs-processes</strong>
11  <br/>
12  <span>+ LeaderElection over the channels</span><br />
13</p>
14
15<p align="center">
16    <a href="https://twitter.com/pubkeypubkey">
17        <img src="https://img.shields.io/twitter/follow/pubkeypubkey.svg?style=social&logo=twitter"
18            alt="follow on Twitter"></a>
19</p>
20
21![demo.gif](docs/files/demo.gif)
22
23* * *
24
25A BroadcastChannel that allows you to send data between different browser-tabs or nodejs-processes.
26
27- It works completely **client-side** and **offline**.
28- Tested on **old browsers**, **new browsers**, **WebWorkers**, **Iframes** and **NodeJs**
29
30This behaves similar to the [BroadcastChannel-API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) which is currently only featured in [some browsers](https://caniuse.com/#feat=broadcastchannel).
31
32## Using the BroadcastChannel
33
34```bash
35npm install --save broadcast-channel
36```
37
38#### Create a channel in one tab/process and send a message.
39
40```js
41const { BroadcastChannel } = require('broadcast-channel');
42const channel = new BroadcastChannel('foobar');
43channel.postMessage('I am not alone');
44```
45
46#### Create a channel with the same name in another tab/process and recieve messages.
47
48```js
49const { BroadcastChannel } = require('broadcast-channel');
50const channel = new BroadcastChannel('foobar');
51channel.onmessage = msg => console.dir(msg);
52// > 'I am not alone'
53```
54
55
56#### Add and remove multiple eventlisteners
57
58```js
59const { BroadcastChannel } = require('broadcast-channel');
60const channel = new BroadcastChannel('foobar');
61
62const handler = msg => console.log(msg);
63channel.addEventListener('message', handler);
64
65// remove it
66channel.removeEventListener('message', handler);
67```
68
69#### Close the channel if you do not need it anymore.
70
71```js
72channel.close();
73```
74
75#### Set options when creating a channel (optional):
76
77```js
78const options = {
79    type: 'localstorage', // (optional) enforce a type, oneOf['native', 'idb', 'localstorage', 'node']
80    webWorkerSupport: true; // (optional) set this to false if you know that your channel will never be used in a WebWorker (increases performance)
81};
82const channel = new BroadcastChannel('foobar', options);
83```
84
85#### Create a typed channel in typescript:
86
87```typescript
88import { BroadcastChannel } from 'broadcast-channel';
89declare type Message = {
90  foo: string;
91};
92const channel: BroadcastChannel<Message> = new BroadcastChannel('foobar');
93channel.postMessage({
94  foo: 'bar'
95});
96```
97
98#### Enforce a options globally
99
100When you use this module in a test-suite, it is recommended to enforce the fast `simulate` method on all channels so your tests run faster. You can do this with `enforceOptions()`. If you set this, all channels have the enforced options, no mather what options are given in the constructor.
101
102```typescript
103import { enforceOptions } from 'broadcast-channel';
104
105// enforce this config for all channels
106enforceOptions({
107  type: 'simulate'
108});
109
110// reset the enforcement
111enforceOptions(null);
112```
113
114
115#### Clear tmp-folder:
116When used in NodeJs, the BroadcastChannel will communicate with other processes over filesystem based sockets.
117When you create a huge amount of channels, like you would do when running unit tests, you might get problems because there are too many folders in the tmp-directory. Calling `BroadcastChannel.clearNodeFolder()` will clear the tmp-folder and it is recommended to run this at the beginning of your test-suite.
118
119```typescript
120import { clearNodeFolder } from 'broadcast-channel';
121// jest
122beforeAll(async () => {
123  const hasRun = await clearNodeFolder();
124  console.log(hasRun); // > true on NodeJs, false on Browsers
125})
126```
127
128```typescript
129import { clearNodeFolder } from 'broadcast-channel';
130// mocha
131before(async () => {
132  const hasRun = await clearNodeFolder();
133  console.log(hasRun); // > true on NodeJs, false on Browsers
134})
135```
136
137#### Handling IndexedDB onclose events
138
139IndexedDB databases can close unexpectedly for various reasons. This could happen, for example, if the underlying storage is removed or if the user clears the database in the browser's history preferences. Most often we have seen this happen in Mobile Safari. By default, we let the connection close and stop polling for changes. If you would like to continue listening you should close BroadcastChannel and create a new one.
140
141Example of how you might do this:
142
143```typescript
144const { BroadcastChannel } = require('broadcast-channel');
145
146let channel;
147
148const createChannel = () => {
149  channel = new BroadcastChannel(CHANNEL_NAME, {
150    idb: {
151      onclose: () => {
152        // the onclose event is just the IndexedDB closing.
153        // you should also close the channel before creating
154        // a new one.
155        channel.close();
156        createChannel();
157      },
158    },
159  });
160
161  channel.onmessage = message => {
162    // handle message
163  };
164};
165```
166
167## Methods:
168
169Depending in which environment this is used, a proper method is automatically selected to ensure it always works.
170
171| Method           | Used in                                                         | Description                                                                                                                                             |
172| ---------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
173| **Native**       | [Modern Browsers](https://caniuse.com/broadcastchannel)         | If the browser supports the BroadcastChannel-API, this method will be used because it is the fastest                                                    |
174| **IndexedDB**    | [Browsers with WebWorkers](https://caniuse.com/#feat=indexeddb) | If there is no native BroadcastChannel support, the IndexedDB method is used because it supports messaging between browser-tabs, iframes and WebWorkers |
175| **LocalStorage** | [Older Browsers](https://caniuse.com/#feat=namevalue-storage)   | In older browsers that do not support IndexedDb, a localstorage-method is used                                                                          |
176| **Sockets**      | NodeJs                                                          | In NodeJs the communication is handled by sockets that send each other messages                                                                         |
177| **Simulate**      | none per default                                                          | This method simulates the behavior of the other methods but only runs in the current process without sharing data between processes. Use this method in your test-suite because it is much faster.                                                                  |
178
179
180
181## Using the LeaderElection
182
183This module also comes with a leader-election which can be used so elect a leader between different BroadcastChannels.
184For example if you have a stable connection from the frontend to your server, you can use the LeaderElection to save server-side performance by only connecting once, even if the user has opened your website in multiple tabs.
185
186In this example the leader is marked with the crown ♛:
187![leader-election.gif](docs/files/leader-election.gif)
188
189
190Create a channel and an elector.
191
192```js
193const {
194  BroadcastChannel,
195  createLeaderElection
196} = require('broadcast-channel');
197const channel = new BroadcastChannel('foobar');
198const elector = createLeaderElection(channel);
199```
200
201Wait until the elector becomes leader.
202
203```js
204const { createLeaderElection } = require('broadcast-channel');
205const elector = createLeaderElection(channel);
206elector.awaitLeadership().then(()=> {
207  console.log('this tab is now leader');
208})
209```
210
211If more than one tab is becoming leader adjust `LeaderElectionOptions` configuration.
212
213```js
214const { createLeaderElection } = require('broadcast-channel');
215const elector = createLeaderElection(channel, {
216  fallbackInterval: 2000, // optional configuration for how often will renegotiation for leader occur
217  responseTime: 1000, // optional configuration for how long will instances have to respond
218});
219elector.awaitLeadership().then(()=> {
220  console.log('this tab is now leader');
221})
222```
223
224Let the leader die. (automatically happens if the tab is closed or the process exits).
225
226```js
227const elector = createLeaderElection(channel);
228await elector.die();
229```
230
231
232
233## What this is
234
235This module is optimised for:
236
237- **low latency**: When you postMessage on one channel, it should take as low as possible time until other channels recieve the message.
238- **lossless**: When you send a message, it should be impossible that the message is lost before other channels recieved it
239- **low idle workload**: During the time when no messages are send, there should be a low processor footprint.
240
241## What this is not
242
243-   This is not a polyfill. Do not set this module to `window.BroadcastChannel`. This implementation behaves similiar to the [BroadcastChannel-Standard](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API) with these limitations:
244    - You can only send data that can be `JSON.stringify`-ed.
245    - While the offical API emits [onmessage-events](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel/onmessage), this module directly emitts the data which was posted
246-   This is not a replacement for a message queue. If you use this in NodeJs and want send more than 50 messages per second, you should use proper [IPC-Tooling](https://en.wikipedia.org/wiki/Message_queue)
247
248
249## Browser Support
250I have tested this in all browsers that I could find. For ie8 and ie9 you must transpile the code before you can use this. If you want to know if this works with your browser, [open the demo page](https://pubkey.github.io/broadcast-channel/e2e.html).
251
252## Thanks
253Thanks to [Hemanth.HM](https://github.com/hemanth) for the module name.
254