From 218ec456cb24daf9170627ad07894af4389c4f04 Mon Sep 17 00:00:00 2001 From: Milo Clack Date: Fri, 10 Feb 2023 10:25:07 +0000 Subject: [PATCH] Web Worker Example App (#1901) Co-authored-by: Benedict Wilson Co-authored-by: Gareth Thackeray Co-authored-by: Milo Clack Co-authored-by: Tom Longridge --- examples/js/web-worker/.gitignore | 1 + examples/js/web-worker/.node-version | 1 + examples/js/web-worker/README.md | 33 +++++++++ examples/js/web-worker/bugsnag.png | Bin 0 -> 3284 bytes examples/js/web-worker/index.css | 67 ++++++++++++++++++ examples/js/web-worker/index.html | 45 ++++++++++++ examples/js/web-worker/package.json | 10 +++ .../web-worker/service-worker-registration.js | 41 +++++++++++ examples/js/web-worker/service-worker.js | 21 ++++++ .../js/web-worker/worker-no-propagation.js | 21 ++++++ examples/js/web-worker/worker-propagation.js | 21 ++++++ examples/js/web-worker/worker-registration.js | 33 +++++++++ 12 files changed, 294 insertions(+) create mode 100644 examples/js/web-worker/.gitignore create mode 100644 examples/js/web-worker/.node-version create mode 100644 examples/js/web-worker/README.md create mode 100644 examples/js/web-worker/bugsnag.png create mode 100644 examples/js/web-worker/index.css create mode 100644 examples/js/web-worker/index.html create mode 100644 examples/js/web-worker/package.json create mode 100644 examples/js/web-worker/service-worker-registration.js create mode 100644 examples/js/web-worker/service-worker.js create mode 100644 examples/js/web-worker/worker-no-propagation.js create mode 100644 examples/js/web-worker/worker-propagation.js create mode 100644 examples/js/web-worker/worker-registration.js diff --git a/examples/js/web-worker/.gitignore b/examples/js/web-worker/.gitignore new file mode 100644 index 0000000000..b512c09d47 --- /dev/null +++ b/examples/js/web-worker/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/examples/js/web-worker/.node-version b/examples/js/web-worker/.node-version new file mode 100644 index 0000000000..da2d3988d7 --- /dev/null +++ b/examples/js/web-worker/.node-version @@ -0,0 +1 @@ +14 \ No newline at end of file diff --git a/examples/js/web-worker/README.md b/examples/js/web-worker/README.md new file mode 100644 index 0000000000..8b2d8b5811 --- /dev/null +++ b/examples/js/web-worker/README.md @@ -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 git@github.com: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. diff --git a/examples/js/web-worker/bugsnag.png b/examples/js/web-worker/bugsnag.png new file mode 100644 index 0000000000000000000000000000000000000000..f46b6314707cab77801daf240d467b3b51c0c2fa GIT binary patch literal 3284 zcmV;_3@h`AP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91V4wp41ONa40RR91U;qFB0I4%yP5=N5K1oDDRCodHU3pNH$rYDlm|+GO zkVCl-@j&Dh4^&uIf)RjX2_lC30LYBbSR%n}d0 z+2|^QsGxu%iWeXt_cg!_Fbw3UUu^p885o%P24VfIuk^jwulsxbqxC>QBqBgOIP@72Abm`D5)mLC9Qw=<0o2{CdvO0! zXNOwff?+OU;~-0zTUwHH<cCBy6*m0tmAy`}(20+~eKdU5v%mRYk2Wb+0u*g#~F>ukOQm zVW1g_tiU6vvhrT~H-D?CelQZTFle)20O@qv3u(KG?q4+c8a-i;o@AH`1Y71iI$HZe zM<#O`7d&T}0$|K6!A6k57Xg~6sVgF)-mWOS{rFLaL7ibPv=l%xnd5V4BHxzS*$;CF z`Zv!~0L_SfKRoiSzTVw4VqDOWooZNF^##^2mkZ{khj~9uHcte|2z0Lspb_JQh6o@l z(FYkBsUx;{h(^$e#b?Ntc|JltqeLIXM`Y9}F%Du8`IhjON;OP?r>XH-+PNL5XeU+3 z?Varv&h|2;!ok(cJ5;IkG@(I3s=OkA47s4Lt`6+R8tj#m(^y}>NFTqbz@V8DiPWHu zg@i){keOkSN>z2Y;2a+8pF~703y)kXlQ~!j5vJJ@w#>J;tFCALYyY0Lndy79of@Vy zmS9I1KpX_P=5*_3%He~Xsx80yE!Y&3$&{=R#>Os-{3wQ6F)9E_NTX5)>nZCQeu6X{!pAn(3gkS&( zYZlWQa^10>6Y)e(dpG;qp?i1J=<~??h5waG9pe)|U}_1%jxZnO=-@W@J3n2u`cIAy zyeXWYd+f%wLxLc}H1cWyvNA6h^B5ES?wZfNyr9nmawF9i8(KHQ26BEbATH+TNGc)#mH}^oMinX;(V$vr^ z4t=C*uH=efK-SfN#=jw?GkP^sjOl7Wtgc&I{5b3I!4K2U?(Ar9Wi+waB`y6eJ!Ed@ zrqK1?#N+Rs((dFkIC#?B|U{j1SWvu69 z8_LVHwbeH@RuCOm_aK?na5B}?)2-1o;{p-FWung!4GmAfO5VKsdw)?ljHZhKP<~!& zM|%q=d{~qopRkc0R3;vTVh6`V_#votH{WKu?~MNN-x+EBu;KFqs{u0FnMUI=a8JYA17hCO0RgyStm{fWWGc z;D|`Duf!;jqQMeF1&|pVLRik{C;r^cJ&5$JrM33a!*s%Ognz&^BEhW0rCP$8Lktx_ z=GZuDl*CpVm+)h{jpE1GXcn}OUnDK5t9eYbCexO3(k2+BQdMVV?60maQYc(QLKiUC zseOFH$9hhxs=Uv&TwZpYd4-ds2Q8_qeKIj*E-f*Q9wLB@Zg#Y^)FvO?gnNAGMsw4% zXBBr;%~dmJt)+Vv7!*qYQmY%zD{J0RMdC&) zgRZW5#7OXYM_tVmS}2$E;zPBX2Ol&gQU%fP((=+{A|EUv7(mPjZ+|gah&6KlhX?A` zdQ!v@4hml9IUzlR7=5sIQaK~+(5Q$+BG9MFf&nC#yAb0*kief4DxJOP()zj*ngt#D zJksO+@${TL+SQL1!SB#4vuCE!sF2wb1*u){Xd*%r2*ChiTtICtZ5ns>Ji5x* zI&S>z+41XbZ0tBWqUVK4zh-oBmzYSbt! zFR|-gdP+;OPafaa&JPHfDqyigc>L(EwA$XdCOT#%k`G$5rurcr8T$A}FcXkg9uzGk zK*+pZM*EW2BWWlv?{%w?JG*!-O8h0ZGKdbo);xT0*R{-j{sGgGZDI8Rg4lt?F$rc(`^$YoP9L%2!bO0Xm%21JRo=OMnl$L_;vE<` zov>yS0s|Boy*%&MF|u3wVsq;x^U+2`^fI-kIp@Y<+H|$L>0V(P9$LuIu5N+YqQ}K5 zMxJqHH+|3=5xI;}Fo*3O?dG&X>f$4x@Ce>FESXpKG&HbVGqJP3pSWbJoS$BjMhp^& z32>lF4(y3e+0$G)sKE+b-q^V_pLKM!kuGsW@Ps*QfAEiK zGuAK}7NZ8%KOkoL%AJWzKG8ox#8=hlPJc#MnL2G1{dT&@G}^|&JD9E+GkrCE8bKEg zkmkBkUY1AnHR{HvrMEByZ23!%jjaUB4Q8dMR|ql{xE{D_oZDav(b>hv*FSn<$h^2W zK8Tw7j+1f>X^jw?wx(k#Ti~sT1lh^F1)CWUMM?)kV5;WaNTxLf_CZ|JK)Lc+A^BV$ z!rGcgN59&F(+F%H)2|1Odovg#co=#AEcQB5k8eXTMbr>L%uoCUy+o2Ca|q$57-!9b zMO&0FFZgg0+~P_8a#QikUov2h(WNCf4RDNzMeys%)8R1>Av)9E;XG6yk01!+Z>lw1@ zy+32r)Yq5L7GrlcKkoz{oKR1g81Lp0?B*7TOqJFFjZ6(YM~E0JDheJy%%qQ4IZb$+ zgt=7be(uVZR#g__;b>e4QaXD-r+cuN>2zJ% zhK5o)1>@An-}qfJbLW19T@)g*1YvQ2U^KoAPg?dV+;djOKDg?>y3x{7gQu@jT8=m% zEOP10nQQfTU1>Ez=%E0JGZgtzK)^KIN4TDKfZo{|Y&Q@(#lQLCz@67%+h_EL4j{Z3 zAsp7436m1Ad5Qsr4I>kP!ro6tjV1S0@fI zd8bZB8u)e + + + + @bugsnag/web-worker: Web Worker example + + + + + + +

Web and service worker example

+

This an example of how to include @bugsnag/web-worker in a web worker and a service worker.

+

+ 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. +

+

+ You can unregister the current service worker by pressing the 'Unregister' button. + Simply refresh the page to instantiate the new service worker. +

+
+
+

Web Worker with Propagation

+ + +
+
+

Web Worker without Propagation

+ + +
+
+

Service Worker

+ + + +
+
+ + + + + + diff --git a/examples/js/web-worker/package.json b/examples/js/web-worker/package.json new file mode 100644 index 0000000000..6eb0526f96 --- /dev/null +++ b/examples/js/web-worker/package.json @@ -0,0 +1,10 @@ +{ + "name": "web-worker", + "version": "1.0.0", + "scripts": { + "start": "serve . -p 8066 -n" + }, + "devDependencies": { + "serve": "^14.1.2" + } +} \ No newline at end of file diff --git a/examples/js/web-worker/service-worker-registration.js b/examples/js/web-worker/service-worker-registration.js new file mode 100644 index 0000000000..e3abd69e48 --- /dev/null +++ b/examples/js/web-worker/service-worker-registration.js @@ -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() \ No newline at end of file diff --git a/examples/js/web-worker/service-worker.js b/examples/js/web-worker/service-worker.js new file mode 100644 index 0000000000..1a6217b7bb --- /dev/null +++ b/examples/js/web-worker/service-worker.js @@ -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) + } +}) \ No newline at end of file diff --git a/examples/js/web-worker/worker-no-propagation.js b/examples/js/web-worker/worker-no-propagation.js new file mode 100644 index 0000000000..21f09f8e61 --- /dev/null +++ b/examples/js/web-worker/worker-no-propagation.js @@ -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) + } +} diff --git a/examples/js/web-worker/worker-propagation.js b/examples/js/web-worker/worker-propagation.js new file mode 100644 index 0000000000..ac248e31dd --- /dev/null +++ b/examples/js/web-worker/worker-propagation.js @@ -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) + } +} \ No newline at end of file diff --git a/examples/js/web-worker/worker-registration.js b/examples/js/web-worker/worker-registration.js new file mode 100644 index 0000000000..a4023132fb --- /dev/null +++ b/examples/js/web-worker/worker-registration.js @@ -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') +}) \ No newline at end of file