Live demo
Everything below runs in your browser. On a real site, each visitor is a different browser and peer-cdn’s service worker does the loading. Here, two visitors share this page, each with a cache of its own, and load the pictures the way the worker would: from their cache, then from the other visitors, then from the server.
Your server has sent 0 pictures.
Visitor 1
Looking for other visitors…
Not loaded
Not loaded
Not loaded
Not loaded
Not loaded
Not loaded
Visitor 2
Looking for other visitors…
Not loaded
Not loaded
Not loaded
Not loaded
Not loaded
Not loaded
What to try
Section titled “What to try”- Load the pictures as Visitor 1. No one has them yet, so they come from the server, which this site is served from. Visitor 1 keeps them in its cache.
- Load them as Visitor 2. Visitor 1 has them, so they come from Visitor 1 over a WebRTC data channel, and the server’s count stays the same.
- Load them again as either visitor. They come from its own cache.
- Clear Visitor 1’s cache, then load. Visitor 2 sends them back.
Open this page in another tab of the same browser and its visitors join in too.
How it’s built
Section titled “How it’s built”Each visitor runs PeerPlugin, the part of peer-cdn that runs in pages, with a cache name of its own. They find
each other through peer-data’s BroadcastChannelSignaling, which reaches the pages of one browser with no
server. load stands in for the service worker with its CachePlugin, DelegatePlugin and NetworkPlugin:
import { PeerPlugin, type PeerPluginOptions } from 'peer-cdn';
/** Where a visitor got a file from. */export type Source = 'cache' | 'peers' | 'server';
export interface Loaded { response: Response; from: Source;}
/** * A visitor of a site, in one page: it loads files as peer-cdn's worker would, from its cache, then from the * other visitors, then from the server, keeping what it loads, and shares its cache with the other visitors. * The site's demo runs two in one page, each with a cache of its own, where a real site has one per browser. */export function visit(options: PeerPluginOptions & { cacheName: string }) { const { cacheName } = options; const plugin = new PeerPlugin(options);
return { /** Loads url, and says where it came from. */ load: async (url: string): Promise<Loaded> => { const cache = await caches.open(cacheName); const cached = await cache.match(url); if (cached) return { response: cached, from: 'cache' }; const fromPeers = await plugin.fetch(url); const response = fromPeers ?? (await fetch(url)); if (response.status === 200) await cache.put(url, response.clone()); return { response, from: fromPeers ? 'peers' : 'server' }; }, /** Empties this visitor's cache, as clearing site data would. */ forget: async (): Promise<void> => { await caches.delete(cacheName); }, leave: (): void => { plugin.close(); }, };}The pictures are the ones the example site serves. PeerPlugin shares them because they are
same-origin 200 responses not marked private or no-store: see what visitors share.
Where this works
Section titled “Where this works”The visitors signal over BroadcastChannel, which reaches pages of the same origin in one browser. To connect
different browsers or devices, pages need a signaling server: see Signaling.