cross_tab 0.1.0 copy "cross_tab: ^0.1.0" to clipboard
cross_tab: ^0.1.0 copied to clipboard

Coordinate the browser tabs of a Flutter Web app: send typed messages between them, know how many are open, and elect exactly one to do the work.

cross_tab #

Coordinate the browser tabs of a Flutter Web app.

final tabs = CrossTab.open('my-app');

tabs.presence.listen((p) {
  if (p.isLeader) startPolling() else stopPolling();
});

tabs.messages.listen((m) => print('${m.from} said ${m.data}'));
tabs.send({'signedOut': true});

The problem #

Open your app in two tabs and things start going wrong quietly. Both poll the server. Both hold a socket. Both raise the same notification. The user signs out in one and the other carries on as though nothing happened.

The browser gives you BroadcastChannel and stops there. What is missing is everything around it.

what you need what the platform gives you
messages with a sender untyped structured clones, no identity
how many tabs are open nothing — you maintain it by heartbeat
exactly one tab doing the work nothing at all

A leader #

This is the part worth the package. Exactly one tab should poll, hold the socket, or raise the notification — and when that tab closes, another must pick it up without being told.

tabs.presence.listen((p) {
  if (p.isLeader) {
    socket.connect();
  } else {
    socket.disconnect();
  }
});

The oldest tab leads, with the id as a tiebreak. That second part matters more than it looks: two tabs opened in the same microsecond would otherwise each conclude the other should lead, or both lead. Comparing ids makes the ordering total, so every tab reaches the same answer without further negotiation.

A tab that closes says goodbye, so the others react at once rather than waiting out a timeout. A tab that crashes says nothing, so it is dropped after three missed heartbeats.

Presence #

final p = tabs.current;
p.count;     // how many tabs are open
p.tabs;      // their ids, including this one
p.leader;    // whose turn it is, or null while an election settles
p.isLeader;  // whether that is you

presence emits the current state on subscription, so a listener knows where it stands immediately rather than after the next change.

Messages #

tabs.send({'cart': items.length});
tabs.messages.listen((m) => print('from ${m.from}: ${m.data}'));

A tab never receives its own messages — the sender already knows what it sent.

Off the web #

The package compiles everywhere. On mobile and desktop there is exactly one instance of your app, so it reports one tab and is always the leader.

That is the correct answer rather than a degraded one, and it is deliberate: it means the code above runs unchanged on every platform, with no if (kIsWeb) wrapped around your leader logic.

Verified #

Two BroadcastChannel objects with the same name see each other even within one document, so the multi-tab behaviour is exercised for real rather than mocked. flutter test --platform chrome covers four tabs agreeing on a single leader, the oldest tab winning, leadership passing when the leader closes, tabs discovering and losing each other, and a tab not hearing its own messages. The single-instance path is tested on the VM.

License #

MIT © K M Shahriar Hossain

0
likes
0
points
--
downloads

Documentation

Documentation

Publisher

verified publisherjumyn.com

Weekly Downloads

Coordinate the browser tabs of a Flutter Web app: send typed messages between them, know how many are open, and elect exactly one to do the work.

Repository (GitHub)
View/report issues

Topics

#web #broadcastchannel #tabs #leader-election #browser

License

unknown (license)

Dependencies

flutter, web

More

Packages that depend on cross_tab