Skip to content
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

feat(fedback): Convert CDN bundles to use async feedback for lower bundle sizes #11791

Merged
merged 8 commits into from Apr 30, 2024

Conversation

ryan953
Copy link
Member

@ryan953 ryan953 commented Apr 25, 2024

It's more aggressive to start with the async loading strategy in the CDN bundle, but could be safer because if we want to change from async->sync it would not really be a majr version change. Whereas going from sync->async would be more of a big feature, riskier, and could demand a version bump or something.

@ryan953 ryan953 requested a review from a team April 25, 2024 15:17
Copy link
Contributor

github-actions bot commented Apr 25, 2024

size-limit report 📦

Path Size
@sentry/browser 21.64 KB (0%)
@sentry/browser (incl. Tracing) 32.68 KB (0%)
@sentry/browser (incl. Tracing, Replay) 68.03 KB (0%)
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 61.43 KB (0%)
@sentry/browser (incl. Tracing, Replay with Canvas) 72.07 KB (0%)
@sentry/browser (incl. Tracing, Replay, Feedback) 84.21 KB (0%)
@sentry/browser (incl. Feedback) 37.77 KB (0%)
@sentry/browser (incl. sendFeedback) 26.43 KB (0%)
@sentry/browser (incl. FeedbackAsync) 30.9 KB (0%)
@sentry/react 24.33 KB (0%)
@sentry/react (incl. Tracing) 35.64 KB (0%)
@sentry/vue 25.47 KB (0%)
@sentry/vue (incl. Tracing) 34.47 KB (0%)
@sentry/svelte 21.77 KB (0%)
CDN Bundle 24.02 KB (+0.29% 🔺)
CDN Bundle (incl. Tracing) 34.05 KB (+0.21% 🔺)
CDN Bundle (incl. Tracing, Replay) 67.72 KB (+0.08% 🔺)
CDN Bundle (incl. Tracing, Replay, Feedback) 73.05 KB (-12.6% 🔽)
CDN Bundle - uncompressed 70.62 KB (+0.06% 🔺)
CDN Bundle (incl. Tracing) - uncompressed 100.98 KB (+0.04% 🔺)
CDN Bundle (incl. Tracing, Replay) - uncompressed 210.59 KB (+0.02% 🔺)
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 224.19 KB (-12.78% 🔽)
@sentry/nextjs (client) 34.86 KB (0%)
@sentry/sveltekit (client) 33.24 KB (0%)
@sentry/node 138.47 KB (0%)

@ryan953
Copy link
Member Author

ryan953 commented Apr 25, 2024

CDN Bundle (incl. Tracing, Replay, Feedback) 73.07 KB (-12.59% 🔽)

Love to see this! 12% of the bundle size was from loading the feedback modules which only render after the user clicks the button. For most pageviews people will not click the button, so thats a large number of bytes saved per pageload.

Copy link
Member

@c298lee c298lee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing bundle size savings!!

@ryan953 ryan953 requested a review from a team April 25, 2024 15:52
@@ -2,7 +2,7 @@ import { browserTracingIntegrationShim, replayIntegrationShim } from '@sentry-in

export * from './index.bundle.base';

export { feedbackIntegration } from './feedback';
export { feedbackAsyncIntegration as feedbackIntegration } from './feedbackAsync';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mydea What do you think about this alias?

The idea is that the docs will use feedbackAsyncIntegration for our npm setup instructions. So that's what people will copy paste and see all over the place.

But for the CDN, most people probably won't interact with the integration name right?

I wanted to have a stable name so that we can flip from async to sync in the future if we wanted to and have it be transparent.

