Skip to content

Commit

Permalink
Web Worker Example App (#1901)
Browse files Browse the repository at this point in the history
Co-authored-by: Benedict Wilson <[email protected]>
Co-authored-by: Gareth Thackeray <[email protected]>
Co-authored-by: Milo Clack <[email protected]>
Co-authored-by: Tom Longridge <[email protected]>
  • Loading branch information
4 people authored Feb 10, 2023
1 parent c754bda commit 218ec45
Show file tree
Hide file tree
Showing 12 changed files with 294 additions and 0 deletions.
1 change: 1 addition & 0 deletions examples/js/web-worker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
1 change: 1 addition & 0 deletions examples/js/web-worker/.node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
14
33 changes: 33 additions & 0 deletions examples/js/web-worker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Web-Worker

This is an example project showing how to use `@bugsnag/web-worker` with a web worker or service worker.

BugSnag can be configured to run in different ways inside a worker depending on whether it's a web or service worker and also its relationship with the “host” web app that spawns it. For full details on this, please see our [online docs](https://docs.bugsnag.com/platforms/javascript/web-workers/#reporting-unhandled-errors).

The project contains a single page which spawns 2 web workers and 1 service worker. Each worker has its own instance of `@bugsnag/web-worker`, and the web page itself is using an instance of `@bugsnag/js`.

The BugSnag instance created by [`worker-propagation.js`](worker-propagation.js) has both `autoDetectErrors` and `autoTrackSessions` set to `false`, leaving the web app responsible for reporting. In [`worker-no-propagation.js`](worker-no-propagation.js) BugSnag has `autoDetectErrors` and `autoTrackSessions` set to `true`, while utilizing `preventDefault` in the [parent script](worker-registration.js) to stop any error propagation. This ensures that this worker will only be reported by itself.

Unhandled errors in service workers will never propagate to the web app, so BugSnag [`service-worker.js`](service-worker.js) is also set up to detect errors.

## Usage

Clone the repo and `cd` into the directory of this example:

```
git clone [email protected]:bugsnag/bugsnag-js.git --recursive
cd bugsnag-js/examples/js/web-worker
```

Firstly, replace `YOUR_API_KEY` with your own in [`index.html`](index.html), [`worker-propagation.js`](worker-propagation.js), [`worker-no-propagation.js`](worker-no-propagation.js) and [`service-worker.js`](service-worker.js).

### Running the Example

Ensure you have a version of Node.js >=14 on your machine.

```
npm install
npm start
```

Once started, it will serve the app at http://localhost:8066 with handled and unhandled error buttons for each worker.
Binary file added examples/js/web-worker/bugsnag.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions examples/js/web-worker/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
body {
font-family: monospace;
max-width: 600px;
margin: 50px auto;
padding: 0 20px;
}

section {
display: flex;
justify-content: center;
text-align: center;
}

a {
margin: 0 2rem 0 2rem;
font-size: 16px;
-moz-appearance: none;
-webkit-appearance: none;
background-color: rgba(73, 73, 228, 1);
color: #FFF;
padding: .5rem;
border: none;
border-radius: 2px;
cursor: pointer;
}

img {
display: block;
margin: auto;
}

div {
display: flex;
flex-direction: column;
align-items: center;
margin: 3rem 3rem 0 3rem;
padding: 3rem;
border-style: solid;
border-color: #000;
}

form {
display: inline-block;
}

button, input[type=submit] {
display: inline-block;
font-size: 16px;
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
background-color: rgba(73, 73, 228, 1);
color: #FFF;
border: none;
border-radius: 2px;
margin: .5rem .125rem .5rem 0;
padding: .5rem 1rem;
cursor: pointer;
}

button:hover {
background-color: rgba(73, 73, 228, .8);
}

button:active {
background-color: rgb(73, 73, 228, 1);
}
45 changes: 45 additions & 0 deletions examples/js/web-worker/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>@bugsnag/web-worker: Web Worker example</title>
<link rel="stylesheet" type="text/css" href="/index.css" />
<script src="//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.min.js"></script>
<script>Bugsnag.start('YOUR_API_KEY')</script>
</head>
<body>
<img width="100" src="/bugsnag.png"/>
<h1>Web and service worker example</h1>
<p>This an example of how to include <code>@bugsnag/web-worker</code> in a web worker and a service worker.</p>
<h3>
This app has 2 web workers and 1 service worker. 1 web worker leaves unhandled errors to propagate to the browser context
and be reported here, while the other has propagation disabled and reports its own unhandled errors.
</h3>
<p>
You can unregister the current service worker by pressing the 'Unregister' button.
Simply refresh the page to instantiate the new service worker.
</p>
<section>
<div>
<h2>Web Worker with Propagation</h2>
<button id="handledErrorWebWrkrProp">Throw handled error</button>
<button id="unhandledErrorWebWrkrProp">Throw unhandled error</button>
</div>
<div>
<h2>Web Worker without Propagation</h2>
<button id="handledErrorWebWrkrNoProp">Throw handled error</button>
<button id="unhandledErrorWebWrkrNoProp">Throw unhandled error</button>
</div>
<div>
<h2>Service Worker</h2>
<button id="handledErrorServWrkr">Throw handled error</button>
<button id="unhandledErrorServWrkr">Throw unhandled error</button>
<button id="unregister">Unregister</button>
</div>
</section>

<script src="service-worker-registration.js"></script>
<script src="worker-registration.js"></script>

</body>
</html>
10 changes: 10 additions & 0 deletions examples/js/web-worker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "web-worker",
"version": "1.0.0",
"scripts": {
"start": "serve . -p 8066 -n"
},
"devDependencies": {
"serve": "^14.1.2"
}
}
41 changes: 41 additions & 0 deletions examples/js/web-worker/service-worker-registration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const handledErrorServWrkr = document.querySelector('#handledErrorServWrkr')
const unhandledErrorServWrkr = document.querySelector('#unhandledErrorServWrkr')
const unregisterBtn = document.querySelector('#unregister')

