跨框架的前端源码定位,再加上点LLM

前几天改一个老项目,需要对页面进行简单调整,花了五分钟才找到它是哪个组件渲染的。这种事儿不是第一次了。

现代前端项目都是组件套组件,页面上的 DOM 和源码文件之间没有直接对应关系。每次要定位一个元素,基本就是 DevTools 看 class、猜组件名、编辑器里搜字符串,来回折腾。

于是我写了 DOM XRay:一个开发模式下运行的插件,按住快捷键点击页面元素,就能弹出源码面板,或者直接打开编辑器跳到对应文件和行号。

它支持 Vite、Webpack、Rspack、Next.js、Nuxt 3 和 Angular。


实际效果

装好插件后,页面加载完控制台会打印这样一段提示:

vbnet 复制代码
 DOM XRay is active
Usage:
  Hold Option + click  →  Open overlay to inspect source
  Hold Option + Command + click  →  Open directly in VSCode
  Press Esc while hovering  →  Cancel inspect mode

按住 Option 点击按钮,弹窗左侧直接显示这个按钮的源码文件和行号;再按一下"打开",编辑器就跳过去了。如果按住 Option + Command 点击,连弹窗都不出现,直接打开编辑器。


核心思路:把源码位置写进 DOM

DOM XRay 的做法并不复杂------在编译阶段把 data-source="filePath:line" 注入到每个元素上。运行时点击元素,向上找最近的 data-source,就能拿到源码位置。

真正麻烦的是怎么在不同框架里做这件事。

JSX / TSX

用 Babel 解析 AST,遍历 JSXOpeningElement,追加一个属性:

js 复制代码
node.attributes.push(
  t.jsxAttribute(
    t.jsxIdentifier("data-source"),
    t.stringLiteral(`${filePath}:${line}`)
  )
);

然后再用 @babel/generator 输出。React、SolidJS、Vue 的 JSX 都这么处理。

Vue 3 SFC

Vue 单文件组件的 template 有自己的编译流程。我用 @vue/compiler-sfc 拿到 template AST,再用 htmlparser2 把属性插回去。

Svelte

Svelte 的模板语法不太一样,用 svelte/compiler 解析后用 magic-string 做精准插入,避免破坏原有格式。

Nuxt 3

Nuxt 3 本质还是 Vue,但更深层。我在 Vue 编译器的 nodeTransforms 阶段注入属性,这样所有页面模板都会自动带上 data-source

Angular

Angular 的模板是独立 HTML 文件,编译器读取模板时才能处理。我用了一个不太优雅但有效的办法:monkey-patch fs.readFileSync,在 Angular 编译器读取 HTML 模板之前把属性注入进去。


项目结构

代码用 pnpm workspace 管理:

bash 复制代码
packages/
├── core          # 配置加载 + 源码转换
├── overlay-ui    # Web Components 弹窗
├── vite          # Vite 插件
├── webpack       # Webpack 5 插件
├── rspack        # Rspack 插件
├── nextjs        # Next.js 插件
├── nuxt          # Nuxt 3 模块
└── angular       # Angular 支持

core 负责所有框架的转换逻辑,各适配器只负责接入自己的构建流程。


几个有意思的实现细节

Web Components 弹窗

弹窗用原生 Web Components 实现,挂在 Shadow DOM 里。这样样式完全隔离,不会和用户页面的 CSS 互相影响。毕竟谁也不希望自己的调试工具被业务样式顶歪。

向上查找

点击的往往是按钮里的文字、卡片里的标题这种深层子元素,它自己不一定有 data-source。所以点击时我会从目标元素开始向上遍历,找到最近的带 data-source 的父元素。这样基本不会点空。

编辑器跳转

弹窗里的"打开"按钮会根据配置生成对应的 URL:

js 复制代码
vscode://file/Users/.../Button.tsx:14
cursor://file/Users/.../Button.tsx:14

window.open 打开就行。浏览器会唤起对应的编辑器并定位到行号。

Next.js 16 + Turbopack 的坑

Next.js 16 默认开 Turbopack,而 Turbopack 的 webpack loader 兼容不是对所有文件生效,尤其是 App Router 的 Server Components。

我试了几种方案,最后决定在 @dom-xray/core 的 Babel transform 里加一个 scriptContent 选项:遇到 layout.tsx 时,不只是在模块里插一段副作用代码,而是直接把 init 脚本作为 <script dangerouslySetInnerHTML> 插到 <body> 里。

因为 RSC 的模块代码在服务端运行,副作用代码不会真正在浏览器执行。但 <body> 里的 <script> 会被 SSR 渲染到 HTML 里,浏览器解析时自然会执行。

这样用户在 Next.js App Router 项目里完全不用手动改 layout.tsx,配置好 next.config.js 就行。


怎么用

Vite:

ts 复制代码
import domXray from "@dom-xray/vite";

export default defineConfig({
  plugins: [domXray({ editor: "vscode" })],
});

Next.js:

js 复制代码
const { withDomSelector } = require("@dom-xray/nextjs");

module.exports = withDomSelector(
  { reactStrictMode: true },
  { editor: "vscode" }
);

也可以写 dom-xray.config.json

json 复制代码
{
  "hotkey": { "mac": "option", "win": "alt" },
  "editor": "vscode",
  "enabled": true
}

还加了 AI Agent

弹窗右侧有一个输入面板,可以把当前元素的源码和提问一起发给 LLM。目前支持 Cursor、OpenCode 和 Claude Code,返回结果是 SSE 流式显示。

这个功能的出发点很简单:定位到源码之后,下一步往往是"这段代码是干什么的"或者"怎么改"。如果能直接在弹窗里问 AI,就不用再复制粘贴了。


写在最后

DOM XRay 不是那种解决大问题的工具,它解决的是一个很小的痛点:页面和源码之间的跳转。

写完之后我自己先用了一段时间,确实省了不少事。如果你也经常被这个问题烦到,可以试试看。

GitHub: github.com/ALittleFox/...

相关推荐
人无远虑必有近忧!1 小时前
fetch请求图片报跨域
前端·javascript
谢院柯2 小时前
解决修改 node_modules 依赖库源码后重复安装问题的几种方案
前端
疯狂打码的少年2 小时前
【程序语言与编译】NFA转DFA(子集构造法)
前端·笔记
半只小闲鱼2 小时前
合并多个excel文件到一个文件中
前端·python·数据分析
fobwebs2 小时前
Chrome谷歌浏览器多开教程,如何在电脑上同时登录多个GMAIL账号
前端·chrome·多开·同时登录多个gmail
前端 贾公子2 小时前
小程序蓝牙打印探索与实践 (最终章)
前端·微信小程序·小程序
chushiyunen2 小时前
vue export default
前端·javascript·vue.js
右耳朵猫AI2 小时前
前端周刊2026W23 | React 19.2.7、Conductor重写提速、Lovable切换TanStack Start
前端·react.js·前端框架
copyer_xyf2 小时前
FastAPI 项目骨架搭建
前端·后端·python