Last active
July 4, 2020 21:21
-
-
Save samdenty/c4bf6241fc437962b463b82f1b6c64d7 to your computer and use it in GitHub Desktop.
comlink chrome extensions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Comlink from 'comlink'; | |
export const PORT_ID = '@@@PORT_ID'; | |
const ports = new Map<string, chrome.runtime.Port>(); | |
chrome.runtime.onConnect.addListener((port) => { | |
if (port.name.startsWith(PORT_ID)) { | |
ports.set(port.name, port); | |
} | |
}); | |
function deserialize(data: any): any { | |
if (Array.isArray(data)) { | |
data.forEach((value, i) => { | |
data[i] = deserialize(value); | |
}); | |
} else if (data && typeof data === 'object') { | |
const id = data[PORT_ID]; | |
if (id) { | |
const port = ports.get(id)!; | |
const { port1, port2 } = new MessageChannel(); | |
forward(port2, port); | |
return port1; | |
} | |
for (const key in data) { | |
data[key] = deserialize(data[key]); | |
} | |
} | |
return data; | |
} | |
export function extensionEndpoint(port: chrome.runtime.Port): Comlink.Endpoint { | |
const listeners = new WeakMap(); | |
return { | |
postMessage: (message, transfer: MessagePort[]) => { | |
for (const port of transfer) { | |
const id = PORT_ID + `${+new Date()}${Math.random()}`; | |
// @ts-ignore | |
port[PORT_ID] = id; | |
forward(port, chrome.runtime.connect({ name: id })); | |
} | |
port.postMessage(message); | |
}, | |
addEventListener: (_, handler) => { | |
const listener = (data: any) => { | |
const event = new MessageEvent('message', { data: deserialize(data) }); | |
if ('handleEvent' in handler) { | |
handler.handleEvent(event); | |
} else { | |
handler(event); | |
} | |
}; | |
port.onMessage.addListener(listener); | |
listeners.set(handler, listener); | |
}, | |
removeEventListener: (_, handler) => { | |
const listener = listeners.get(handler); | |
if (!listener) { | |
return; | |
} | |
port.onMessage.removeListener(listener); | |
listeners.delete(handler); | |
}, | |
}; | |
} | |
export function forward(from: MessagePort, to: chrome.runtime.Port) { | |
const port = extensionEndpoint(to); | |
from.onmessage = ({ data, ports }) => port.postMessage(data, ports as any); | |
port.addEventListener('message', ({ data, ports }: any) => { | |
from.postMessage(data, ports as any); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment