Skip to content

ref(core): Remove redundant iframe check in supportsNativeFetch#19853

Open
HazAT wants to merge 1 commit intodevelopfrom
bundle-size/supports-native-fetch
Open

ref(core): Remove redundant iframe check in supportsNativeFetch#19853
HazAT wants to merge 1 commit intodevelopfrom
bundle-size/supports-native-fetch

Conversation

@HazAT
Copy link
Member

@HazAT HazAT commented Mar 17, 2026

Summary

Remove ~30 lines of iframe-based DOM manipulation from supportsNativeFetch(). Saves ~200 bytes gzipped — the single biggest win in this bundle size effort.

Problem

supportsNativeFetch() created a sandboxed iframe to check if fetch is natively implemented. This is identical logic to getNativeImplementation("fetch") in browser-utils, creating two separate iframe-based checks in the CDN bundle.

The function is only called behind a skipNativeFetchCheck guard:

if (skipNativeFetchCheck && !supportsNativeFetch()) { return; }

In the base CDN bundle, skipNativeFetchCheck is never set to true, making the iframe code dead weight. Terser cannot tree-shake it because it cannot prove the parameter is always falsy.

Solution

Simplify supportsNativeFetch() to just delegate to _isFetchSupported() (checks if window.fetch exists). The native-vs-polyfill distinction is handled by getNativeImplementation at call sites that need it.

Also simplifies isNativeFunction from /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/ to /\[native code\]/ — more permissive across different JS engine toString() formats.

Part of #19833.

Co-Authored-By: Claude claude@anthropic.com

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

}

if (!_isFetchSupported()) {
return false;
Copy link

Choose a reason for hiding this comment

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

Public API supportsNativeFetch no longer checks native implementation

Medium Severity

supportsNativeFetch is a publicly exported function whose JSDoc says "returns true if window.fetch is natively implemented, false otherwise." It now delegates to _isFetchSupported(), which only checks whether fetch exists (native or polyfilled). This is a semantic breaking change to a public API — external consumers relying on this function to distinguish native from polyfilled fetch will get incorrect results. The function is now functionally identical to the already-deprecated supportsFetch.

Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 25.4 kB -0.92% -234 B 🔽
@sentry/browser - with treeshaking flags 23.94 kB -0.84% -201 B 🔽
@sentry/browser (incl. Tracing) 42.4 kB -0.52% -220 B 🔽
@sentry/browser (incl. Tracing, Profiling) 47.06 kB -0.48% -223 B 🔽
@sentry/browser (incl. Tracing, Replay) 81.18 kB -0.31% -245 B 🔽
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 70.78 kB -0.3% -211 B 🔽
@sentry/browser (incl. Tracing, Replay with Canvas) 85.88 kB -0.29% -245 B 🔽
@sentry/browser (incl. Tracing, Replay, Feedback) 98.14 kB -0.24% -235 B 🔽
@sentry/browser (incl. Feedback) 42.22 kB -0.53% -221 B 🔽
@sentry/browser (incl. sendFeedback) 30.07 kB -0.78% -234 B 🔽
@sentry/browser (incl. FeedbackAsync) 35.13 kB -0.66% -232 B 🔽
@sentry/browser (incl. Metrics) 26.68 kB -0.92% -246 B 🔽
@sentry/browser (incl. Logs) 26.82 kB -0.91% -245 B 🔽
@sentry/browser (incl. Metrics & Logs) 27.51 kB -0.83% -228 B 🔽
@sentry/react 27.19 kB -0.75% -203 B 🔽
@sentry/react (incl. Tracing) 44.73 kB -0.5% -224 B 🔽
@sentry/vue 29.86 kB -0.73% -218 B 🔽
@sentry/vue (incl. Tracing) 44.26 kB -0.51% -226 B 🔽
@sentry/svelte 25.43 kB -0.93% -238 B 🔽
CDN Bundle 28.11 kB -0.61% -172 B 🔽
CDN Bundle (incl. Tracing) 43.29 kB -0.49% -213 B 🔽
CDN Bundle (incl. Logs, Metrics) 28.97 kB -0.62% -178 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) 44.16 kB -0.44% -195 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) 68.03 kB -0.27% -184 B 🔽
CDN Bundle (incl. Tracing, Replay) 80.15 kB -0.23% -179 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 81.04 kB -0.24% -193 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) 85.66 kB -0.25% -211 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 86.55 kB -0.25% -215 B 🔽
CDN Bundle - uncompressed 81.97 kB -0.8% -655 B 🔽
CDN Bundle (incl. Tracing) - uncompressed 127.89 kB -0.52% -666 B 🔽
CDN Bundle (incl. Logs, Metrics) - uncompressed 84.83 kB -0.77% -655 B 🔽
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 130.76 kB -0.51% -666 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 208.47 kB -0.32% -655 B 🔽
CDN Bundle (incl. Tracing, Replay) - uncompressed 244.75 kB -0.28% -666 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 247.6 kB -0.27% -666 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 257.66 kB -0.26% -666 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 260.5 kB -0.26% -666 B 🔽
@sentry/nextjs (client) 47.16 kB -0.44% -204 B 🔽
@sentry/sveltekit (client) 42.82 kB -0.6% -255 B 🔽
@sentry/node-core 56.28 kB -0.12% -63 B 🔽
@sentry/node 173.21 kB +0.03% +51 B 🔺
@sentry/node - without tracing 96.27 kB -0.08% -76 B 🔽
@sentry/aws-serverless 113.28 kB -0.06% -62 B 🔽

