I recently needed to implement a shared worker in a project. Though they are super useful, there wasn't much info to be found in the usual places, so here are some pointers that might help searchers from the mysterious future.
SharedWorkers are a special class of WebWorker that can be shared across multiple tabs, windows or other (regular) web workers.
In my application, I needed a process which would poll for new application events (for example, a customer completing a purchase), and show a notification (using the Notifications API) to logged in administrators (or more specifically, those logged in administrators who had chosen to receive notifications).
An administrator could have the application open in several tabs or windows, so it would be wasteful to have each tab polling for new events. I only wanted one notification per event, regardless of the number of open tabs or windows.
SharedWorker to the rescue! Each of the open tabs or windows shares a single worker, which polls in the background, and shows just one notification per new event.
The first challenge was loading the shared worker in my Vite-based setup.
If you're running Vite in dev mode, Vite serves the script from a different domain and port (eg http://[::1]:5173/), which won't work, because shared workers must obey the same-origin policy.
I tried various Vite workarounds for web workers:
In the end, I created a new route to serve the script either from the resources directory in dev, or the build directory in staging and live environments.
Route::addRoute('GET', '/notifications-shared-worker.js', function () { // If in dev environment, send the file from the resources folder if (app()->environment('local')) { return response()->file(resource_path('js/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']); } else { // Otherwise, send the file from the public folder return response()->file(public_path('build/assets/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']); } });
I then create the shared worker with that route as the URL:
const worker = new SharedWorker('/notifications-shared-worker.js');
You'll quickly find that any syntax or runtime errors in your shared worker don't appear in your devtools. Nor do any console log/warn/info calls.
This one is easy, paste chrome://inspect/#workers into your URL bar, find the shared worker and click on 'inspect'. Now you have a devtools window just for the shared worker.
To communicate back to the ‘parent’ tab, use the port.postMessage method, as described in the MDN SharedWorker documentation.
However, the example code only allows communication with the most recent ‘parent’ tab/window because it overwrites the communication port reference each time a parent connects.
Instead, store an array of ports, and add each new port to the array when a new ‘parent’ connects.
Route::addRoute('GET', '/notifications-shared-worker.js', function () { // If in dev environment, send the file from the resources folder if (app()->environment('local')) { return response()->file(resource_path('js/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']); } else { // Otherwise, send the file from the public folder return response()->file(public_path('build/assets/notificationWatcherWorker.js'), ['Content-Type' => 'text/javascript']); } });
Then, send a message to all the parent pages like this:
const worker = new SharedWorker('/notifications-shared-worker.js');
The above is the detailed content of Some notes on SharedWorkers. For more information, please follow other related articles on the PHP Chinese website!