π» Prerequisites
In this demo, we are using (on 2023-02-06):
NextJS: 13.1.5
TypeScript template
Bundler: Turbopack or webpack
Let's create a simple web worker demo!
π» Create a simple web worker demo
Because we can use Worker on any browser, so we don't need to check if (typeof Worker !== 'undefined')
:
if (typeof Worker !== 'undefined') {
// Create a new Worker.
} else {
// Web workers are not supported in this environment.
}
We need new URL()
, the project can't detect the real path of ../workers/plus
when source code is built with bundler (e.g. webpack).
Import webworker script without new URL()
:
const plusWorker = new Worker('../workers/plus');
Import webworker script with new URL()
:
const plusWorker = new Worker(new URL('../workers/plus', import.meta.url));
I develop with the next dev --turbo
script. This is turbopack mode (A webpack alternative). But unfortunately, the following error occurred:
Refused to execute script from 'http://localhost:3000/_next/static/assets/d6f517fec7dcd080.ts' because its MIME type ('video/vnd.dlna.mpeg-tts') is not executable.
Then, I back to webpack
with the next dev
script, everything works fine! Maybe vercel turbo is a very new tool and there are still many issues with it at this time.
Here is the complete code. src/pages/index.tsx
file's content:
import Head from 'next/head';
import styles from '@/styles/Home.module.css';
import { useEffect } from 'react';
export default function Home() {
useEffect(() => {
const plusWorker = new Worker(new URL('../workers/plus', import.meta.url));
plusWorker.onmessage = (event) => {
console.log('π Message received from worker: ', event.data);
};
plusWorker.onerror = (event) => {
if (event instanceof Event) {
console.log('π Error message received from worker: ', event);
return event;
}
console.log('π Unexpected error: ', event);
throw event;
};
plusWorker.postMessage([1, 2]);
return () => {
plusWorker.terminate();
};
}, []);
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<div className={styles.description}>
<p>Get started by editing</p>
</div>
</main>
</>
);
}
src/workers/plus.ts
file's content:
import { TWorkerMess } from '@/models';
const onmessage = (event: MessageEvent<TWorkerMess>) => {
console.log('π Worker: Message received from main script');
const data = event.data;
const result = data[0] + data[1];
const workerResult = 'Result: ' + result;
console.log('π Worker: Posting message back to main script');
postMessage(workerResult);
};
addEventListener('message', onmessage);
src/models/worker.ts
file's content:
export type TWorkerMess = number[];
When run next dev
or pnpm dev
output on console log is below:
π Worker: Message received from main script
π Worker: Posting message back to main script
π Message received from worker: Result: 3
We did it!