I'm trying to implement web workers in NextJs, I've followed their example but It really bugs me that I cannot pass the worker relative URL as a variable to new URL(url, baseUrl)
.
The following snippet is where the worker gets called:
import { useEffect, useRef, useCallback } from 'react'
export default function Index() {
const workerRef = useRef()
useEffect(() => {
const workerUrl = '../worker.js';
console.log({
URL: new URL('../worker.js', import.meta.url),
meta: import.meta.url
});
console.log({
URL: new URL(workerUrl, import.meta.url),
meta: import.meta.url
});
workerRef.current = new Worker(new URL('../worker.js', import.meta.url))
workerRef.current.onmessage = (evt) =>
alert(`WebWorker Response => ${evt.data}`)
return () => {
workerRef.current.terminate()
}
}, [])
const handleWork = useCallback(async () => {
workerRef.current.postMessage(100000)
}, [])
return (
<div>
<p>Do work in a WebWorker!</p>
<button onClick={handleWork}>Calculate PI</button>
</div>
)
}
This strangely logs:
{
"URL":"/_next/static/media/worker.3c527896.js",
"meta":"file:///home/omar/CODE/NextJs/lullo/with-web-worker-app/pages/index.js"
}
{
"URL":"file:///home/omar/CODE/NextJs/lullo/with-web-worker-app/worker.js",
"meta":"file:///home/omar/CODE/NextJs/lullo/with-web-worker-app/pages/index.js"
}
How in the world is this any different:
const workerUrl = '../worker.js';
console.log({
URL: new URL('../worker.js', import.meta.url),
meta: import.meta.url
});
console.log({
URL: new URL(workerUrl, import.meta.url),
meta: import.meta.url
});
The problem is that I cannot pass the URL as a prop, to some generic worker caller. I get the annoying error:
SecurityError: Failed to construct 'Worker': Script at 'file:///home/omar/CODE/NextJs/lullo/client/src/utils/WebWorkers/postErrorToServer.ts' cannot be accessed from origin 'http://localhost:3000'.
CodePudding user response:
This is probably happening because in the first case:
const workerUrl = '../worker.js';
const url = new URL(workerUrl, import.meta.url);
webpack sees the URL as dynamic and is unable to properly bundle the web worker at compile-time. Something similar happens if you define the worker as follows:
const url = new URL('../worker.js', import.meta.url);
const worker = new Worker(url);
This comment on a discussion in webpack's GitHub repo might help in your case. I don't think the worker URL can be truly dynamic, due to the above reason - webpack needs to know the url of the worker script at compile-time.