The CDN could alternatively ship feedbackAsyncIntegration to start, and then in the future ship both feedbackAsyncIntegration and feedbackIntegration.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, i'm thinking now that things like getIntegrationByName would still need to have 'feedbackAsyncIntegration' passed in because that's what the instance will be called. so the alias here isn't adding confusion to that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So there are two aspects to this:

  1. Integration Name: this is what is used for e.g. getIntegrationByName, but this is e.g. Feedback, not the function name. Technically both the async and sync integration could have the same name, meaning any check for getIntegrationByName('Feedback') would return either one of these if installed (benefit of this is that it would become impossible to install both).
  2. The function name: This will have to be used even on the CDN, as users still need to add it to their init. So it's def. a difference as what we export this.

Usage would be:

<script src="URL_TO_CDN_WITH_FEEDBACK"></script>
<script>
Sentry.init({
  integrations: [Sentry.feedbackAsyncIntegration()]
});
</script>

I am not so sure, it feels a bit weird to expose this to users like this 🤔 When using the CDN, is there ever a reason to not use the async variant? E.g. the only reason to do that in NPM is to avoid loading stuff from the CDN, which you are already doing anyhow in the CDN scenario 😅

So I think I would tend to just expose this as feedbackIntegration(). But this of course has two potential issues:

  1. Is the API the same for both? I guess yes, then all good, but if not it may become confusing.
  2. It may become confusing on NPM if we want to expose this as separate integrations, because suddenly they are not the same in NPM/CDN land.

I think part of the issue is that overall the naming of feedbackAsyncIntegration is not very user-friendly and clear (e.g. what does async mean in this context, ...). Mind you, I don't have any better ideas either 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

100%... I had some feeling about some of these points but the getIntegrationName i was less sure about. You laid it out well, let see what levers we can pull to improve it:

getIntegrationName

This should be Feedback in both cases, because buildFeedbackIntegration returns the same object, with different dependencies injected. So this sounds like the ideal ✅

CDN default impl and function name

For the CDN bundle, we'll go with the slim bundle size, and async loading strategy. So this PR will deliver that.
What's the function name though?

Some ideas:

// basic name, no hint about strategy:
  integrations: [Sentry.feedbackIntegration()]

// strategy specific name, can help with clarifying the docs
   integrations: [Sentry.feedbackAsyncIntegration()]

// different strategy specific name:
  integrations: [Sentry.lazyFeedbackIntegration()]

// different strategy specific name (not as good):
  integrations: [Sentry.feedbackOnInteractionIntegration()]

I think we should write the docs and that could help a lot

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this:

We always (CDN & NPM) have a feedbackIntegration, which uses some undefined loading strategy. Basically we'll use what we think works better, which on CDN is async and on NPM is sync.

Then in addition we also have feedbackAsyncIntegration and feedbackSyncIntegration. On CDN only the former exists, on NPM both exist.

Does that make sense?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes! i like this. It's good for docs-writing, because we can be consistent everywhere, and we'll just add the section for loading strategies to disambiguate. In that section can explain how it's Async for all the web-facing stuff, and we can make the electron package be Sync to both prove the point, but that's what I'd expect there anyway.

I'll update this PR in a sec

Comment on lines 35 to 39
export {
feedbackAsyncIntegration,
feedbackSyncIntegration,
feedbackSyncIntegration as feedbackIntegration
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NPM users will have both strategies to pick from, but feedbackIntegration is the name we have all over the docs, so that's available too using the Sync strat.


import * as ReplayBundle from '../../src/index.bundle.replay';

describe('index.bundle.replay', () => {
it('has correct exports', () => {
expect(ReplayBundle.replayIntegration).toBe(replayIntegration);
expect(ReplayBundle.browserTracingIntegration).toBe(browserTracingIntegrationShim);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the test files were missing various assertions (none of them assert that getFeedback or the long list of tracing helpers exist)

I made sure they all assert that browserTracingIntegration is set, and the order of assertions is consistent to hopefully make it easier going forward to verify what's here and add new ones.

Copy link
Member

@mydea mydea left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sweet, I like it!

@ryan953 ryan953 merged commit 3c95ac9 into develop Apr 30, 2024
91 checks passed
@ryan953 ryan953 deleted the ryan953/feedback-async-default branch April 30, 2024 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants