DEV Community

Cover image for How to get access to DOM from Service Worker?
Jakub T. Jankiewicz
Jakub T. Jankiewicz

Posted on

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
Enter fullscreen mode Exit fullscreen mode

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 modules[name]();
    }
    return null;
  }
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

GitHub logo jcubic / mitty

A transport-agnostic proxy RPC for executing method chains from any isolated context (Workers, Tabs, or Servers) using lazy evaluation.

Mitty Logo

npm version github repo CI Coverage Status LICENSE MIT

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
Enter fullscreen mode Exit fullscreen mode

Universal Communication

While originally…

Top comments (0)