comlink
comlink copied to clipboard
Using comlink with GoogleChromeLabs/worker-plugin
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
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.
This error is also there with worker-loader
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 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.
UPDATE - The errors only occur when using webpack-dev-server in "inline" mode.
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()
).
Would you expect this to be the case if the webpack-dev-server hot options are set to false?
I still get the error when explicitly setting to false. Only inline prevents the error.
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
.
能将解一下如何在React项目中使用它吗
Unhandled Rejection (DataCloneError): Failed to execute 'postMessage' on 'Window': function remoteFunction(_x) { return _remoteFunction.apply(this, arguments); } could not be cloned.
I am getting the same error using [email protected], Angular/[email protected]
no window
try config your webpack
export default {
output: {
globalObject: 'this'
}
}
and disabled your hot loading, cos worker do not have window
or document
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
A suggestion to people who's having trouble: you should try comlink-loader
, which combines worker-loader
and comlink
.
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
Closing this issue as I groom my old issues. Feel free to reopen if there is more activity