View base workflow run

@github-actions
Copy link
Contributor

github-actions bot commented Mar 17, 2026

node-overhead report 🧳

Note: This is a synthetic benchmark with a minimal express app and does not necessarily reflect the real-world performance impact in an application.

Scenario Requests/s % of Baseline Prev. Requests/s Change %
GET Baseline 8,976 - 9,287 -3%
GET With Sentry 1,669 19% 1,616 +3%
GET With Sentry (error only) 5,887 66% 6,043 -3%
POST Baseline 1,154 - 1,158 -0%
POST With Sentry 558 48% 561 -1%
POST With Sentry (error only) 1,004 87% 1,037 -3%
MYSQL Baseline 3,113 - 3,205 -3%
MYSQL With Sentry 332 11% 409 -19%
MYSQL With Sentry (error only) 2,489 80% 2,591 -4%

View base workflow run

@Lms24 Lms24 force-pushed the bundle-size/supports-native-fetch branch from e2fd3a8 to 39fcc12 Compare March 19, 2026 11:42
@Lms24 Lms24 requested review from a team as code owners March 19, 2026 11:42
@Lms24 Lms24 changed the title refactor(core): Remove redundant iframe check in supportsNativeFetch ref(core): Remove redundant iframe check in supportsNativeFetch Mar 19, 2026
@Lms24 Lms24 changed the title ref(core): Remove redundant iframe check in supportsNativeFetch ref(core): Remove redundant iframe check in supportsNativeFetch Mar 19, 2026
@Lms24 Lms24 self-assigned this Mar 19, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 19, 2026

Semver Impact of This PR

🟢 Patch (bug fixes)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (remix) Server Timing Headers Trace Propagation by onurtemizkan in #18653

Bug Fixes 🐛

Deps

  • Bump next to 15.5.13/16.1.7 to fix CVE-2026-1525, CVE-202-33036 and related by chargome in #19870
  • Bump devalue 5.6.3 to 5.6.4 to fix CVE-2026-30226 by chargome in #19849
  • Bump file-type to 21.3.2 and @nestjs/common to 11.1.17 by chargome in #19847
  • Bump unhead 2.1.4 to 2.1.12 to fix CVE-2026-31860 and CVE-2026-31873 by chargome in #19848
  • Bump flatted 3.3.1 to 3.4.2 to fix CVE-2026-32141 by chargome in #19842
  • Bump tar 7.5.10 to 7.5.11 to fix CVE-2026-31802 by chargome in #19846
  • Bump hono 4.12.5 to 4.12.7 in cloudflare-hono E2E test app by chargome in #19850
  • Bump undici 6.23.0 to 6.24.1 to fix multiple CVEs by chargome in #19841

