Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Anchor-click and form-submit navigations run outside the runtime's interaction frame (observe: NavigationEvent.interaction is undefined)

已关闭
#643 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
52/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
typescript
领域
frontend, web-dev

调研方向

Start in src/data/events.ts at setupNativeEvents, then inspect @solidjs/web's internal addEvent and the delegated event path through delegateEvents. Preserve the existing listener order and preload behavior; done means anchor clicks and native form submissions receive interaction attribution, preventDefault still works, and non-observe builds remain unchanged.

由索引模型根据 Issue 内容生成。

描述

bug

Summary

Under Solid's observe tier, a navigation performed by clicking an <a> records no interaction: NavigationEvent.interaction is undefined, and the calls the route's data makes carry a navigation origin with no click behind it. A navigation performed by navigate() from an onClick handler is attributed correctly. The difference is where the handler runs: the router attaches its anchor handler to document directly, outside the web runtime's interaction frame.

Where

src/data/events.ts, setupNativeEvents:

// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
  document.addEventListener("mousemove", handleAnchorMove, { passive: true });
  document.addEventListener("focusin", handleAnchorPreload, { passive: true });
  document.addEventListener("touchstart", handleAnchorPreload, { passive: true });
}
document.addEventListener("submit", handleFormSubmit);

@solidjs/web wraps every handler it dispatches — delegated events via eventHandler, runtime-attached ones via addEvent — in dispatchAsInteraction, i.e. OBSERVE.attribution.withInteraction({ type, target, at }, fn), so every root write inside the handler (the router's location write included) is attributed to that interaction. A raw document.addEventListener goes around that wrapper. handleAnchorClick then calls navigateFromRoute, whose withOrigin(describeNavigation…) frame opens with no enclosing interaction, so the record is an orphan.

handleFormSubmit has the same shape: an action submitted through a native <form> is unattributed, while one submitted from a handler is not.

Observed

With @sentry/solid-2 consuming the records (e2e app on rc.13 / next.32, / → /users/6):

  • <button onClick={() => navigate('/users/6')}>: NavigationEvent.interaction is the click; the click span links to the route-named navigation span.
  • <a href="/users/6">: NavigationEvent.interaction === undefined; there is no click span at all, since no interaction frame ever opened. The navigation and its server-function call stand alone. The INP-relevant facts on the interaction record (inputDelayMs, handlerMs, settledMs) are lost for every link click in the app — which is most navigations.

The consumer documents the caveat for now rather than guessing a parent by time.

Cause

The direct document listeners date from the ordering requirement noted in the comment — Solid's delegated click must run first so a component's onClick with preventDefault() can stop the navigation — and predate the runtime having an interaction frame to run under. That ordering still has to hold; the fix is to run the handler inside the frame, not to change when it runs.

Options

  1. Router wraps its handlers. In setupNativeEvents, when OBSERVE is defined, dispatch handleAnchorClick and handleFormSubmit through OBSERVE.attribution.withInteraction({ type: evt.type, target: …, at: evt.timeStamp }, () => handler(evt)). Smallest change, but it duplicates the web runtime's describeEventTarget (element description, the values privacy gate for text) and interactionStart (the timeStamp clock check), which the router should not own.
  2. Web exposes the frame. @solidjs/web gains a small public entry — a listener attach that wraps under observe and is the identity function otherwise (addEvent(node, name, handler, false) already does exactly this but is marked @internal, compiler-emitted). The router uses it for the click and submit listeners. Preload listeners (mousemove, focusin, touchstart) stay raw: preloading is not a user interaction and should not open frames.
  3. Web stamps document-level listeners itself. Not viable without patching EventTarget.prototype; not proposed.

(2) is the right shape: the web runtime owns interaction description, the router only needs "run this as the event's handler". It is a public-surface addition on @solidjs/web, so it needs a decision there first; (1) can land in the router alone if that is preferred short-term.

Either way the order relative to Solid's delegated handler must not change: attach after delegateEvents(["click", "submit"]) exactly as today, so evt.defaultPrevented still reflects component handlers.

Acceptance

  • An anchor click that navigates produces a NavigationEvent whose interaction is the click's InteractionRef (type click, target a#…), the same object identity a navigate() from onClick gets today.
  • A <form> submitted to an action produces an interaction of type submit on the action's records.
  • A component onClick calling preventDefault() still stops the anchor navigation.
  • Nothing changes in non-observe builds (the wrapper folds to the plain listener).

Related: solidjs/solid#3683 (route declaration to the observe tier), getsentry/sentry-javascript#24517 (consumer; the caveat is documented in docs/solid-2-observe.md there).

— Claude via Cursor

主要语言
TypeScript
星标
1.3k
派生
182
平均合并
16 小时 9 分钟
30 天内合并 PR
42

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

solidjs/solid-router 的其他 Issue

查看 solidjs/solid-router 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。