-
Notifications
You must be signed in to change notification settings - Fork 135
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 destination filters for device mode action destinations #597
Conversation
🦋 Changeset detectedLatest commit: 91f0d8e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
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.
Overall I think this looks great, excited to see this middleware support added to action destinations!
Things I wanted to check:
- We may need to move
alternativeNames
to the plugin interface then include it in our checks here:analytics-next/packages/browser/src/core/queue/event-queue.ts
Lines 236 to 239 in 9c93579
return ( denyList[p.name] ?? (p.name === 'Segment.io' ? true : denyList.All) !== false )
This way if someone is currently disabling/enabling based on the current plugin name (likeFullStory (actions) trackEvent
) it still works. - Can we apply the above logic for logging/metrics as well?
- I commented that we should only apply destination filters on destination plugins - wonder if that should apply for all destination middleware as well. What are your thoughts there given action destinations can have non-destination actions.
|
||
return new Context(modifiedEvent) | ||
} | ||
|
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.
Is there an opportunity here to be more DRY and shave off some bytes?
Something like:
private _createMethod(methodName: 'track' | 'page' | 'identify' | 'alias' | 'group' | 'screen') {
return async (ctx: Context): Promise<Context> => {
if (!this.action[methodName]) return ctx
const transformedContext = await this.transform(ctx)
await this.action[methodName](transformedContext)
return ctx
}
}
alias = _createMethod('track')
group = _createMethod('group')
... etc
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.
thanks!
|
The context keeps logs/stats about which plugins were ran. Currently you can see which actions are ran and some stats about them. With these changes I think we'll see the wrapper plugin's name instead, so |
if ( | ||
routing.length && | ||
routingMiddleware && | ||
plugin.type === 'destination' |
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.
Might be worth adding a comment that we only want to apply destination filters to destination
actions so that we don't cause issues for hybrid action destinations (where we simply augment the event and send it to the cloud rather than directly to the destination)
I see future selves forgetting why we limited this 😄
} | ||
|
||
unload(ctx: Context, analytics: Analytics): Promise<unknown> | unknown { | ||
return this.action.unload && this.action.unload(ctx, analytics) |
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.
just in case you aren’t a Typescript nerd, you can shorten this to “return this.action.unload?.(ctx, analytics)” IIRC
@@ -232,9 +232,16 @@ export class EventQueue extends Emitter { | |||
return true | |||
} | |||
|
|||
const alternativeNameMatch = | |||
p.alternativeNames && | |||
p.alternativeNames.filter((name) => |
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.
Optional changing nitpick! p.alternativeNames?.filter would be a bit nicer IMO
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 typically agree - though the size savings are not insignificant due to the transpilations that occur (assuming variables/field names get minified). See this as an example. (Just a tradeoff - if it makes the code more readable then go with the optional chaining - I was just surprised how much larger the transpiled code was)
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.
interesting... that's a nice data point. I think I still prefer the optional chain... I wonder if babel would do a better job?
We use optional chaining all over, so IMO we should just use it and not care about size and hope the tooling gets better (or attempt to apply more optimization). or, if we're going to ban it, we should talk about it and then ban it and do a global refactor and use a lint rule to enforce. But If we're going to use it once I'd prefer to use it liberally for readability and then at some future point we target it for cost savings.
private async transform(ctx: Context): Promise<Context> { | ||
const modifiedEvent = await applyDestinationMiddleware( | ||
this.name, | ||
klona(ctx.event), |
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 wasn't aware that applyDestinationMiddleware mutated the event
- Can we avoid that? (If so, we'd want to clone the event inside of the applyDestinationMiddleware function, right?)
- Are there any tests that would fail if
klona
wasn't included?
This is the kind of code smell stuff that I think can get confusing later if the why is not documented (in tests, comments, etc).
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.
We do need to mutate the event I believe, but I moved the cloning logic into applyDestinationMiddleware and added a test that will fail if the original context gets modified (ie. if klona gets removed) 👍
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.
Overall looks great! Just had 1 question that might be an issue.
// Explicit integration option takes precedence, `All: false` does not apply to Segment.io | ||
return ( | ||
denyList[p.name] ?? | ||
alternativeNameMatch ?? |
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.
Isn't alternativeNameMismatch
an array of strings here? I think that'd be evaluated as a truthy value so we'd never hit the next conditional, or am I missing something?
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.
Nice catch - fixed the logic and added a new test
Co-authored-by: Christopher Radek <14189820+chrisradek@users.noreply.github.com>
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.
Looks good to me!
This PR allows destination filters to work with action destinations, by adding destination middleware support to them.
This change was tested by adding destination filters to an action destination and making sure events and properties were dropped properly.
[x] I've included a changeset (psst. run
yarn changeset
. Read about changesets here).