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

ref(tracing): Make tracing integrations tree shakeable #4204

Merged
merged 18 commits into from
Dec 3, 2021

Conversation

AbhiPrasad
Copy link
Member

@AbhiPrasad AbhiPrasad commented Dec 1, 2021

Supercedes #4199 and #4200

Fixes #3310 properly.

Cuts ~2kb for nextjs client gzip + minified bundle.

This works because we avoid the object spread in the index, we instead just take advantage of js exporting the object correctly. See an example in the rollup repl. For more info, see the details at the end of the PR description.

RIP Mongo in the browser tracing bundle!

Before

image

After

image

Details

We previously exported integrations in tracing like so:

import * as TracingIntegrations from './integrations.js';
import { BrowserTracing } from './browsertracing.js';
const Integrations = { ...TracingIntegrations, BrowserTracing };

export { Integrations };

because we created a new object and then exported it, the classes would always get included:

class Mongo {}

class Postgres {}

var TracingIntegrations = /*#__PURE__*/Object.freeze({
	__proto__: null,
	Mongo: Mongo,
	Postgres: Postgres
});

class BrowserTracing {}

const Integrations = { ...TracingIntegrations, BrowserTracing };

Webpack/Rollup will always include the TracingIntegrations object, so this means it would always pull in the classes.

We changed this like so

// int.js
export * from './integrations.js';
export { BrowserTracing } from './browsertracing.js';
import * as Integrations from './int.js'
export { BrowserTracing } from './browsertracing.js';

export { Integrations };

This just makes each integration part of the module exports, so webpack/rollup can tree shake them out effectively. This way, a user can import BrowserTracing without bringing in the rest of the modules.

Next Steps

Update docs after release so that users get this for free. They'll have to directly import BrowserTracing instead of doing Integrations.BrowserTracing.

@AbhiPrasad AbhiPrasad added this to the Treeshaking / Bundle Size milestone Dec 1, 2021
@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2021

size-limit report

Path Base Size (d17f049) Current Size Change
@sentry/browser - CDN Bundle (gzipped) 22.45 KB 22.45 KB +0.01% 🔺
@sentry/browser - Webpack 23.29 KB 23.29 KB 0%
@sentry/react - Webpack 23.32 KB 23.32 KB 0%
@sentry/nextjs Client - Webpack 49.7 KB 47.97 KB -3.48% 🔽
@sentry/browser + @sentry/tracing - CDN Bundle (gzipped) 29.89 KB 29.9 KB +0.01% 🔺

