Skip to content

Commit

Permalink
fix: service worker communicates with the latest client only (#573)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladetsky authored Mar 24, 2024
1 parent d72574b commit 81b2f0d
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 6 deletions.
3 changes: 2 additions & 1 deletion src/lib/main/snippet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export function snippet(

function loadSandbox(isAtomics?: number) {
sandbox = doc.createElement(isAtomics ? 'script' : 'iframe');
win._pttab = Date.now();
if (!isAtomics) {
sandbox.style.display = 'block';
sandbox.style.width = '0';
Expand All @@ -90,7 +91,7 @@ export function snippet(
sandbox.src =
libPath +
'partytown-' +
(isAtomics ? 'atomics.js?v=_VERSION_' : 'sandbox-sw.html?' + Date.now());
(isAtomics ? 'atomics.js?v=_VERSION_' : 'sandbox-sw.html?' + win._pttab);

doc.querySelector(config!.sandboxParent || 'body')!.appendChild(sandbox);
}
Expand Down
1 change: 1 addition & 0 deletions src/lib/sandbox/read-main-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export const readMainPlatform = () => {
$interfaces$: readImplementations(impls, initialInterfaces),
$libPath$: new URL(libPath, mainWindow.location as any) + '',
$origin$: origin,
$tabId$: mainWindow._pttab,
};

addGlobalConstructorUsingPrototype(
Expand Down
18 changes: 14 additions & 4 deletions src/lib/service-worker/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,24 @@ export const receiveMessageFromSandboxToServiceWorker = (ev: ExtendableMessageEv
}
};

const sendMessageToSandboxFromServiceWorker = (accessReq: MainAccessRequest) =>
new Promise<MainAccessResponse>(async (resolve) => {
const clients = await (self as any as ServiceWorkerGlobalScope).clients.matchAll();
const client = [...clients].sort((a, b) => {
const getClientByTab = (clients: Client[], msgId: string) => {
const tabId = msgId.split('.').pop();
let client = clients.find((a) => a.url.endsWith(`?${tabId}`));
if (!client) {
client = [...clients].sort((a, b) => {
if (a.url > b.url) return -1;
if (a.url < b.url) return 1;
return 0;
})[0];
}

return client;
}

const sendMessageToSandboxFromServiceWorker = (accessReq: MainAccessRequest) =>
new Promise<MainAccessResponse>(async (resolve) => {
const clients = await (self as any as ServiceWorkerGlobalScope).clients.matchAll();
const client = getClientByTab([...clients], accessReq.$msgId$);

if (client) {
const timeout = debug ? 120000 : 10000;
Expand Down
3 changes: 3 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ export interface InitWebWorkerData {
$libPath$: string;
$sharedDataBuffer$?: SharedArrayBuffer;
$origin$: string;
$tabId$?: number;
}

/**
Expand Down Expand Up @@ -166,6 +167,7 @@ export interface WebWorkerContext {
$postMessage$: (msg: MessageFromWorkerToSandbox, arr?: any[]) => void;
$sharedDataBuffer$?: SharedArrayBuffer;
lastLog?: string;
$tabId$?: number;
}

export interface InitializeEnvironmentData {
Expand Down Expand Up @@ -622,6 +624,7 @@ export type StringIndexable = {
export interface MainWindow extends Window, StringIndexable {
partytown?: PartytownConfig;
_ptf?: any[];
_pttab?: number;
}

export const enum NodeName {
Expand Down
1 change: 1 addition & 0 deletions src/lib/web-worker/init-web-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const initWebWorker = (initWebWorkerData: InitWebWorkerData) => {
webWorkerCtx.$origin$ = locOrigin;
webWorkerCtx.$postMessage$ = (postMessage as any).bind(self);
webWorkerCtx.$sharedDataBuffer$ = initWebWorkerData.$sharedDataBuffer$;
webWorkerCtx.$tabId$ = initWebWorkerData.$tabId$;

(self as any).importScripts = undefined;
delete (self as any).postMessage;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/web-worker/worker-proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export const sendToMain = (isBlocking?: boolean) => {

const endTask = taskQueue[len(taskQueue) - 1];
const accessReq: MainAccessRequest = {
$msgId$: randomId(),
$msgId$: `${randomId()}.${webWorkerCtx.$tabId$}`,
$tasks$: [...taskQueue],
};
taskQueue.length = 0;
Expand Down
1 change: 1 addition & 0 deletions tests/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ <h2>Platform Tests</h2>
<li><a href="/tests/platform/iframe/">IFrame</a></li>
<li><a href="/tests/platform/image/">Image</a></li>
<li><a href="/tests/platform/intersection-observer/">IntersectionObserver</a></li>
<li><a href="/tests/platform/multiple-tabs/">Multiple Tabs</a></li>
<li><a href="/tests/platform/mutation-observer/">MutationObserver</a></li>
<li><a href="/tests/platform/navigator/">Navigator</a></li>
<li><a href="/tests/platform/node/">Node</a></li>
Expand Down
80 changes: 80 additions & 0 deletions tests/platform/multiple-tabs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Partytown Test Page" />
<title>Form</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif,
Apple Color Emoji, Segoe UI Emoji;
font-size: 12px;
}
h1 {
margin: 0 0 15px 0;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
a {
display: block;
padding: 16px 8px;
}
a:link,
a:visited {
text-decoration: none;
color: blue;
}
a:hover {
background-color: #eee;
}
li {
display: flex;
margin: 15px 0;
}
li strong,
li code,
li button {
white-space: nowrap;
flex: 1;
margin: 0 5px;
}
</style>
<script>
partytown = {
logCalls: true,
logGetters: true,
logSetters: true,
logStackTraces: false,
logScriptExecution: true,
};
</script>
<script src="/~partytown/debug/partytown.js"></script>
</head>
<body>
<h1>Multiple Tabs</h1>
<p>
<span>Opened Tabs:</span>
<span id="testNewTabs">0</span>
</p>
<a href="#" target="_blank" id="openNewTab">Open New Tab</a>
<script type="text/partytown">
let tabsNumber = 0;
document.getElementById('openNewTab').addEventListener('click', () => {
tabsNumber++;
document.getElementById('testNewTabs').textContent = tabsNumber;
});
</script>

<script type="text/partytown">
(function () {
document.body.classList.add('completed');
})();
</script>
<hr />
<p><a href="/tests/">All Tests</a></p>
</body>
</html>
23 changes: 23 additions & 0 deletions tests/platform/multiple-tabs/multiple-tabs.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { test, expect } from '@playwright/test';

test('multiple tabs', async ({ page, context }) => {
await page.goto('/tests/platform/multiple-tabs/');

await page.waitForSelector('.completed');

const testNewTabs = page.locator('#testNewTabs');
await expect(testNewTabs).toHaveText('0');

const linkNewTab = page.locator('#openNewTab');
const newPagePromise = context.waitForEvent('page');
await linkNewTab.click();
const newPage = await newPagePromise;
await newPage.waitForSelector('.completed');
await expect(testNewTabs).toHaveText('1');

const newPagePromise2 = context.waitForEvent('page');
await linkNewTab.click();
const newPage2 = await newPagePromise2;
await newPage2.waitForSelector('.completed');
await expect(testNewTabs).toHaveText('2');
});

0 comments on commit 81b2f0d

Please sign in to comment.