-
-
Notifications
You must be signed in to change notification settings - Fork 9
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
Support Web Worker and ServiceWorker scope #45
base: main
Are you sure you want to change the base?
Conversation
Work off main thread: rm window/ document, explicit dep on local/sessionStorage
remove NoopStorage, warn when localStorage not available
Looks like CI ran well this time, but failed due to test coverage. I'll take a look at covering additional branches within |
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.
Good work! This looks great 👍
Just a few initial comments, and I believe you'll need to either run eslint . --fix
or setup format on save for your IDE using ESLint & Prettier to get the formatting just right.
I'm also going to have a think about any other opportunities we might have to reduce the output file size a bit.
packages/ga4/src/index.ts
Outdated
@@ -96,8 +114,8 @@ function getArguments(args: any[]): [string | undefined, IProps] { | |||
* | |||
* -------------------------------- */ | |||
|
|||
function getEventMeta({ type = '', event }: Pick<IProps, 'type' | 'event'>) { | |||
const searchString = document.location.search; | |||
function getEventMeta({ type = '', event }: Pick<IProps, 'type' | 'event'>): [string, string][] { |
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.
issue: this should be across multiple lines according to Prettier 👍
function getEventMeta({ type = '', event }: Pick<IProps, 'type' | 'event'>): [string, string][] { | |
function getEventMeta({ | |
type = '', | |
event, | |
}: Pick<IProps, 'type' | 'event'>): [string, string][] { |
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.
I can't seem to get these configs loaded into VSCode with the Prettier extension. I'll look for a CLI command soon. Might be worth adding as a pre-commit hook if it can be automated.
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.
const eventType = this?.event?.type; | ||
const sync = syncEvents.has((eventType || '').toLowerCase()); | ||
|
||
const xhr = new XMLHttpRequest(); |
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.
question: Is there a reason we're not using fetch()
as the primary fallback for navigator.sendBeacon()
? Is there a need to use XMLHttpRequest
here? Is there an opportunity to save some bytes here by going down that route?
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.
Although fetch
with the keepalive
property is a fallback for navigator.sendBeacon
, it's not available on any version of Firefox. Synchronous XHR is more broadly supported, so it's the preferred fallback. See https://developer.mozilla.org/en-US/docs/Web/API/Fetch#keepalive
* | ||
* -------------------------------- */ | ||
|
||
function sendBeaconFetch(url: string | URL, data?: XMLHttpRequestBodyInit | null): boolean { |
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.
suggestion: Although we're not making use of the Promise
returned via fetch()
here (yet), it's still probably worth returning one here for future sake. Can we rework this so we can return & resolve the Promise used within this functions scope?
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.
Good work! This looks great 👍
Just a few initial comments, and I believe you'll need to either run
eslint . --fix
or setup format on save for your IDE using ESLint & Prettier to get the formatting just right.I'm also going to have a think about any other opportunities we might have to reduce the output file size a bit.
Thanks for the suggestions, I (hopefully) brought test coverage high enough now that it'll pass CI. Returning and passing through Promise
will be a larger refactor that I'll get to when time permits.
// #3: fetch (ServiceWorker Scope) | ||
const hasFetch = (typeof fetch !== 'undefined'); | ||
if (hasFetch) { | ||
if (data) { |
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.
suggestion: Do we need this condition here? It seems like sendBeaconFetch()
can handle an undefined value for data
, resulting in an empty body value. Any thoughts?
The same goes for this condition and this one.
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.
I think I was writing to the tests, because without this the toBeCalledWith
need to explicitly include undefined
. From what I can tell, jest-extended
is needed for expect.anything()
to include undefined
or include some other hack.
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.
Ah I see, if we know in the test case whether data
will be undefined (or something else), couldn't we do one of the following:
// data is defined in test case
expect(sendBeaconFetch).toBeCalledWith(expect.any(String), stubOfData);
// data is undefined in test case
expect(sendBeaconFetch).toBeCalledWith(expect.any(String), undefined);
I may be missing something, but we should be able to do something similar I believe. Ideally we'd also want an explicit value for each, so rather than using expect.any()
we pass in the stub or test value.
What do you think?
@@ -9,8 +9,11 @@ import { | |||
isTargetElement, | |||
getUrlData, | |||
getEventParams, | |||
mergeEventParams, | |||
EventParamArray, |
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.
question: This seems to be very similar to the following type, can we re-use that instead?
type EventParams = Record<string, ParamValue> | [string, ParamValue][]; |
Add support for Web Worker and ServiceWorker contexts with the following changes
navigator.sendBeacon
isn't available, default toXMLHttpRequest
(Worker) orfetch
(ServiceWorker)sessionStorage
orlocalStorage
isn't available (i.e. Worker/ ServiceWorker), use an in-memoryMap
and warn thatclientId
is not persistedself
orwindow
, depending on contextwindow
ordocument
scoped events when not availablelocalStorage
isn't available in a Worker scope, per Unable to override default parameters #43, allow param overrides, i.e. to pullclientId
from IndexedDB