AbhiPrasad and others added 5 commits December 1, 2021 10:35
Given that ember tests take longer to run than most other tests (and have been known to fail for reasons having nothing to do with whatever PR we're working on), in #3571 we stopped running them locally and on PRs*, instead only running them when merging to `master` or releasing.

*Provided the PR didn't touch any of the `@sentry/ember` code

As a result, we didn't catch a currently-failing ember test until later than we would have liked. To prevent that from happening again, this restores the running of ember tests (both locally and on PRs), but restricts which tests run in each circumstance, in order to prevent this change from slowing down the overall repo test suite more than necessary. Specifically:

- Locally, we run tests only against the current version of ember.
- In the context of a PR, we run tests against the current version, the LTS version, and a version using `embroider` (which is an optional ember compiler many people use).
- When merging to `master` or creating a release, for greatest safety, we test against current, LTS, embroider, beta, and "classic" (a legacy ember version).

Key changes:

- Up until now, the logic controlling which set of ember tests to run has been split between a script (`run_tests.js`, which differentiated local runs from CI runs), and the GHA workflow config (`build.yml`, which differentiated PRs from merges into master and creation of releases). That work is now consolidated into the ember-try config (since ember-try is the runner which needs to know which tests to run in the first place!).
- As a result of the above change, the method for forcing tests for all versions of ember to run needed to be modified. That option is now handled by a new script, `run-CI-tests.js`, which simply mimics the the third situation above by setting environment variables, thereby tricking ember-try into thinking it needs to run all tests.
Copy link
Member

@lobsterkatie lobsterkatie left a comment

Choose a reason for hiding this comment

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

Good change! All but one of my comments are just about making it clearer to the reader what's going on and why.

On that topic:

This works because we avoid the object spread in the index, we instead just take advantage of js exporting the object correctly. See an example in the rollup repl.

Two questions here:

  1. I'm not clear what you mean by "avoid object spread in the index," or what it means for JS to export the object correctly.

  2. (potentially solved by solving part 1 above) What is the repl illustrating, and how? Maybe have the bad way commented out so people can switch back and forth to see the effect?

packages/tracing/src/index.ts Outdated Show resolved Hide resolved
Comment on lines +4 to +6
it('is exported correctly', () => {
Object.keys(Integrations).forEach(key => {
expect(Integrations[key as keyof typeof Integrations].id).toStrictEqual(expect.any(String));
Copy link
Member

Choose a reason for hiding this comment

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

In both its old and new versions, I find this test confusing. How does the fact that every value in the Integrations object is itself an object with a string-valued id property prove anything about how things are getting exported? (This applies to the version in index.test.ts also.)

(Also, what's the advantage of the refactor here?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I just made it so that we don't need to use testOnlyIfNodeVersionAtLeast anymore.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah good question on the value of this test. I just copied the existing one from index.bundle.test.ts into index.test.ts, but open to alternatives.

Copy link
Member

Choose a reason for hiding this comment

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

I just made it so that we don't need to use testOnlyIfNodeVersionAtLeast anymore.

I figured that might be the case. My thought about that, though, is that if you leave aside the node restriction, IMHO the old test is simpler, because you don't need the keyof typeof stuff, and since we're about to drop node 6 compatibility anyway, we could just remove the wrapper when we do and still get to have a simpler test. What do you think?

That said, yeah, first we have to figure out if we even want the test in the first place! My issue with it is less "is there value in testing the exportation?" (though I'm iffy on that) and more "okay, but how does any of this prove that it's exported correctly?". Do you understand the logic there?

Copy link
Member Author

Choose a reason for hiding this comment

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

whether to deal with it here or come back to it

I will come back to this and address this in another PR. You make great points that we have to figure out.

packages/tracing/test/index.test.ts Outdated Show resolved Hide resolved
packages/tracing/src/index.ts Show resolved Hide resolved
`ReportTypes` is an interally used enum, so we do not need the runtime support. The `ReportTypes` enum lives in `packages/integrations/src/reportingobserver.ts` and is used by the `ReportingObserver` integration to manage report types.

According to the TS docs: https://www.typescriptlang.org/docs/handbook/enums.html 

> Const enums can only use constant enum expressions and unlike regular enums they are completely removed during compilation. Const enum members are inlined at use sites. This is possible since const enums cannot have computed members. 

This helps save on bundle size.
`States` is an interally used enum, so we do not need the runtime support. The `States` enum lives in `packages/utils/src/syncpromise.ts` and is used by `SyncPromise` to manage state internally.

According to the TS docs: https://www.typescriptlang.org/docs/handbook/enums.html 

> Const enums can only use constant enum expressions and unlike regular enums they are completely removed during compilation. Const enum members are inlined at use sites. This is possible since const enums cannot have computed members. 

This helps save on bundle size.
Copy link
Member

@lobsterkatie lobsterkatie left a comment

Choose a reason for hiding this comment

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

Nice writeup! 💯

LGTM

(As for the test we're discussing above, I don't see how the logic holds water, but I'll leave the ball in your court to decide whether to deal with it here or come back to it. Happy to rubber duck if you want to talk through whether it does or doesn't make any sense.)

@AbhiPrasad AbhiPrasad enabled auto-merge (squash) December 3, 2021 14:15
@AbhiPrasad AbhiPrasad merged commit aeedac2 into master Dec 3, 2021
@AbhiPrasad AbhiPrasad deleted the abhi-browser-tracing-tree-shake branch December 3, 2021 14:28
AbhiPrasad added a commit to getsentry/sentry-docs that referenced this pull request Dec 8, 2021
In getsentry/sentry-javascript#4204 we updated
the `BrowserTracing` import in the JS SDK to be exported individually.
We want users to use this individual import so that the other
integrations are treeshaken. This patch updates our documentation to
import `BrowserTracing` directly from `@sentry/tracing` instead of
through the `Integrations` object, which hopefully should lead to
a bundle size reduction for people.
AbhiPrasad added a commit to getsentry/sentry-docs that referenced this pull request Dec 8, 2021
In getsentry/sentry-javascript#4204 we updated
the `BrowserTracing` import in the JS SDK to be exported individually.
We want users to use this individual import so that the other
integrations are treeshaken. This patch updates our documentation to
import `BrowserTracing` directly from `@sentry/tracing` instead of
through the `Integrations` object, which hopefully should lead to
a bundle size reduction for people.
lobsterkatie added a commit that referenced this pull request Dec 14, 2021
In #3978, code was introduced to prevent node tracing integrations (mongo, postgres, etc) from appearing in the browser bundle where they don't belong. However, as part of our larger push to make our code more treeshakable, we recently changed how we export those integrations[1], making the previous workaround unnecessary.

As a bonus, this should fix a rendering issue some users were having when using the `fallback` flag.

Tested locally and on vercel.

Fixes #4090.

[1] #4204
onurtemizkan pushed a commit that referenced this pull request Dec 19, 2021
Cuts ~2kb for nextjs client gzip + minified bundle.

Previously we expected users to import tracing integrations like

```js
import { Integrations } from '@sentry/tracing';
const instance = new Integrations.BrowserTracing();
```

This makes the integrations unable to be treeshaken though. To address this, we now have
this individual export. We now expect users to consume BrowserTracing like so:

```js
import { BrowserTracing } from '@sentry/tracing';
const instance = new BrowserTracing();
```

This works because we avoid the object spread in the index, we instead just take advantage of js exporting the object correctly.
onurtemizkan pushed a commit that referenced this pull request Dec 19, 2021
In #3978, code was introduced to prevent node tracing integrations (mongo, postgres, etc) from appearing in the browser bundle where they don't belong. However, as part of our larger push to make our code more treeshakable, we recently changed how we export those integrations[1], making the previous workaround unnecessary.

As a bonus, this should fix a rendering issue some users were having when using the `fallback` flag.

Tested locally and on vercel.

Fixes #4090.

[1] #4204
lobsterkatie pushed a commit to getsentry/sentry-docs that referenced this pull request Jan 31, 2022
In getsentry/sentry-javascript#4204 we updated
the `BrowserTracing` import in the JS SDK to be exported individually.
We want users to use this individual import so that the other
integrations are treeshaken. This patch updates our documentation to
import `BrowserTracing` directly from `@sentry/tracing` instead of
through the `Integrations` object, which hopefully should lead to
a bundle size reduction for people.
lobsterkatie pushed a commit to getsentry/sentry-docs that referenced this pull request Jan 31, 2022
In getsentry/sentry-javascript#4204 we updated the `BrowserTracing` import in the JS SDK to be exported individually. We want users to use this individual import so that the other integrations are treeshaken. This patch updates our documentation to import `BrowserTracing` directly from `@sentry/tracing` instead of through the `Integrations` object, which hopefully should lead to a bundle size reduction for people.
lobsterkatie added a commit that referenced this pull request Feb 1, 2022
This applies the changes made in #4204 (exporting `BrowserTracing` outside of `Integrations`, in order that it be treeshakable if necessary) to the nextjs SDK, which got left out of that PR.

Fixes #4411.
lobsterkatie added a commit that referenced this pull request Feb 14, 2022
When we made the changes in #4204 (to export `BrowserTracing` directly rather than as part of `Sentry.Integrations`), we didn't make the change in the tracing CDN bundle. While It's true that there's no bundle size issue there (mongo and friends never were getting included in the CDN bundle, so there was nothing to fix), it did mean that when we changed the docs to match the above PR's changes, we ended up breaking CDN folks' usage of `BrowserTracing`.

This fixes that by making the same change in the tracing CDN bundle as was made for the npm package.

Fixes getsentry/sentry-docs#4722.
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.

@sentry/tracing Integrations can't be tree-shaked effectively
3 participants