demo · v139
SharedWorker CSP Lab
Before Chrome 139, both Worker and SharedWorker could throw synchronously when blocked by CSP — making async error recovery impossible. v139 brings SharedWorker into spec compliance: the constructor never throws; the error event always fires instead.
Feature detection: checking…
SharedWorker blocked by CSP
Construct a SharedWorker from a data: URI — blocked by default CSP. Which path fires?
—
Click to run the test.
Allowed SharedWorker
Construct a SharedWorker from a Blob URL — same-origin, allowed by CSP. Verifies the happy path is untouched.
—
Click to run the test.
SharedWorker is shared across tabs. If the worker fails silently and the site relies on the shared channel for cross-tab communication, every tab loses that channel. Async error recovery via
onerror matters more here than with dedicated workers.
code comparison
// v138 — synchronous throw, may lose the error in async contexts:
try {
const sw = new SharedWorker(blockedUrl);
sw.port.start();
} catch (e) {
// SecurityError — only works synchronously
showFallback();
}
// v139+ — spec-compliant, always async:
const sw = new SharedWorker(blockedUrl);
sw.onerror = (e) => {
// always fires on block or load failure
showFallback();
};
sw.port.start();
// Universal guard — handles both v138 and v139:
let sw;
try {
sw = new SharedWorker(url);
} catch (e) {
showFallback(); return;
}
sw.onerror = () => showFallback();
sw.port.start();
Migration guide
- v138
new SharedWorker(url)may throwSecurityErrorsynchronously when blocked by CSP - v139 Constructor always succeeds; CSP block fires
sw.onerrorasynchronously - Add
sw.onerrorhandler immediately after construction — beforeport.start() - Keep a
try/catcharound the constructor for browsers not yet on v139 — the universal guard handles both - After migration, the fallback in
onerrormust set up messaging via an alternative channel (BroadcastChannel, service worker, etc.) - SharedWorker name collisions are a separate failure mode — always handle
onerroreven for allowed scripts