Getting started
A site with peer-cdn has three parts:
- The service worker gets your pages’ requests for assets and routes them through middleware: this browser’s cache, then the other visitors, then your server.
- Each page runs PeerPlugin, which connects to the other visitors’ pages over WebRTC. Service workers can’t use WebRTC, so the worker asks its page to find files among the visitors, and the page shares what the worker cached.
- A signaling server introduces the pages to each other. After that, files go straight from one browser to another.
Install
Section titled “Install”npm install peer-cdn socket.io-clientpeer-cdn is an ES module with types, and installs peer-data, which holds
the pages’ connections. It passes on peer-data’s SocketChannel, so pages import everything from peer-cdn. The
signaling server needs socket.io on Node.js: npm install socket.io where it runs.
The service worker
Section titled “The service worker”This worker answers requests for everything under assets/ next to it, from the cache, the visitors, then the
server:
import { CachePlugin, DelegatePlugin, NetworkPlugin, PeerCDN, ordered } from 'peer-cdn';
// The folder this worker is served from, which is its scope: the site's pages and assets are below it.const base = new URL('./', location.href).pathname;
const cache = new CachePlugin();const peers = new DelegatePlugin();const network = new NetworkPlugin();
// Pictures come from this browser's cache, then from other visitors, then from the server. What the peers or// the server send is cached on the way, for this visitor and for the peers it shares with.new PeerCDN().GET(`${base}assets`, ordered, cache.getMiddleware, peers.getMiddleware, network.getMiddleware).register();ordered asks each middleware in turn. The ones asked before the one that answered get a copy of the response,
so what came from the visitors or the server is cached, and this visitor shares it in turn.
Routes and strategies covers the rest.
Browsers run a service worker from one script, so bundle the worker before serving it. With Vite, the
Vite plugin does that for vite and vite build:
import { defineConfig } from 'vite';import { peerCDN } from 'peer-cdn/vite';
export default defineConfig({ plugins: [peerCDN({ worker: 'src/sw.ts' })],});With another bundler, build the worker on its own into one classic script, such as an IIFE, and serve it from the top folder of what it should control: a service worker only controls pages at or below its own path.
The page
Section titled “The page”import { io } from 'socket.io-client';import { PeerPlugin, SocketChannel } from 'peer-cdn';
new PeerPlugin({ signaling: new SocketChannel(io('https://signaling.example.com')) });await navigator.serviceWorker.register('/sw.js');PeerPlugin answers the worker by itself. Create it on every page the worker controls, before the page loads the files you route, so it can answer the first requests. Only the worker classes end up in the worker’s bundle: PeerPlugin and peer-data stay in the page’s.
The signaling server
Section titled “The signaling server”import { createServer } from 'node:http';import { attachSignaling } from 'peer-cdn/server';
const server = createServer();attachSignaling(server, { cors: { origin: 'https://www.example.com' } });server.listen(8080);While you develop with Vite, the plugin runs it on Vite’s own server, and pages reach it with io().
Signaling covers ICE servers and signaling of your own.
Run the example
Section titled “Run the example”-
Clone the repository and serve the example site:
Terminal window git clone https://github.com/vardius/peer-cdn.gitcd peer-cdnnpm cinpm run examples -
Open http://localhost:5173 in one browser. It loads six pictures from the server, and its worker caches them.
-
Open the same address in another browser, such as a private window. It finds the first browser and gets the pictures from it: the page shows how many pictures the server has sent, which stays at six. To try another device on your network, serve the example with
npm run examples -- --host.
Or try it right here, in the live demo.