Other

  • (cloudflare) Use correct env types for withSentry by JPeer264 in #19836
  • (core) Align error span status message with core SpanStatusType for langchain/google-genai by nicohrubec in #19863
  • (deno) Clear pre-existing OTel global before registering TracerProvider by sergical in #19723
  • (nextjs) Skip tracing for tunnel requests by chargome in #19861
  • (node-core) Recycle propagationContext for each request by Lms24 in #19835

Internal Changes 🔧

Core

  • Remove redundant iframe check in supportsNativeFetch by HazAT in #19853
  • Simplify core utility functions for smaller bundle by HazAT in #19854

Other

  • (deps) Bump next from 16.1.5 to 16.1.7 in /dev-packages/e2e-tests/test-applications/nextjs-16 by dependabot in #19851
  • (nextjs) Skip broken ISR tests by chargome in #19871
  • (react) Add gql tests for react router by chargome in #19844
  • (release) Switch from action-prepare-release to Craft by BYK in #18763

🤖 This preview updates automatically when you update the PR.

@Lms24 Lms24 changed the base branch from autoresearch/browser-bundle-size-2026-03-17 to develop March 19, 2026 11:49
supportsNativeFetch() created a sandboxed iframe to check if the Fetch API
is natively implemented — identical logic to getNativeImplementation('fetch')
in browser-utils. The iframe approach adds ~30 lines of DOM manipulation code.

The function is only called behind a `skipNativeFetchCheck` guard that is
never set to true in the base CDN bundle, making the iframe code dead weight
that cannot be tree-shaken by terser (it can't prove the parameter is always
falsy across the program).

Simplify to delegate to `_isFetchSupported()` which checks if `window.fetch`
exists. The actual native-vs-polyfill distinction is already handled by
`getNativeImplementation` at the call sites that need it.

Also simplifies the `isNativeFunction` regex from an exact whitespace pattern
to a simpler `/[native code]/` check, which is more permissive across
different JS engine toString() formats.

Saves ~200 bytes gzipped on the base browser bundle.

Co-Authored-By: Claude claude@anthropic.com
@Lms24 Lms24 force-pushed the bundle-size/supports-native-fetch branch from 39fcc12 to dff6335 Compare March 19, 2026 12:13
// eslint-disable-next-line @typescript-eslint/ban-types
export function isNativeFunction(func: Function): boolean {
return func && /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString());
return func && /\[native code\]/.test(func.toString());
Copy link

Choose a reason for hiding this comment

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

Bug: The relaxed regex in isNativeFunction can misidentify a wrapped fetch as native, causing getNativeImplementation to return a version that can trigger an infinite loop with ad-blockers.
Severity: HIGH

Suggested Fix

Revert the regex in isNativeFunction to a stricter version that validates the function's structure, not just the presence of the [native code] substring. The previous regex /^function\s+\w+\(\)\s+\{\s+\[native code\]\s+\}$/ or a similarly strict alternative should be used to ensure only truly native functions are identified.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.

Location: packages/core/src/utils/supports.ts#L97

Potential issue: The `isNativeFunction` utility was changed to use a permissive regex
that only checks for the substring `[native code]`. This causes wrapped or polyfilled
functions, such as a `fetch` implementation modified by an ad-blocker or framework, to
be incorrectly identified as native. Consequently, `getNativeImplementation('fetch')`
returns this wrapped version instead of a truly native one. If Sentry then uses this
wrapped `fetch` for its own event reporting and an ad-blocker intercepts the request, it
can trigger an infinite loop, freezing the user's application. This bypasses a specific
safety mechanism designed to prevent this exact scenario.

Did we get this right? 👍 / 👎 to inform future reviews.

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.

2 participants