const registerWorker = () => {
if (!('serviceWorker' in navigator)) {
console.log('Service Worker not supported')
} else {
navigator.serviceWorker.register('service-worker.js')
.then((registration) => {
console.log('Service Worker registered. Scope is:', registration.scope)

handledErrorServWrkr.addEventListener('click', () => {
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage('Handled error in service-worker.js')
})
})
unhandledErrorServWrkr.addEventListener('click', () => {
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage('Unhandled error in service-worker.js')
})
})
unregisterBtn.addEventListener('click', () => {
unregisterWorker()
})
})
}
}

const unregisterWorker = () => {
if('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations()
.then((registrations) => {
for(let registration of registrations) {
registration.unregister()
}
})
}
}

registerWorker()
21 changes: 21 additions & 0 deletions examples/js/web-worker/service-worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
importScripts('//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.web-worker.min.js')

Bugsnag.start({
apiKey: 'YOUR_API_KEY',
autoDetectErrors: true,
autoTrackSessions: false
})

self.addEventListener('message', (message) => {
if (message.data === 'Handled error in service-worker.js') {
Bugsnag.leaveBreadcrumb('Handled error breadcrumb from service-worker.js')
console.log(message)
Bugsnag.notify(new Error(message.data))
}

else if (message.data === 'Unhandled error in service-worker.js') {
Bugsnag.leaveBreadcrumb('Unhandled error breadcrumb from service-worker.js')
console.log(message)
throw new Error(message.data)
}
})
21 changes: 21 additions & 0 deletions examples/js/web-worker/worker-no-propagation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
importScripts('//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.web-worker.min.js')

Bugsnag.start({
apiKey: 'YOUR_API_KEY',
autoDetectErrors: true,
autoTrackSessions: true
})

self.onmessage = (message) => {
if(message.data === 'Handled error in worker-no-propagation.js') {
Bugsnag.leaveBreadcrumb('Handled error breadcrumb from worker-no-propagation.js')
console.log(message)
Bugsnag.notify(new Error(message.data))
}

else if (message.data === 'Unhandled error in worker-no-propagation.js') {
Bugsnag.leaveBreadcrumb('Unhandled error breadcrumb from worker-no-propagation.js')
console.log(message)
throw new Error(message.data)
}
}
21 changes: 21 additions & 0 deletions examples/js/web-worker/worker-propagation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
importScripts('//d2wy8f7a9ursnm.cloudfront.net/v7/bugsnag.web-worker.min.js')

Bugsnag.start({
apiKey: 'YOUR_API_KEY',
autoDetectErrors: false,
autoTrackSessions: false
})

self.onmessage = (message) => {
if(message.data === 'Handled error in worker-propagation.js') {
Bugsnag.leaveBreadcrumb('Handled error breadcrumb from worker-propagation.js')
console.log(message)
Bugsnag.notify(new Error(message.data))
}

else if (message.data === 'Unhandled error in worker-propagation.js') {
Bugsnag.leaveBreadcrumb('Unhandled error breadcrumb from worker-propagation.js')
console.log(message)
throw new Error(message.data)
}
}
33 changes: 33 additions & 0 deletions examples/js/web-worker/worker-registration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const workerPropagation = new Worker('worker-propagation.js')
const workerNoPropagation = new Worker('worker-no-propagation.js')

// Within a web worker, unhandled errors will also bubble up to
// the script that initialized the worker. Since we are also
// using BugSnag in the parent script (see `index.html`),
// we are stopping the propagation of unhandled errors
// from `worker-no-propagation.js`, because this worker is
// currently responsible for reporting its own unhandled errors:

workerNoPropagation.onerror = (e) => {
e.preventDefault()
}

const handledErrorWebWrkrProp = document.querySelector('#handledErrorWebWrkrProp')
const unhandledErrorWebWrkrProp = document.querySelector('#unhandledErrorWebWrkrProp')

const handledErrorWebWrkrNoProp = document.querySelector('#handledErrorWebWrkrNoProp')
const unhandledErrorWebWrkrNoProp = document.querySelector('#unhandledErrorWebWrkrNoProp')

handledErrorWebWrkrProp.addEventListener('click', () => {
workerPropagation.postMessage('Handled error in worker-propagation.js')
})
unhandledErrorWebWrkrProp.addEventListener('click', () => {
workerPropagation.postMessage('Unhandled error in worker-propagation.js')
})

handledErrorWebWrkrNoProp.addEventListener('click', () => {
workerNoPropagation.postMessage('Handled error in worker-no-propagation.js')
})
unhandledErrorWebWrkrNoProp.addEventListener('click', () => {
workerNoPropagation.postMessage('Unhandled error in worker-no-propagation.js')
})

0 comments on commit 218ec45

Please sign in to comment.