zgba Network

How to get access to DOM from Service Worker?

When working on Fake Linux Terminal and then Hacking Cafe, I’ve created an abstraction of a Linux process in the form of a web worker. Those executable scripts lived in Filesystem and needed an access to DOM (in my case jQuery, becasuse the used jQuery Terminal). In this article I will show how to give access to the DOM from a web worker (service workers will work exactly the same) using Mitty. Installation If you’re building an application, first you need to install Mitty npm install @jcubic/mitty Main Thread In the main thread, you expose the document or window object: import { Host } from ‘@jcubic/mitty’; // helper object to have all exposed objects in one place const modules = { document: () => document, window: () => window }; const channel = new BroadcastChannel(‘my-app’); const worker = new Worker(’./worker.js’, { type: ‘module’ }); const host = new Host({ // worker instance can also be used as a channel channel: channel, resolve(name) { // you can just return the object by name here if (Object.hasOwn(modules, name)) { return modulesname; } return null; } }); Web Worker Then in a web worker (or service worker): import { connect } from ‘https://cdn.jsdelivr.net/npm/@jcubic/mitty’; const { require } = connect(new BroadcastChannel(‘my-app’)); // or when using worker as a channel const { require } = connect(self); const document = require(‘document’); // methods need await const body = await document.querySelector(‘body’); await body.style.setProperty(‘color’, ‘red’); // setting properties are send right away body.style.backgroundColor = ‘#000’; console.log(await body.style.color); console.log(await body.style.backgroundColor); Universal Transport The Mitty library is not limited to web/service workers. You can use it to connect: Server with client (expose Node.js object in browser) Client with server (use the browser DOM inside Node.js), you can hide the logic on the server. Different tabs using Sysend or BroadcastChannel. Connect peers using WebRTC To create a channel, you need to implement this interface: interface Channel { postMessage(message: string): void; addEventListener(type: ‘message’, listener: ChannelListener): void; removeEventListener(type: ‘message’, listener: ChannelListener): void; } As you can see, the channel interface has the same methods as the web/service worker. That’s why both can be used as channels. Access Any Objects You’re not limited to DOM nodes. You can expose any objects that have methods. You can expose part of the backend code to be executed directly on the client. GitHub Project More information and examples on GitHub jcubic / mitty A transport-agnostic proxy RPC for executing method chains from any isolated context (Workers, Tabs, or Servers) using lazy evaluation. Mitty: A transport-agnostic proxy RPC for executing method chains from any isolated context (Workers, Tabs, or Servers). Use objects that only exist on the main thread — DOM nodes, jQuery objects, class instances with methods, or anything that is inaccessible from inside a Web/Service Worker. A worker has no DOM, and postMessage cannot carry a DOM node, a jQuery object, or anything else that isn’t structured-cloneable. Mitty leaves the real object on the main thread and puts a proxy in the worker. The proxy records property accesses and calls without touching the channel; the whole chain is replayed on the main thread when you await it. // inside a worker — no DOM here const $ = require(’$’); await $(‘#list’).find(‘li’).first().text(); // one message, not four Universal Communication While originally… View on GitHub

View original article