I used https://blog.logrocket.com/web-workers-react-typescript/ to build some simple Web Workers in an application created with create-react-app. In it, I have code like this:
const workerSimplerExample: Worker = useMemo(
() => new Worker(new URL("../workers/simple-example.ts", import.meta.url), {type:"module"}),
[]
);
This generates a URL which works whether I'm in dev mode, or using the build
directory in Production mode. However, no matter what I do, Jest throws errors when I run create-react-app's basic npm test
or yarn test
, with the error being: SyntaxError: Cannot use 'import.meta' outside a module
Any solutions I've found, (of which there aren't many, and none are very confident,) involve changing Jest or Bable settings in ways create-react-app doesn't allow unless I eject.
Has anyone figured out how to have Web Workers in React without breaking Jest or ejecting create-react-app?
To fix this, I figured out that I can isolate the call to new URL()
and then replace the file which is loaded when Jest runs. Credit goes to this GitHub comment.
First, isolate new URL()
. My file is located at src/workers/simple-example-factory.ts
const getWorker = (): Worker => {
return new Worker(new URL('./simple-example', import.meta.url));
}
export default getWorker;
Then, create a test double at src/workers/simple-example-factory.fake.ts
and use a static file path.
const getWorker = (): Worker => {
return new Worker(new URL('./simple-example', ''));
}
export default getWorker;
Then, you can get an instance of the work in your JSX/TSX files like so:
import SimpleExampleFactory from "../workers/simple-example-factory";
...
const workerSimplerExample: Worker = SimpleExampleFactory();
At this point, the worker should still work in the browser. Now, to fix Jest, we have to tell it to load a different file. We can modify the Jest configuration through package.json
when using create-react-app (See documentation.)
package.json
{
...
"jest": {
"moduleNameMapper": {
"workers/(.*)-factory": "<rootDir>/src/workers/$1-factory.fake.ts"
}
},
...
}