-
Notifications
You must be signed in to change notification settings - Fork 115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove ServiceWorker Page Control Requirement #745
Conversation
* Setup the WebSDK in the dev sandbox under a sub directory scope. - This is to confirm the current limitation that this SDK does not work if the page currently viewing isn't under control of the sw. - The following last message is shown in this example - installWorker - Awaiting on navigator.serviceWorker's 'controllerchange' event * Added OneSignalWorker.js under push/onesignal/ as a possible sub-dir someone may want to use onesignal under. * Modified the expresss example's server.js to support the new subfoldered files.
* No need to wait for page control for any of the sw features OneSignal uses.
* We do NOT need to wait to setup a listner to get messages sent from a ServiceWorker - In fact it can be setup before we even install one. * It isn't clear if we need to wait for a specific ServiceWorker state before we use `postMessage`. - We can't use "controllerchange" as this is the specific requirment we want to drop. - This didn't have an issue while testing this SDK as a whole at this point but doesn't mean there could be an issue. - TODO to confirm in before considering this PR complete.
* This is no longer being used any more and is dead code * We also never need to know this as we don't want to depend on our SW being in control of the page.
* Moved getRegistration to ServicWorkerManager * getRegistration requires a scope to get the correct sw that only the ServiceWorkerManager instance can provide * We don't want to use location.href any more as this is the ServiceWorker that is in control of the page which may not be OneSIgnal's.
* Changed `navigator.serviceWorker.controller` to `this.context.serviceWorkerManager.getRegistration()` * This ensure we get the correct OneSignal ServiceWorker. * Added error handling that was missing before - This was also required to get some tests to pass
* getRegistration is now only defined on ServiceWorkerManager. This requires a few things now: - An instance to ServiceWorkerManager - A OneSignal.context, due to above. * Removed location.href check as we dont' call this any more * postMessage does now get called in tests due the usage of getRegistration, this is ok but had to remove NotImplementedError from the mock so tests do not break.
* This corrects which sw we use to subscribe and unsubscribe from push * navigator.serviceWorker.controller gets the service worker in control of the page which isn't what we want. - We want to use the serviceWorkerManager.getRegistration() so we get the sw OneSignal registered. * Clean up tests using serviceWorker.ready
* Bypassed isn't something we care about any more as it only matters if you require page control which our service worker no longer requires. * This means hard refreashes don't break the SDK either now 🙌!
* We had includeUncontrolled: true in 2 of 3 spots already this was an outlier without any reason given. * This is requried to track on_session and on_focus correctly. * Confirmed this changed was required on an HTTPS setup
* self.location.origin works in the service worker context and won't be wrong when the scope of the service worker isn't root.
* Fixed bug where sometime in Firefox `serviceWorker.active` is `null` because it take a few secounds to become active for postMessage to use. * See "Page to SW Message race condition" in PR for more details on how I validated this as a stable solution.
* Since we no longer need to control the page for OneSignal to work there is no longer a need to claim or skipWaiting for the service worker
* Since the scope of the ServiceWorker can be a path where no HTML pages are served it is safer to use the origin instead as a default the notification open URL.
* `Installing` is not a state we care about since we don't need control of the page so removing the logic for this. - Both `postMessage` and `pushManager.subscribe` work in any state. * `.active` will be covered in a different commit.
* Since we are no longer useing `skipWaiting` and `clients.claim()` `workerRegistration.active` can't be used to detect if the SW is `ThirdParty` or not. * This signal also is unnecessary as the filename is later used with the call to `swActiveStateByFileName` which should be the source of turth for this.
* Removed `listenIfPageUncontrolled` flag on listen. * This is dead code as we never passing in this flag. * Also controlled vs uncontrolled is no longer relevent with this PR.
* Page control isn't a factor in the PR so cleaned up all comments referencing to ServiceWorker page control.
* renamed helpers/page/ServiceWorkerHelper to helpers/page/ServiceWorkerUtilHelper. * There was another `ServiceWorkerHelper` class under just /helpers/ and this was creating some confussion.
* Replaced all `ServiceWorker.active` with a new getAvailableServiceWorker helper method. * Updated in place `availableWorker` to use this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 21 of 21 files at r1, 1 of 1 files at r2.
Reviewable status: 15 of 23 files reviewed, 2 unresolved discussions (waiting on @itrush, @jkasten2, and @rgomezp)
src/helpers/SubscriptionHelper.ts, line 165 at r3 (raw file):
OneSignal.context.serviceWorkerManager
possibly replace with function argument to keep helper clean of dependencies
src/helpers/page/ServiceWorkerUtilHelper.ts, line 20 at r3 (raw file):
throw new Error("Could not find an available ServiceWorker instance!");
just be careful about this error, it may break people's sites
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 8 of 8 files at r3.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on @jkasten2 and @rgomezp)
* There are cases where getAvailableServiceWorker returning `null` is ok and it safe to move on so the following was done. - Removed the throw - Added a warning log etnry - Added null handling where this method is being called.
5c0ccfc
to
57f60b2
Compare
* Created a MockServiceWorkerContainerWithAPIBan that throws on the APIs we want to ban * MockServiceWorkerContainerWithAPIBan instance is created by default for all test's env setup. - This means any test that hits these APIs will throw, even for new tests * Also added self test (meta tests) for the new MockServiceWorkerContainerWithAPIBan class
* Clean up - Moved access to OneSignal.context.serviceWorkerManager down one call stack from getRawPushSubscriptionFromServiceWorkerRegistration to getRawPushSubscription
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 18 of 30 files reviewed, 2 unresolved discussions (waiting on @itrush and @rgomezp)
src/helpers/SubscriptionHelper.ts, line 165 at r3 (raw file):
Previously, itrush (Iryna Trush) wrote…
OneSignal.context.serviceWorkerManager
possibly replace with function argument to keep helper clean of dependencies
I move the access to OneSignal.context.serviceWorkerManager
down one level to SubscriptionHelper.getRawPushSubscription
to make things a bit more separated. However the call stack for this goes through MainHelper.createDeviceRecord which is also static and has 7 entry points. This helper layering isn't the best design and adding a 3 param to each seems like a side step.
This points to a larger issues of using state through statics instead of creating instance where we can do dependency injection.
src/helpers/page/ServiceWorkerUtilHelper.ts, line 20 at r3 (raw file):
Previously, itrush (Iryna Trush) wrote…
throw new Error("Could not find an available ServiceWorker instance!");
just be careful about this error, it may break people's sites
Fixed! Turned this into a warning. On the consuming end added a null check.
* establishServiceWorkerChannel already internally handles if the ServiceWorker exists already and doesn't require active status.
* Added a new changedServiceWorkerParams method which check if; - OneSignal ServiceWorker path, filename, or query params changed. - OneSignal ServierWorker scope changed * This is a new check that was added to shouldInstallWorker * A developer might change the OneSignal service worker params to take advantage of the PR #745 "Remove ServiceWorker Page Control Requirement" - This way the new OneSignal SW scope can be setup while their new root scoped SW can be installed at the same time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 14 of 14 files at r4.
Reviewable status: all files reviewed, 6 unresolved discussions (waiting on @jkasten2 and @rgomezp)
src/helpers/SubscriptionHelper.ts, line 165 at r3 (raw file):
Previously, jkasten2 (Josh Kasten) wrote…
I move the access to
OneSignal.context.serviceWorkerManager
down one level toSubscriptionHelper.getRawPushSubscription
to make things a bit more separated. However the call stack for this goes through MainHelper.createDeviceRecord which is also static and has 7 entry points. This helper layering isn't the best design and adding a 3 param to each seems like a side step.This points to a larger issues of using state through statics instead of creating instance where we can do dependency injection.
yeah, it's asking for a nice refactor :) but if it's too involved, let's keep it simple for now
src/managers/ServiceWorkerManager.ts, line 89 at r4 (raw file):
····
nit: extra spaces
test/support/mocks/service-workers/models/MockServiceWorkerContainer.ts, line 7 at r4 (raw file):
·
nit: trailing whitespace
test/support/mocks/service-workers/models/MockServiceWorkerContainerWithAPIBan.ts, line 13 at r4 (raw file):
··
nit: trailing spaces
test/support/mocks/service-workers/models/MockServiceWorkerContainerWithAPIBan.ts, line 46 at r4 (raw file):
}
nit: empty line at the end of the file
test/unit/helpers/page/ServiceWorkerUtilHelper.ts, line 34 at r4 (raw file):
}); // See test/unit/manager/ServiceWorkerManager.ts for other tests that cover this class
nit: new line at the end of the file
test/unit/managers/ServiceWorkerManager.ts, line 187 at r3 (raw file):
navigator.serviceWorker.controller
just to double-check: if someone writes it like this in tests, it would throw too?
test/unit/meta/mockPushManager.ts, line 57 at r4 (raw file):
subscribedSubscription
subscribed subscription, buttery butter 🙃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: 25 of 30 files reviewed, 6 unresolved discussions (waiting on @itrush and @rgomezp)
src/helpers/SubscriptionHelper.ts, line 165 at r3 (raw file):
Previously, itrush (Iryna Trush) wrote…
yeah, it's asking for a nice refactor :) but if it's too involved, let's keep it simple for now
Thanks!
src/managers/ServiceWorkerManager.ts, line 89 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
····
nit: extra spaces
Fixed!
test/support/mocks/service-workers/models/MockServiceWorkerContainer.ts, line 7 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
·
nit: trailing whitespace
Fixed!
test/support/mocks/service-workers/models/MockServiceWorkerContainerWithAPIBan.ts, line 13 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
··
nit: trailing spaces
Fixed!
test/support/mocks/service-workers/models/MockServiceWorkerContainerWithAPIBan.ts, line 46 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
}
nit: empty line at the end of the file
Fixed!
test/unit/helpers/page/ServiceWorkerUtilHelper.ts, line 34 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
nit: new line at the end of the file
Fixed!
test/unit/managers/ServiceWorkerManager.ts, line 187 at r3 (raw file):
Previously, itrush (Iryna Trush) wrote…
navigator.serviceWorker.controller
just to double-check: if someone writes it like this in tests, it would throw too?
Yes! Also will throw if someone adds this to something in src /and it runs in any test.
test/unit/meta/mockPushManager.ts, line 57 at r4 (raw file):
Previously, itrush (Iryna Trush) wrote…
subscribedSubscription
subscribed subscription, buttery butter 🙃
haha, just making sure someone doesn't think it is I can't believe it's not butter! 😆
Anyway I picked a better name.
* Added a new changedServiceWorkerParams method which check if; - OneSignal ServiceWorker path, filename, or query params changed. - OneSignal ServierWorker scope changed * This is a new check that was added to shouldInstallWorker * A developer might change the OneSignal service worker params to take advantage of the PR #745 "Remove ServiceWorker Page Control Requirement" - This way the new OneSignal SW scope can be setup while their new root scoped SW can be installed at the same time.
* Added a new changedServiceWorkerParams method which check if; - OneSignal ServiceWorker path, filename, or query params changed. - OneSignal ServierWorker scope changed * This is a new check that was added to shouldInstallWorker * A developer might change the OneSignal service worker params to take advantage of the PR #745 "Remove ServiceWorker Page Control Requirement" - This way the new OneSignal SW scope can be setup while their new root scoped SW can be installed at the same time.
* Added a new changedServiceWorkerParams method which check if; - OneSignal ServiceWorker path, filename, or query params changed. - OneSignal ServierWorker scope changed * This is a new check that was added to shouldInstallWorker * A developer might change the OneSignal service worker params to take advantage of the PR #745 "Remove ServiceWorker Page Control Requirement" - This way the new OneSignal SW scope can be setup while their new root scoped SW can be installed at the same time.
* Added a new changedServiceWorkerParams method which check if; - OneSignal ServiceWorker path, filename, or query params changed. - OneSignal ServierWorker scope changed * This is a new check that was added to shouldInstallWorker * A developer might change the OneSignal service worker params to take advantage of the PR #745 "Remove ServiceWorker Page Control Requirement" - This way the new OneSignal SW scope can be setup while their new root scoped SW can be installed at the same time.
It turned out this wasn't always true. If another service worker is registered already under a scope of the newly registered one you may get the first one. Example first service worker scope could be This part of the logic from this PR was corrected in PR #1136 |
Description
1 Line Summary
Remove ServiceWorker page control requirement.
Details
Summary
This is a quick 2 minute summary, recommend also seeing the full spike work here after reading this summary.
Removes the requirement of the service worker scope to be at or higher than the page you are viewing. (AKA the ServiceWorker has control of the page)
APIs that assumed only one ServiceWorker is on a domain has been replaced with
navigator.serviceWorker.getRegistration(scope)
.navigator.serviceWorker.controller
&navigator.serviceWorker.ready
Dev Sandbox has been updated to a non-root scope to demonstrate these changes work.
What this means
What is PR does NOT do
en/push/onesignal
andes/push/onesignal
Full Details
See issue #615 for the full research done before this PR was created.
Systems Affected
Validation
Tests
Tests have been updated and pass. Need to evaluate changes if we some new tests.
Info
Checklist
ServiceWorkerUtilHelper
teststhrows
to a new mock for service worker APIs that require page control which we should never use again.Programming Checklist
Interfaces:
Functions:
Typescript:
Other:
elem of array
syntax. PreferforEach
or usemap
context
if possible. Instead, we can pass it to function/constructor so that we don't callOneSignal.context
OneSignal.context
were introduced into this PR as injection of theserviceWorkerManager
would have required a number of changes. I recommend instead we come up with a strategy on removing this in another unrelated PR.Browser behavior
Page to SW Message race condition
I had a concern about how soon you can send a message to a ServiceWorker after registering it. It seems right away as long as you
await
onnavigator.serviceWorker.getRegistration()
and check all 3 possible state the worker can be in.Proof of this behavior:
Page:
pwa-sw.js:
Results:
Confirmed this on Edge(Chromium) 88.0.705.63 , Firefox 85.0.2, and Safari 13.1.2.
Subscribe to push race condition
I had a concern about how soon you can subscribe for push after the service worker is registered. As long as you
await
onnavigator.serviceWorker.getRegistration()
this isn't an issue in my testing.Page:
Results:
Confirmed this on Edge(Chromium) 88.0.705.63 and Firefox 85.0.2.
Checklist
Related Tickets
This change is