devtools-vite: source injection silently yields zero data-tsd-source attributes (AST child-key cache poisoned by regex literals)
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- TypeScript
- Star
- 499
- Fork
- 100
- Merge trung bình
- 1 ngày 17 giờ
- Pull request đã merge (30 ngày)
- 4
Mô tả
TanStack Devtools version
@tanstack/devtools-vite@0.8.5- transitive
@tanstack/devtools-bundler-core@0.1.3 @tanstack/react-devtools@0.10.12(transitive@tanstack/devtools@0.14.2)- Vite
8.2.2, Astro7.2.9(Astro drives Vite here; I could not reproduce with plain Vite) - Node
26.7.0, Linux
Describe the bug and the steps to reproduce it
The "Go to Source" / source inspector feature injects zero data-tsd-source
attributes. There is no browser console warning and nothing in the Vite dev
server log, so the feature just silently does nothing.
Root cause, from reading @tanstack/devtools-bundler-core/dist/esm/ast-utils.js.
getChildKeys(node) memoises the child-bearing keys of each AST node type in a
module-level childKeysCache Map, seeded from the first instance of that
type it ever sees:
for (const key in node) {
if (key === "type" || key === "start" || key === "end") continue;
if (typeof node[key] === "object") keys.push(key);
}
A regex literal (/abc/g) is an oxc Literal whose value is an object, so
value is cached as a child key for the type Literal. Every subsequent
string Literal then reaches:
} else if ("type" in value) callback(value);
with value being a string, and throws:
TypeError: Cannot use 'in' operator to search for 'type' in use client
at forEachChild (.../@tanstack/devtools-bundler-core/dist/esm/ast-utils.js:31:21)
"use client" is simply the first string literal in that particular file; the
throw happens for any string literal. addSourceToJsx() wraps its whole body in
try { ... } catch (e) { return; }, so the TypeError is swallowed and the
function returns undefined — no attributes, no log, no warning.
Because the cache is module-level and shared across every file and every call,
a single regex literal anywhere in the module graph disables source injection
for every string literal parsed afterwards. That is why this reproduces in a
real dev server but not in an isolated unit test.
Minimal reproduction
Two separate node processes, same target file (any .tsx file with JSX):
import { addSourceToJsx } from '@tanstack/devtools-bundler-core'
// Case A — fresh cache: works
addSourceToJsx(heroCode, heroPath, {}) // -> transformed, N attributes injected
// Case B — parse a regex literal first, then the same file: returns undefined
addSourceToJsx('const r = /abc/g;\nexport default r;\n', regexPath, {})
addSourceToJsx(heroCode, heroPath, {}) // -> undefined
Run the two cases in separate processes. Case A injects the attributes,
Case B returns undefined.
Observed in a real app: a component that reported 36 injected attributes in
isolation injected 0 once the dev server had processed the rest of the graph.
Expected behavior
Source injection should not depend on which files were parsed earlier. And a
failure inside addSourceToJsx should at least be logged rather than swallowed,
so the feature cannot fail completely silently.
Suggested fix
Guard the non-array branch the same way the array branch already is:
- } else if ("type" in value) callback(value);
+ } else if (typeof value === "object" && "type" in value) callback(value);
With that guard, Case B injects the attributes again. A more thorough fix would
make getChildKeys key the cache on the shape of the node (or only record
keys whose value is a node or an array of nodes) and drop the bare catch.
I am carrying this as a local patch-package patch for now.
Do you intend to try to help solve this bug with your own PR?
Maybe, I'll investigate and start debugging
Terms & Code of Conduct
- I agree to follow this project's Code of Conduct
- I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not get fixed and this issue may even be closed.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với việc duyệt AST trong ast-utils.js của @tanstack/devtools-bundler-core và entry point addSourceToJsx. Chạy bản tái hiện tối thiểu gồm hai process, trước tiên xác nhận rằng một regex literal làm hỏng các string literal phía sau. Được xem là hoàn tất khi việc chèn source vẫn thêm các thuộc tính data-tsd-source sau khi các file regex được xử lý và các lỗi không còn âm thầm vô hình nữa.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- devtools, typescript, vite
- Lĩnh vực
- build-system, tooling
- Loại issue
- Lỗi
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 74/100