scroll-restoration registers pagehide with a bare addEventListener, which breaks under a patched EventTarget

Đang mở Phù hợp với người mới
#8,024 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
1/5
Thời gian dự kiến
Dưới một giờ
Mức phù hợp với người mới
78/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
typescript
Lĩnh vực
frontend

Hướng nghiên cứu

Bắt đầu trong packages/router-core/src/scroll-restoration.ts tại phần đăng ký pagehide quanh dòng 222, và so sánh với listener document đủ điều kiện ở phía trên. Tái hiện lỗi bằng app tối giản được liên kết, sử dụng scrollRestoration và instrumentation EventTarget đã được patch. Hoàn tất khi việc xây dựng router thành công và trang được render với handler pagehide được đăng ký trên window.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Which project does this relate to?

Router

Describe the bug

setupScrollRestoration registers its pagehide handler with an unqualified call:

// packages/router-core/src/scroll-restoration.ts:222
addEventListener('pagehide', () => { … })

From an ES module that passes this === undefined. The native method resolves an undefined receiver to the global per WebIDL, so the call is legal and works normally — but only as long as nothing has replaced EventTarget.prototype.addEventListener with a plain JS function that reads its receiver.

TypeError: Invalid value used as weak map key
    at WeakMap.set (<anonymous>)
    at UserInteractionInstrumentation.addPatchedListener (…/@opentelemetry_instrumentation-user-interaction.js:487:19)
    at addEventListenerPatched (…/@opentelemetry_instrumentation-user-interaction.js:533:16)
    at setupScrollRestoration (…/@tanstack_react-router.js:1549:3)
    at RouterCore.update (…/@tanstack_react-router.js:3133:25)
    at new RouterCore (…/@tanstack_react-router.js:3817:8)
    at new Router (…/@tanstack_react-router.js:6850:3)
    at createRouter (…/@tanstack_react-router.js:6846:9)
    at …/src/main.tsx:100:16

The throw is uncaught and synchronous, out of createRouter() — nothing renders at all. #root stays empty and the body holds two elements (the root div and the module script). There is also no useful console output: React reports this class of failure as a generic An error occurred in the <AwaitInner> component, logged via console.error("%s\n\n%s", …), so the substitution args carrying the real error are dropped by every forwarder in the chain. The stack above only exists because the reproducer hooks window.onerror.

The instrumentation is at fault for throwing on a legal call, and that is being fixed upstream (open-telemetry/opentelemetry-js-contrib#3639, PR telemetry/opentelemetry-js-contrib#3653). But the
bare call is the only one of its kind in the package — every other listener registration qualifies its receiver, including document.addEventListener two lines above this one — and it is fragile against any library that patches EventTarget (OTel, Zone.js, Sentry, analytics wrappers). window. on line 222 makes router construction independent of the WebIDL fallback.

Complete minimal reproducer

https://github.com/typedrat/tanstack-router-otel-user-interaction-repro

Steps to Reproduce the Bug
  1. git clone https://github.com/typedrat/tanstack-router-otel-user-interaction-repro && cd tanstack-router-otel-user-interaction-repro
  2. npm install && npm run dev
  3. Open http://localhost:5199 in a Chromium-based browser.
  4. The page is blank and the TypeError above is thrown. The app is ~70 lines in a single src/main.tsx: two routes, createRouter({ routeTree, scrollRestoration: true }), and one registerInstrumentations(…) call.

Two independent one-line toggles each make it render, which isolates the
interaction:

variant result
instrumentation registered, scrollRestoration: true blank page, TypeError
instrumentation registered, scrollRestoration unset renders
registerInstrumentations(…) commented out, scrollRestoration: true renders

So this only affects apps that opt into scrollRestoration — that is the flag on
setupScrollRestoration's shouldSetupScrollRestoration guard, and the bare call
sits inside it.

Expected behavior

The router registers its pagehide handler on window and constructs normally regardless of what has patched EventTarget.prototype.addEventListener.

Screenshots or Videos

No response

Platform
  • Router / Start Version: @tanstack/react-router 1.170.18 (@tanstack/router-core 1.171.15; the call site is unchanged on main)
  • OS: Linux
  • Browser: Chrome
  • Browser Version: 151.0.7922.108 (headless)
  • Bundler: vite
  • Bundler Version: 8.2.1

Also present with React 19.2.8, @opentelemetry/instrumentation-user-interaction 0.65.0, @opentelemetry/sdk-trace-web 2.10.0, and no zone.js in the tree. The no-Zone patch path is the one that breaks.

Additional context

Triggered in a real app by @opentelemetry/auto-instrumentations-web >= 0.66.0, which is the release that moved its instrumentation-user-interaction dependency to ^0.65.0.

We've worked around it by wrapping the upstream wrapper to reinstate the WebIDL fallback, and I can confirm that does resolve the issue.

Ngôn ngữ chính
TypeScript
Star
15.1k
Fork
1.9k
Merge trung bình
1 ngày 19 giờ
Pull request đã merge (30 ngày)
136

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của TanStack/router

Tất cả issue của TanStack/router

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.