comlink icon indicating copy to clipboard operation
comlink copied to clipboard

Using comlink with GoogleChromeLabs/worker-plugin

Open alshdavid opened this issue 4 years ago • 14 comments

Hi team, love your work. Having some trouble integrating google's worker plugin.

main.ts

void async function() {
  const worker = new Worker('./test.js', { type: 'module' })
  const TestStore = Comlink.wrap(worker)
  console.log(await new TestStore())
}()

test.js

import { expose } from 'comlink'

class Thing {
  constructor() {
    this.state = ''
  }

  setState(v) {
    this.state = v
  }
}

expose(Thing)

results in the error

Uncaught (in promise) TypeError: Cannot read property 'apply' of undefined
    at MessagePort.eval

I am using the latest Chrome

alshdavid avatar Aug 15 '19 14:08 alshdavid

I’m not sure that this is a bug with Comlink, but rather worker-plugin, but it’s hard to tell from this.

Can you put a test project in a gist or something?

Also cc @developit.

surma avatar Aug 16 '19 08:08 surma

This error is also there with worker-loader

ritz078 avatar Sep 08 '19 13:09 ritz078

Is this by chance happening in webpack's dev mode? (webpack-dev-server) That's the only thing I can think of that would add an eval() into the mix.

developit avatar Oct 04 '19 01:10 developit

@developit I'm using comlink + worker-plugin and when using webpack-dev-server (development mode in watch + http-server is fine) i'm getting an error (see below) for each worker that is created using worker-plugin.

image

UPDATE - The errors only occur when using webpack-dev-server in "inline" mode.

rssfrncsrenishaw avatar Oct 07 '19 10:10 rssfrncsrenishaw

It seems like what's happening here is that Comlink has a few Symbols and a Set that it creates as a side-effect of module instantiation. When the hot update comes in for the Worker, it gets a new copy of Comlink with new symbols and maps instances.

It's very possible the only solution here is to have worker-plugin destroy and recreate the Worker instance when it gets a hot update for the worker's entry module. The problem with this is that it means nothing within the worker is particularly "hot" - it just gets reloaded, like a page refresh. Also there'd be no way to swap the Worker instance that Comlink is pointing to from the main thread, so the module that instantiated the worker would need to be swapped, and so-on up the tree.

It might be possible to fix this on a case-by-case basis by using Webpack's module.hot.accept() API in Worker code. If the class exposed through Comlink can be monkey-patched in response to an update, that might work:

import { expose } from 'comlink'

class Thing {
  constructor() {
    this.state = ''
  }

  setState(v) {
    this.state = v
  }
}

// something like this (varies by usage)
module.hot.accept('.', r => {
  const p = r();
  Object.assign(Thing.prototype, p.Thing.prototype);
});

expose(Thing)

(note: the above might only work if Thing is exported from a child module, and the module's specifier is passed to module.hot.accept()).

developit avatar Oct 08 '19 01:10 developit

Would you expect this to be the case if the webpack-dev-server hot options are set to false?

image

I still get the error when explicitly setting to false. Only inline prevents the error.

rssfrncsrenishaw avatar Oct 08 '19 06:10 rssfrncsrenishaw

Is it possible to identify messages sent via comlink so that any non-comlink ones (like webpack-dev-server) can be ignored by the message handler?

Might it be possibly related to https://github.com/auth0/auth0.js/issues/406 ?

An option that works locally for me is to add a source property to ep.postMessage({ id, source: comlinkSourceToken, ...msg }, transfers) and then in the message listener check for the existence of data.source and that it equals comlinkSourceToken.

rssfrncsrenishaw avatar Oct 08 '19 07:10 rssfrncsrenishaw

能将解一下如何在React项目中使用它吗

2213397919 avatar Oct 12 '19 10:10 2213397919

Unhandled Rejection (DataCloneError): Failed to execute 'postMessage' on 'Window': function remoteFunction(_x) { return _remoteFunction.apply(this, arguments); } could not be cloned.

2213397919 avatar Oct 12 '19 10:10 2213397919

I am getting the same error using [email protected], Angular/[email protected]

MurhafSousli avatar Nov 22 '19 07:11 MurhafSousli

no window try config your webpack

export default {
    output: {
        globalObject: 'this'
    }
}

and disabled your hot loading, cos worker do not have window or document

AielloChan avatar Nov 24 '19 16:11 AielloChan

I also consistently get this error with create-react-app project and the module that tries to expose ANYTHING.

UPD: It was actually a hiccup in my code. somehow modifying a couple of lines magically solved the problem, so it seems that this error is really app-specific and has nothing to do with comlink functionality

sAbakumoff avatar Jun 10 '20 14:06 sAbakumoff

A suggestion to people who's having trouble: you should try comlink-loader, which combines worker-loader and comlink.

huy-nguyen avatar Jun 10 '20 22:06 huy-nguyen

For anyone stumbling upon this: I'm using Create React app with a custom override using the worker-loader as well.

A workaround is to actually change something in the worker file (not any component) to trigger a recompile I guess

LarsKoelpin avatar Dec 17 '20 10:12 LarsKoelpin

Closing this issue as I groom my old issues. Feel free to reopen if there is more activity

alshdavid avatar Feb 17 '23 23:02 alshdavid